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.
Files changed (236) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +341 -0
  3. package/bin/ralph.js +8 -0
  4. package/dist/ai/enhancer.d.ts +100 -0
  5. package/dist/ai/enhancer.d.ts.map +1 -0
  6. package/dist/ai/enhancer.js +233 -0
  7. package/dist/ai/enhancer.js.map +1 -0
  8. package/dist/ai/index.d.ts +8 -0
  9. package/dist/ai/index.d.ts.map +1 -0
  10. package/dist/ai/index.js +11 -0
  11. package/dist/ai/index.js.map +1 -0
  12. package/dist/ai/prompts.d.ts +26 -0
  13. package/dist/ai/prompts.d.ts.map +1 -0
  14. package/dist/ai/prompts.js +201 -0
  15. package/dist/ai/prompts.js.map +1 -0
  16. package/dist/ai/providers.d.ts +35 -0
  17. package/dist/ai/providers.d.ts.map +1 -0
  18. package/dist/ai/providers.js +104 -0
  19. package/dist/ai/providers.js.map +1 -0
  20. package/dist/cli.d.ts +6 -0
  21. package/dist/cli.d.ts.map +1 -0
  22. package/dist/cli.js +196 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/commands/init.d.ts +16 -0
  25. package/dist/commands/init.d.ts.map +1 -0
  26. package/dist/commands/init.js +124 -0
  27. package/dist/commands/init.js.map +1 -0
  28. package/dist/commands/monitor.d.ts +17 -0
  29. package/dist/commands/monitor.d.ts.map +1 -0
  30. package/dist/commands/monitor.js +342 -0
  31. package/dist/commands/monitor.js.map +1 -0
  32. package/dist/commands/new.d.ts +19 -0
  33. package/dist/commands/new.d.ts.map +1 -0
  34. package/dist/commands/new.js +272 -0
  35. package/dist/commands/new.js.map +1 -0
  36. package/dist/commands/run.d.ts +16 -0
  37. package/dist/commands/run.d.ts.map +1 -0
  38. package/dist/commands/run.js +175 -0
  39. package/dist/commands/run.js.map +1 -0
  40. package/dist/generator/config.d.ts +59 -0
  41. package/dist/generator/config.d.ts.map +1 -0
  42. package/dist/generator/config.js +68 -0
  43. package/dist/generator/config.js.map +1 -0
  44. package/dist/generator/index.d.ts +64 -0
  45. package/dist/generator/index.d.ts.map +1 -0
  46. package/dist/generator/index.js +147 -0
  47. package/dist/generator/index.js.map +1 -0
  48. package/dist/generator/templates.d.ts +70 -0
  49. package/dist/generator/templates.d.ts.map +1 -0
  50. package/dist/generator/templates.js +296 -0
  51. package/dist/generator/templates.js.map +1 -0
  52. package/dist/generator/writer.d.ts +93 -0
  53. package/dist/generator/writer.d.ts.map +1 -0
  54. package/dist/generator/writer.js +213 -0
  55. package/dist/generator/writer.js.map +1 -0
  56. package/dist/index.d.ts +12 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +17 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/scanner/detectors/core/framework.d.ts +11 -0
  61. package/dist/scanner/detectors/core/framework.d.ts.map +1 -0
  62. package/dist/scanner/detectors/core/framework.js +275 -0
  63. package/dist/scanner/detectors/core/framework.js.map +1 -0
  64. package/dist/scanner/detectors/core/packageManager.d.ts +11 -0
  65. package/dist/scanner/detectors/core/packageManager.d.ts.map +1 -0
  66. package/dist/scanner/detectors/core/packageManager.js +74 -0
  67. package/dist/scanner/detectors/core/packageManager.js.map +1 -0
  68. package/dist/scanner/detectors/core/styling.d.ts +12 -0
  69. package/dist/scanner/detectors/core/styling.d.ts.map +1 -0
  70. package/dist/scanner/detectors/core/styling.js +230 -0
  71. package/dist/scanner/detectors/core/styling.js.map +1 -0
  72. package/dist/scanner/detectors/core/testing.d.ts +12 -0
  73. package/dist/scanner/detectors/core/testing.d.ts.map +1 -0
  74. package/dist/scanner/detectors/core/testing.js +190 -0
  75. package/dist/scanner/detectors/core/testing.js.map +1 -0
  76. package/dist/scanner/detectors/data/api.d.ts +12 -0
  77. package/dist/scanner/detectors/data/api.d.ts.map +1 -0
  78. package/dist/scanner/detectors/data/api.js +261 -0
  79. package/dist/scanner/detectors/data/api.js.map +1 -0
  80. package/dist/scanner/detectors/data/database.d.ts +12 -0
  81. package/dist/scanner/detectors/data/database.d.ts.map +1 -0
  82. package/dist/scanner/detectors/data/database.js +213 -0
  83. package/dist/scanner/detectors/data/database.js.map +1 -0
  84. package/dist/scanner/detectors/data/orm.d.ts +12 -0
  85. package/dist/scanner/detectors/data/orm.d.ts.map +1 -0
  86. package/dist/scanner/detectors/data/orm.js +160 -0
  87. package/dist/scanner/detectors/data/orm.js.map +1 -0
  88. package/dist/scanner/detectors/frontend/formHandling.d.ts +12 -0
  89. package/dist/scanner/detectors/frontend/formHandling.d.ts.map +1 -0
  90. package/dist/scanner/detectors/frontend/formHandling.js +211 -0
  91. package/dist/scanner/detectors/frontend/formHandling.js.map +1 -0
  92. package/dist/scanner/detectors/frontend/stateManagement.d.ts +12 -0
  93. package/dist/scanner/detectors/frontend/stateManagement.d.ts.map +1 -0
  94. package/dist/scanner/detectors/frontend/stateManagement.js +221 -0
  95. package/dist/scanner/detectors/frontend/stateManagement.js.map +1 -0
  96. package/dist/scanner/detectors/frontend/uiComponents.d.ts +12 -0
  97. package/dist/scanner/detectors/frontend/uiComponents.d.ts.map +1 -0
  98. package/dist/scanner/detectors/frontend/uiComponents.js +285 -0
  99. package/dist/scanner/detectors/frontend/uiComponents.js.map +1 -0
  100. package/dist/scanner/detectors/infra/deployment.d.ts +12 -0
  101. package/dist/scanner/detectors/infra/deployment.d.ts.map +1 -0
  102. package/dist/scanner/detectors/infra/deployment.js +301 -0
  103. package/dist/scanner/detectors/infra/deployment.js.map +1 -0
  104. package/dist/scanner/detectors/infra/monorepo.d.ts +12 -0
  105. package/dist/scanner/detectors/infra/monorepo.d.ts.map +1 -0
  106. package/dist/scanner/detectors/infra/monorepo.js +219 -0
  107. package/dist/scanner/detectors/infra/monorepo.js.map +1 -0
  108. package/dist/scanner/detectors/mcp/mcpProject.d.ts +12 -0
  109. package/dist/scanner/detectors/mcp/mcpProject.d.ts.map +1 -0
  110. package/dist/scanner/detectors/mcp/mcpProject.js +154 -0
  111. package/dist/scanner/detectors/mcp/mcpProject.js.map +1 -0
  112. package/dist/scanner/detectors/mcp/mcpServers.d.ts +17 -0
  113. package/dist/scanner/detectors/mcp/mcpServers.d.ts.map +1 -0
  114. package/dist/scanner/detectors/mcp/mcpServers.js +193 -0
  115. package/dist/scanner/detectors/mcp/mcpServers.js.map +1 -0
  116. package/dist/scanner/detectors/services/analytics.d.ts +12 -0
  117. package/dist/scanner/detectors/services/analytics.d.ts.map +1 -0
  118. package/dist/scanner/detectors/services/analytics.js +236 -0
  119. package/dist/scanner/detectors/services/analytics.js.map +1 -0
  120. package/dist/scanner/detectors/services/auth.d.ts +12 -0
  121. package/dist/scanner/detectors/services/auth.d.ts.map +1 -0
  122. package/dist/scanner/detectors/services/auth.js +217 -0
  123. package/dist/scanner/detectors/services/auth.js.map +1 -0
  124. package/dist/scanner/detectors/services/email.d.ts +12 -0
  125. package/dist/scanner/detectors/services/email.d.ts.map +1 -0
  126. package/dist/scanner/detectors/services/email.js +211 -0
  127. package/dist/scanner/detectors/services/email.js.map +1 -0
  128. package/dist/scanner/detectors/services/payments.d.ts +12 -0
  129. package/dist/scanner/detectors/services/payments.d.ts.map +1 -0
  130. package/dist/scanner/detectors/services/payments.js +185 -0
  131. package/dist/scanner/detectors/services/payments.js.map +1 -0
  132. package/dist/scanner/detectors/utils.d.ts +160 -0
  133. package/dist/scanner/detectors/utils.d.ts.map +1 -0
  134. package/dist/scanner/detectors/utils.js +222 -0
  135. package/dist/scanner/detectors/utils.js.map +1 -0
  136. package/dist/scanner/index.d.ts +42 -0
  137. package/dist/scanner/index.d.ts.map +1 -0
  138. package/dist/scanner/index.js +282 -0
  139. package/dist/scanner/index.js.map +1 -0
  140. package/dist/scanner/registry.d.ts +43 -0
  141. package/dist/scanner/registry.d.ts.map +1 -0
  142. package/dist/scanner/registry.js +243 -0
  143. package/dist/scanner/registry.js.map +1 -0
  144. package/dist/scanner/types.d.ts +112 -0
  145. package/dist/scanner/types.d.ts.map +1 -0
  146. package/dist/scanner/types.js +6 -0
  147. package/dist/scanner/types.js.map +1 -0
  148. package/dist/templates/config/ralph.config.js.tmpl +38 -0
  149. package/dist/templates/guides/AGENTS.md.tmpl +100 -0
  150. package/dist/templates/guides/FRONTEND.md.tmpl +523 -0
  151. package/dist/templates/guides/PERFORMANCE.md.tmpl +264 -0
  152. package/dist/templates/guides/SECURITY.md.tmpl +100 -0
  153. package/dist/templates/prompts/PROMPT.md.tmpl +77 -0
  154. package/dist/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
  155. package/dist/templates/prompts/PROMPT_feature.md.tmpl +83 -0
  156. package/dist/templates/prompts/PROMPT_review.md.tmpl +167 -0
  157. package/dist/templates/prompts/PROMPT_verify.md.tmpl +72 -0
  158. package/dist/templates/root/.gitignore.tmpl +5 -0
  159. package/dist/templates/root/LEARNINGS.md.tmpl +24 -0
  160. package/dist/templates/root/README.md.tmpl +61 -0
  161. package/dist/templates/scripts/feature-loop.sh.tmpl +267 -0
  162. package/dist/templates/scripts/loop.sh.tmpl +59 -0
  163. package/dist/templates/scripts/ralph-monitor.sh.tmpl +244 -0
  164. package/dist/templates/specs/README.md.tmpl +57 -0
  165. package/dist/templates/specs/_example.md.tmpl +71 -0
  166. package/dist/utils/config.d.ts +95 -0
  167. package/dist/utils/config.d.ts.map +1 -0
  168. package/dist/utils/config.js +148 -0
  169. package/dist/utils/config.js.map +1 -0
  170. package/dist/utils/header.d.ts +5 -0
  171. package/dist/utils/header.d.ts.map +1 -0
  172. package/dist/utils/header.js +15 -0
  173. package/dist/utils/header.js.map +1 -0
  174. package/dist/utils/logger.d.ts +11 -0
  175. package/dist/utils/logger.d.ts.map +1 -0
  176. package/dist/utils/logger.js +24 -0
  177. package/dist/utils/logger.js.map +1 -0
  178. package/package.json +44 -0
  179. package/src/ai/enhancer.ts +350 -0
  180. package/src/ai/index.ts +38 -0
  181. package/src/ai/prompts.ts +217 -0
  182. package/src/ai/providers.ts +136 -0
  183. package/src/cli.ts +255 -0
  184. package/src/commands/init.ts +149 -0
  185. package/src/commands/monitor.ts +412 -0
  186. package/src/commands/new.ts +312 -0
  187. package/src/commands/run.ts +214 -0
  188. package/src/generator/config.ts +116 -0
  189. package/src/generator/index.ts +227 -0
  190. package/src/generator/templates.ts +412 -0
  191. package/src/generator/writer.ts +293 -0
  192. package/src/index.ts +41 -0
  193. package/src/scanner/detectors/core/framework.ts +332 -0
  194. package/src/scanner/detectors/core/packageManager.ts +91 -0
  195. package/src/scanner/detectors/core/styling.ts +261 -0
  196. package/src/scanner/detectors/core/testing.ts +221 -0
  197. package/src/scanner/detectors/data/api.ts +303 -0
  198. package/src/scanner/detectors/data/database.ts +245 -0
  199. package/src/scanner/detectors/data/orm.ts +180 -0
  200. package/src/scanner/detectors/frontend/formHandling.ts +244 -0
  201. package/src/scanner/detectors/frontend/stateManagement.ts +261 -0
  202. package/src/scanner/detectors/frontend/uiComponents.ts +328 -0
  203. package/src/scanner/detectors/infra/deployment.ts +343 -0
  204. package/src/scanner/detectors/infra/monorepo.ts +251 -0
  205. package/src/scanner/detectors/mcp/mcpProject.ts +176 -0
  206. package/src/scanner/detectors/mcp/mcpServers.ts +237 -0
  207. package/src/scanner/detectors/services/analytics.ts +273 -0
  208. package/src/scanner/detectors/services/auth.ts +254 -0
  209. package/src/scanner/detectors/services/email.ts +244 -0
  210. package/src/scanner/detectors/services/payments.ts +213 -0
  211. package/src/scanner/detectors/utils.ts +251 -0
  212. package/src/scanner/index.ts +354 -0
  213. package/src/scanner/registry.ts +301 -0
  214. package/src/scanner/types.ts +152 -0
  215. package/src/templates/config/ralph.config.js.tmpl +38 -0
  216. package/src/templates/guides/AGENTS.md.tmpl +100 -0
  217. package/src/templates/guides/FRONTEND.md.tmpl +523 -0
  218. package/src/templates/guides/PERFORMANCE.md.tmpl +264 -0
  219. package/src/templates/guides/SECURITY.md.tmpl +100 -0
  220. package/src/templates/prompts/PROMPT.md.tmpl +77 -0
  221. package/src/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
  222. package/src/templates/prompts/PROMPT_feature.md.tmpl +83 -0
  223. package/src/templates/prompts/PROMPT_review.md.tmpl +167 -0
  224. package/src/templates/prompts/PROMPT_verify.md.tmpl +72 -0
  225. package/src/templates/root/.gitignore.tmpl +5 -0
  226. package/src/templates/root/LEARNINGS.md.tmpl +24 -0
  227. package/src/templates/root/README.md.tmpl +61 -0
  228. package/src/templates/scripts/feature-loop.sh.tmpl +267 -0
  229. package/src/templates/scripts/loop.sh.tmpl +59 -0
  230. package/src/templates/scripts/ralph-monitor.sh.tmpl +244 -0
  231. package/src/templates/specs/README.md.tmpl +57 -0
  232. package/src/templates/specs/_example.md.tmpl +71 -0
  233. package/src/utils/config.ts +221 -0
  234. package/src/utils/header.ts +15 -0
  235. package/src/utils/logger.ts +28 -0
  236. package/tsconfig.json +19 -0
@@ -0,0 +1,160 @@
1
+ /**
2
+ * ORM Detector
3
+ * Detects ORMs: Prisma, Drizzle
4
+ */
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ /**
8
+ * Read and parse package.json from a directory
9
+ */
10
+ function readPackageJson(projectRoot) {
11
+ const packageJsonPath = join(projectRoot, 'package.json');
12
+ if (!existsSync(packageJsonPath)) {
13
+ return null;
14
+ }
15
+ try {
16
+ const content = readFileSync(packageJsonPath, 'utf-8');
17
+ return JSON.parse(content);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ /**
24
+ * Get all dependencies from package.json (deps + devDeps)
25
+ */
26
+ function getDependencies(pkg) {
27
+ const deps = pkg.dependencies || {};
28
+ const devDeps = pkg.devDependencies || {};
29
+ return { ...deps, ...devDeps };
30
+ }
31
+ /**
32
+ * Check if a config file exists (supports multiple extensions)
33
+ */
34
+ function findConfigFile(projectRoot, baseName, extensions) {
35
+ for (const ext of extensions) {
36
+ const filePath = join(projectRoot, `${baseName}${ext}`);
37
+ if (existsSync(filePath)) {
38
+ return `${baseName}${ext}`;
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ /**
44
+ * Detect Prisma
45
+ */
46
+ function detectPrisma(projectRoot, deps) {
47
+ const evidence = [];
48
+ let confidence = 0;
49
+ // Check for @prisma/client
50
+ if (deps['@prisma/client']) {
51
+ evidence.push(`@prisma/client@${deps['@prisma/client']} in dependencies`);
52
+ confidence += 50;
53
+ }
54
+ // Check for prisma CLI
55
+ if (deps.prisma) {
56
+ evidence.push(`prisma@${deps.prisma} in devDependencies`);
57
+ confidence += 30;
58
+ }
59
+ // Check for prisma schema file
60
+ const schemaPath = join(projectRoot, 'prisma', 'schema.prisma');
61
+ if (existsSync(schemaPath)) {
62
+ evidence.push('prisma/schema.prisma found');
63
+ confidence += 30;
64
+ }
65
+ // Also check for schema in root (less common but valid)
66
+ const rootSchema = join(projectRoot, 'schema.prisma');
67
+ if (existsSync(rootSchema)) {
68
+ evidence.push('schema.prisma found in root');
69
+ confidence += 20;
70
+ }
71
+ if (confidence === 0)
72
+ return null;
73
+ return {
74
+ name: 'Prisma',
75
+ version: deps['@prisma/client'] || deps.prisma,
76
+ confidence: Math.min(confidence, 100),
77
+ evidence,
78
+ };
79
+ }
80
+ /**
81
+ * Detect Drizzle ORM
82
+ */
83
+ function detectDrizzle(projectRoot, deps) {
84
+ const evidence = [];
85
+ let confidence = 0;
86
+ // Check for drizzle-orm
87
+ if (deps['drizzle-orm']) {
88
+ evidence.push(`drizzle-orm@${deps['drizzle-orm']} in dependencies`);
89
+ confidence += 60;
90
+ }
91
+ // Check for drizzle-kit (migration tool)
92
+ if (deps['drizzle-kit']) {
93
+ evidence.push(`drizzle-kit@${deps['drizzle-kit']} in dependencies`);
94
+ confidence += 20;
95
+ }
96
+ // Check for drizzle config file
97
+ const configExtensions = ['.config.ts', '.config.js', '.config.mjs'];
98
+ const configFile = findConfigFile(projectRoot, 'drizzle', configExtensions);
99
+ if (configFile) {
100
+ evidence.push(`${configFile} found`);
101
+ confidence += 20;
102
+ }
103
+ // Detect database adapter
104
+ let variant;
105
+ if (deps['@planetscale/database'] || deps['drizzle-orm/planetscale-serverless']) {
106
+ variant = 'planetscale';
107
+ }
108
+ else if (deps['@neondatabase/serverless']) {
109
+ variant = 'neon';
110
+ }
111
+ else if (deps['@libsql/client'] || deps['better-sqlite3']) {
112
+ variant = 'sqlite';
113
+ }
114
+ else if (deps.pg || deps.postgres) {
115
+ variant = 'postgres';
116
+ }
117
+ else if (deps.mysql2) {
118
+ variant = 'mysql';
119
+ }
120
+ if (confidence === 0)
121
+ return null;
122
+ return {
123
+ name: 'Drizzle',
124
+ version: deps['drizzle-orm'],
125
+ variant,
126
+ confidence: Math.min(confidence, 100),
127
+ evidence,
128
+ };
129
+ }
130
+ /**
131
+ * ORM detector
132
+ * Returns the primary ORM detected
133
+ */
134
+ export const ormDetector = {
135
+ category: 'orm',
136
+ name: 'ORM Detector',
137
+ async detect(projectRoot) {
138
+ const pkg = readPackageJson(projectRoot);
139
+ if (!pkg) {
140
+ return null;
141
+ }
142
+ const deps = getDependencies(pkg);
143
+ // Check both ORMs and return the one with higher confidence
144
+ const prisma = detectPrisma(projectRoot, deps);
145
+ const drizzle = detectDrizzle(projectRoot, deps);
146
+ // Return the one with higher confidence, or first one if equal
147
+ if (prisma && drizzle) {
148
+ return prisma.confidence >= drizzle.confidence ? prisma : drizzle;
149
+ }
150
+ if (prisma && prisma.confidence >= 40) {
151
+ return prisma;
152
+ }
153
+ if (drizzle && drizzle.confidence >= 40) {
154
+ return drizzle;
155
+ }
156
+ return null;
157
+ },
158
+ };
159
+ export default ormDetector;
160
+ //# sourceMappingURL=orm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm.js","sourceRoot":"","sources":["../../../../src/scanner/detectors/data/orm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Form Handling Detector
3
+ * Detects: React Hook Form, Formik, Zod, Yup
4
+ */
5
+ import type { Detector } from '../../types.js';
6
+ /**
7
+ * Form handling detector
8
+ * Returns all detected form/validation libraries (projects often use multiple)
9
+ */
10
+ export declare const formHandlingDetector: Detector;
11
+ export default formHandlingDetector;
12
+ //# sourceMappingURL=formHandling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formHandling.d.ts","sourceRoot":"","sources":["../../../../src/scanner/detectors/frontend/formHandling.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAyLhE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,QA6ClC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Form Handling Detector
3
+ * Detects: React Hook Form, Formik, Zod, Yup
4
+ */
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ /**
8
+ * Read and parse package.json from a directory
9
+ */
10
+ function readPackageJson(projectRoot) {
11
+ const packageJsonPath = join(projectRoot, 'package.json');
12
+ if (!existsSync(packageJsonPath)) {
13
+ return null;
14
+ }
15
+ try {
16
+ const content = readFileSync(packageJsonPath, 'utf-8');
17
+ return JSON.parse(content);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ /**
24
+ * Get all dependencies from package.json (deps + devDeps)
25
+ */
26
+ function getDependencies(pkg) {
27
+ const deps = pkg.dependencies || {};
28
+ const devDeps = pkg.devDependencies || {};
29
+ return { ...deps, ...devDeps };
30
+ }
31
+ /**
32
+ * Detect React Hook Form
33
+ */
34
+ function detectReactHookForm(deps) {
35
+ const evidence = [];
36
+ let confidence = 0;
37
+ if (deps['react-hook-form']) {
38
+ evidence.push(`react-hook-form@${deps['react-hook-form']} in dependencies`);
39
+ confidence += 80;
40
+ }
41
+ // Check for @hookform/resolvers (validation integrations)
42
+ if (deps['@hookform/resolvers']) {
43
+ evidence.push('@hookform/resolvers found');
44
+ confidence += 10;
45
+ }
46
+ // Check for @hookform/devtools
47
+ if (deps['@hookform/devtools']) {
48
+ evidence.push('@hookform/devtools found');
49
+ confidence += 5;
50
+ }
51
+ if (confidence === 0)
52
+ return null;
53
+ return {
54
+ name: 'React Hook Form',
55
+ version: deps['react-hook-form'],
56
+ confidence: Math.min(confidence, 100),
57
+ evidence,
58
+ };
59
+ }
60
+ /**
61
+ * Detect Formik
62
+ */
63
+ function detectFormik(deps) {
64
+ const evidence = [];
65
+ let confidence = 0;
66
+ if (deps.formik) {
67
+ evidence.push(`formik@${deps.formik} in dependencies`);
68
+ confidence += 80;
69
+ }
70
+ if (confidence === 0)
71
+ return null;
72
+ return {
73
+ name: 'Formik',
74
+ version: deps.formik,
75
+ confidence: Math.min(confidence, 100),
76
+ evidence,
77
+ };
78
+ }
79
+ /**
80
+ * Detect Zod
81
+ */
82
+ function detectZod(deps) {
83
+ const evidence = [];
84
+ let confidence = 0;
85
+ if (deps.zod) {
86
+ evidence.push(`zod@${deps.zod} in dependencies`);
87
+ confidence += 80;
88
+ }
89
+ // Check for zod-to-json-schema
90
+ if (deps['zod-to-json-schema']) {
91
+ evidence.push('zod-to-json-schema found');
92
+ confidence += 10;
93
+ }
94
+ if (confidence === 0)
95
+ return null;
96
+ return {
97
+ name: 'Zod',
98
+ version: deps.zod,
99
+ variant: 'validation',
100
+ confidence: Math.min(confidence, 100),
101
+ evidence,
102
+ };
103
+ }
104
+ /**
105
+ * Detect Yup
106
+ */
107
+ function detectYup(deps) {
108
+ const evidence = [];
109
+ let confidence = 0;
110
+ if (deps.yup) {
111
+ evidence.push(`yup@${deps.yup} in dependencies`);
112
+ confidence += 80;
113
+ }
114
+ if (confidence === 0)
115
+ return null;
116
+ return {
117
+ name: 'Yup',
118
+ version: deps.yup,
119
+ variant: 'validation',
120
+ confidence: Math.min(confidence, 100),
121
+ evidence,
122
+ };
123
+ }
124
+ /**
125
+ * Detect Valibot (lightweight alternative to Zod)
126
+ */
127
+ function detectValibot(deps) {
128
+ const evidence = [];
129
+ let confidence = 0;
130
+ if (deps.valibot) {
131
+ evidence.push(`valibot@${deps.valibot} in dependencies`);
132
+ confidence += 80;
133
+ }
134
+ if (confidence === 0)
135
+ return null;
136
+ return {
137
+ name: 'Valibot',
138
+ version: deps.valibot,
139
+ variant: 'validation',
140
+ confidence: Math.min(confidence, 100),
141
+ evidence,
142
+ };
143
+ }
144
+ /**
145
+ * Detect TanStack Form
146
+ */
147
+ function detectTanStackForm(deps) {
148
+ const evidence = [];
149
+ let confidence = 0;
150
+ if (deps['@tanstack/react-form']) {
151
+ evidence.push(`@tanstack/react-form@${deps['@tanstack/react-form']} in dependencies`);
152
+ confidence += 80;
153
+ }
154
+ if (deps['@tanstack/vue-form']) {
155
+ evidence.push(`@tanstack/vue-form@${deps['@tanstack/vue-form']} in dependencies`);
156
+ confidence += 80;
157
+ }
158
+ if (confidence === 0)
159
+ return null;
160
+ return {
161
+ name: 'TanStack Form',
162
+ version: deps['@tanstack/react-form'] || deps['@tanstack/vue-form'],
163
+ confidence: Math.min(confidence, 100),
164
+ evidence,
165
+ };
166
+ }
167
+ /**
168
+ * Form handling detector
169
+ * Returns all detected form/validation libraries (projects often use multiple)
170
+ */
171
+ export const formHandlingDetector = {
172
+ category: 'formHandling',
173
+ name: 'Form Handling Detector',
174
+ async detect(projectRoot) {
175
+ const pkg = readPackageJson(projectRoot);
176
+ if (!pkg) {
177
+ return null;
178
+ }
179
+ const deps = getDependencies(pkg);
180
+ const results = [];
181
+ // Check form libraries
182
+ const formDetectors = [
183
+ () => detectReactHookForm(deps),
184
+ () => detectFormik(deps),
185
+ () => detectTanStackForm(deps),
186
+ ];
187
+ // Check validation libraries
188
+ const validationDetectors = [
189
+ () => detectZod(deps),
190
+ () => detectYup(deps),
191
+ () => detectValibot(deps),
192
+ ];
193
+ // Add form libraries
194
+ for (const detector of formDetectors) {
195
+ const result = detector();
196
+ if (result && result.confidence >= 40) {
197
+ results.push(result);
198
+ }
199
+ }
200
+ // Add validation libraries
201
+ for (const detector of validationDetectors) {
202
+ const result = detector();
203
+ if (result && result.confidence >= 40) {
204
+ results.push(result);
205
+ }
206
+ }
207
+ return results.length > 0 ? results : null;
208
+ },
209
+ };
210
+ export default formHandlingDetector;
211
+ //# sourceMappingURL=formHandling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formHandling.js","sourceRoot":"","sources":["../../../../src/scanner/detectors/frontend/formHandling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * State Management Detector
3
+ * Detects: Redux, Zustand, Jotai, Pinia, Recoil, MobX
4
+ */
5
+ import type { Detector } from '../../types.js';
6
+ /**
7
+ * State management detector
8
+ * Returns the primary state management solution detected
9
+ */
10
+ export declare const stateManagementDetector: Detector;
11
+ export default stateManagementDetector;
12
+ //# sourceMappingURL=stateManagement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateManagement.d.ts","sourceRoot":"","sources":["../../../../src/scanner/detectors/frontend/stateManagement.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAoNhE;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAqCrC,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * State Management Detector
3
+ * Detects: Redux, Zustand, Jotai, Pinia, Recoil, MobX
4
+ */
5
+ import { readPackageJson, getDependencies, } from '../utils.js';
6
+ /**
7
+ * Detect Redux / Redux Toolkit
8
+ */
9
+ function detectRedux(deps) {
10
+ const evidence = [];
11
+ let confidence = 0;
12
+ let variant;
13
+ // Check for Redux Toolkit (modern approach)
14
+ if (deps['@reduxjs/toolkit']) {
15
+ evidence.push(`@reduxjs/toolkit@${deps['@reduxjs/toolkit']} in dependencies`);
16
+ confidence += 70;
17
+ variant = 'toolkit';
18
+ }
19
+ // Check for classic redux
20
+ if (deps.redux) {
21
+ evidence.push(`redux@${deps.redux} in dependencies`);
22
+ confidence += 50;
23
+ if (!variant)
24
+ variant = 'classic';
25
+ }
26
+ // Check for react-redux bindings
27
+ if (deps['react-redux']) {
28
+ evidence.push(`react-redux@${deps['react-redux']} in dependencies`);
29
+ confidence += 20;
30
+ }
31
+ // Check for redux-saga or redux-thunk
32
+ if (deps['redux-saga']) {
33
+ evidence.push('redux-saga detected');
34
+ confidence += 10;
35
+ }
36
+ if (deps['redux-thunk']) {
37
+ evidence.push('redux-thunk detected');
38
+ confidence += 10;
39
+ }
40
+ if (confidence === 0)
41
+ return null;
42
+ return {
43
+ name: 'Redux',
44
+ version: deps['@reduxjs/toolkit'] || deps.redux,
45
+ variant,
46
+ confidence: Math.min(confidence, 100),
47
+ evidence,
48
+ };
49
+ }
50
+ /**
51
+ * Detect Zustand
52
+ */
53
+ function detectZustand(deps) {
54
+ const evidence = [];
55
+ let confidence = 0;
56
+ if (deps.zustand) {
57
+ evidence.push(`zustand@${deps.zustand} in dependencies`);
58
+ confidence += 90;
59
+ }
60
+ if (confidence === 0)
61
+ return null;
62
+ return {
63
+ name: 'Zustand',
64
+ version: deps.zustand,
65
+ confidence: Math.min(confidence, 100),
66
+ evidence,
67
+ };
68
+ }
69
+ /**
70
+ * Detect Jotai
71
+ */
72
+ function detectJotai(deps) {
73
+ const evidence = [];
74
+ let confidence = 0;
75
+ if (deps.jotai) {
76
+ evidence.push(`jotai@${deps.jotai} in dependencies`);
77
+ confidence += 90;
78
+ }
79
+ // Check for jotai utils
80
+ if (deps['jotai-devtools']) {
81
+ evidence.push('jotai-devtools detected');
82
+ confidence += 10;
83
+ }
84
+ if (confidence === 0)
85
+ return null;
86
+ return {
87
+ name: 'Jotai',
88
+ version: deps.jotai,
89
+ confidence: Math.min(confidence, 100),
90
+ evidence,
91
+ };
92
+ }
93
+ /**
94
+ * Detect Pinia (Vue state management)
95
+ */
96
+ function detectPinia(deps) {
97
+ const evidence = [];
98
+ let confidence = 0;
99
+ if (deps.pinia) {
100
+ evidence.push(`pinia@${deps.pinia} in dependencies`);
101
+ confidence += 90;
102
+ }
103
+ // Check for pinia plugins
104
+ if (deps['pinia-plugin-persistedstate']) {
105
+ evidence.push('pinia-plugin-persistedstate detected');
106
+ confidence += 10;
107
+ }
108
+ if (confidence === 0)
109
+ return null;
110
+ return {
111
+ name: 'Pinia',
112
+ version: deps.pinia,
113
+ confidence: Math.min(confidence, 100),
114
+ evidence,
115
+ };
116
+ }
117
+ /**
118
+ * Detect Recoil
119
+ */
120
+ function detectRecoil(deps) {
121
+ const evidence = [];
122
+ let confidence = 0;
123
+ if (deps.recoil) {
124
+ evidence.push(`recoil@${deps.recoil} in dependencies`);
125
+ confidence += 90;
126
+ }
127
+ if (confidence === 0)
128
+ return null;
129
+ return {
130
+ name: 'Recoil',
131
+ version: deps.recoil,
132
+ confidence: Math.min(confidence, 100),
133
+ evidence,
134
+ };
135
+ }
136
+ /**
137
+ * Detect MobX
138
+ */
139
+ function detectMobX(deps) {
140
+ const evidence = [];
141
+ let confidence = 0;
142
+ if (deps.mobx) {
143
+ evidence.push(`mobx@${deps.mobx} in dependencies`);
144
+ confidence += 70;
145
+ }
146
+ // Check for mobx-react bindings
147
+ if (deps['mobx-react'] || deps['mobx-react-lite']) {
148
+ evidence.push('mobx-react bindings detected');
149
+ confidence += 20;
150
+ }
151
+ // Check for mobx-state-tree
152
+ if (deps['mobx-state-tree']) {
153
+ evidence.push('mobx-state-tree detected');
154
+ confidence += 10;
155
+ }
156
+ if (confidence === 0)
157
+ return null;
158
+ return {
159
+ name: 'MobX',
160
+ version: deps.mobx,
161
+ confidence: Math.min(confidence, 100),
162
+ evidence,
163
+ };
164
+ }
165
+ /**
166
+ * Detect Valtio
167
+ */
168
+ function detectValtio(deps) {
169
+ const evidence = [];
170
+ let confidence = 0;
171
+ if (deps.valtio) {
172
+ evidence.push(`valtio@${deps.valtio} in dependencies`);
173
+ confidence += 90;
174
+ }
175
+ if (confidence === 0)
176
+ return null;
177
+ return {
178
+ name: 'Valtio',
179
+ version: deps.valtio,
180
+ confidence: Math.min(confidence, 100),
181
+ evidence,
182
+ };
183
+ }
184
+ /**
185
+ * State management detector
186
+ * Returns the primary state management solution detected
187
+ */
188
+ export const stateManagementDetector = {
189
+ category: 'stateManagement',
190
+ name: 'State Management Detector',
191
+ async detect(projectRoot) {
192
+ const pkg = readPackageJson(projectRoot);
193
+ if (!pkg) {
194
+ return null;
195
+ }
196
+ const deps = getDependencies(pkg);
197
+ // Modern/lightweight solutions preferred in detection order
198
+ const detectors = [
199
+ () => detectZustand(deps),
200
+ () => detectJotai(deps),
201
+ () => detectValtio(deps),
202
+ () => detectPinia(deps),
203
+ () => detectRecoil(deps),
204
+ () => detectRedux(deps),
205
+ () => detectMobX(deps),
206
+ ];
207
+ // Find the highest confidence result
208
+ let bestResult = null;
209
+ let bestConfidence = 0;
210
+ for (const detector of detectors) {
211
+ const result = detector();
212
+ if (result && result.confidence > bestConfidence) {
213
+ bestResult = result;
214
+ bestConfidence = result.confidence;
215
+ }
216
+ }
217
+ return bestResult && bestResult.confidence >= 40 ? bestResult : null;
218
+ },
219
+ };
220
+ export default stateManagementDetector;
221
+ //# sourceMappingURL=stateManagement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateManagement.js","sourceRoot":"","sources":["../../../../src/scanner/detectors/frontend/stateManagement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * UI Components Detector
3
+ * Detects: shadcn, Radix, MUI, Chakra, Ant Design, Headless UI
4
+ */
5
+ import type { Detector } from '../../types.js';
6
+ /**
7
+ * UI Components detector
8
+ * Returns all detected UI libraries (projects often use multiple)
9
+ */
10
+ export declare const uiComponentsDetector: Detector;
11
+ export default uiComponentsDetector;
12
+ //# sourceMappingURL=uiComponents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiComponents.d.ts","sourceRoot":"","sources":["../../../../src/scanner/detectors/frontend/uiComponents.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AA6QhE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,QA6ClC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}