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,5 @@
1
+ /**
2
+ * Display the RALPH ASCII header in Simpson yellow
3
+ */
4
+ export declare function displayHeader(): void;
5
+ //# sourceMappingURL=header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../src/utils/header.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CASpC"}
@@ -0,0 +1,15 @@
1
+ import cfonts from 'cfonts';
2
+ /**
3
+ * Display the RALPH ASCII header in Simpson yellow
4
+ */
5
+ export function displayHeader() {
6
+ cfonts.say('RALPH', {
7
+ font: 'block',
8
+ colors: ['#FED90F'],
9
+ letterSpacing: 1,
10
+ lineHeight: 1,
11
+ space: true,
12
+ maxLength: 0,
13
+ });
14
+ }
15
+ //# sourceMappingURL=header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/utils/header.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE;QAClB,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,CAAC,SAAS,CAAC;QACnB,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,CAAC;QACb,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,CAAC;KACb,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Logging utilities with colored output
3
+ */
4
+ export declare const logger: {
5
+ info(message: string): void;
6
+ success(message: string): void;
7
+ warn(message: string): void;
8
+ error(message: string): void;
9
+ debug(message: string): void;
10
+ };
11
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,MAAM;kBACH,MAAM,GAAG,IAAI;qBAIV,MAAM,GAAG,IAAI;kBAIhB,MAAM,GAAG,IAAI;mBAIZ,MAAM,GAAG,IAAI;mBAIb,MAAM,GAAG,IAAI;CAK7B,CAAC"}
@@ -0,0 +1,24 @@
1
+ import pc from 'picocolors';
2
+ /**
3
+ * Logging utilities with colored output
4
+ */
5
+ export const logger = {
6
+ info(message) {
7
+ console.log(pc.blue('info'), message);
8
+ },
9
+ success(message) {
10
+ console.log(pc.green('success'), message);
11
+ },
12
+ warn(message) {
13
+ console.log(pc.yellow('warn'), message);
14
+ },
15
+ error(message) {
16
+ console.log(pc.red('error'), message);
17
+ },
18
+ debug(message) {
19
+ if (process.env.DEBUG) {
20
+ console.log(pc.gray('debug'), message);
21
+ }
22
+ },
23
+ };
24
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,CAAC,OAAe;QACrB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,OAAe;QACnB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,OAAe;QACnB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "wiggum-cli",
3
+ "version": "0.1.0",
4
+ "description": "AI-powered feature development loop CLI",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "ralph": "./bin/ralph.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc && npm run copy-templates",
12
+ "copy-templates": "cp -r src/templates dist/",
13
+ "dev": "tsc --watch",
14
+ "start": "node bin/ralph.js",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "cli",
19
+ "ai",
20
+ "development",
21
+ "automation",
22
+ "feature-loop",
23
+ "code-generation",
24
+ "tech-stack-detection"
25
+ ],
26
+ "author": "Ralph CLI Contributors",
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "@ai-sdk/anthropic": "^3.0.15",
30
+ "@ai-sdk/openai": "^3.0.12",
31
+ "@clack/prompts": "^0.7.0",
32
+ "ai": "^6.0.41",
33
+ "cfonts": "^3.2.0",
34
+ "commander": "^12.1.0",
35
+ "picocolors": "^1.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.10.0",
39
+ "typescript": "^5.3.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ }
44
+ }
@@ -0,0 +1,350 @@
1
+ /**
2
+ * AI Enhancer Module
3
+ * Uses AI to analyze the codebase for deeper insights
4
+ */
5
+
6
+ import { generateText } from 'ai';
7
+ import type { ScanResult, DetectedStack, DetectionResult } from '../scanner/types.js';
8
+ import { getModel, type AIProvider, hasApiKey, getApiKeyEnvVar } from './providers.js';
9
+ import { SYSTEM_PROMPT, createAnalysisPrompt } from './prompts.js';
10
+ import { logger } from '../utils/logger.js';
11
+
12
+ /**
13
+ * Framework insights from AI analysis
14
+ */
15
+ export interface FrameworkInsights {
16
+ variant?: string;
17
+ confidence: 'high' | 'medium' | 'low';
18
+ notes?: string;
19
+ }
20
+
21
+ /**
22
+ * Architectural pattern detected by AI
23
+ */
24
+ export interface ArchitecturalPattern {
25
+ pattern: string;
26
+ confidence: 'high' | 'medium' | 'low';
27
+ evidence: string;
28
+ }
29
+
30
+ /**
31
+ * Coding convention detected by AI
32
+ */
33
+ export interface CodingConvention {
34
+ convention: string;
35
+ suggestion: string;
36
+ }
37
+
38
+ /**
39
+ * MCP server recommendation
40
+ */
41
+ export interface McpRecommendation {
42
+ name: string;
43
+ reason: string;
44
+ }
45
+
46
+ /**
47
+ * Additional detection suggestions
48
+ */
49
+ export interface AdditionalDetections {
50
+ possibleMissed?: string[];
51
+ refinements?: string[];
52
+ }
53
+
54
+ /**
55
+ * AI analysis result
56
+ */
57
+ export interface AIAnalysisResult {
58
+ frameworkInsights?: FrameworkInsights;
59
+ architecturalPatterns?: ArchitecturalPattern[];
60
+ codingConventions?: CodingConvention[];
61
+ recommendedMcpServers?: McpRecommendation[];
62
+ customPromptSuggestions?: string[];
63
+ additionalDetections?: AdditionalDetections;
64
+ }
65
+
66
+ /**
67
+ * Enhanced scan result with AI insights
68
+ */
69
+ export interface EnhancedScanResult extends ScanResult {
70
+ aiAnalysis?: AIAnalysisResult;
71
+ aiEnhanced: boolean;
72
+ aiProvider?: AIProvider;
73
+ aiError?: string;
74
+ }
75
+
76
+ /**
77
+ * Options for the AI enhancer
78
+ */
79
+ export interface EnhancerOptions {
80
+ provider?: AIProvider;
81
+ verbose?: boolean;
82
+ }
83
+
84
+ /**
85
+ * Parse AI response JSON safely
86
+ */
87
+ function parseAIResponse(text: string): AIAnalysisResult | null {
88
+ try {
89
+ // Try to extract JSON from the response
90
+ // The AI might wrap it in markdown code blocks
91
+ let jsonText = text;
92
+
93
+ // Remove markdown code blocks if present
94
+ const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
95
+ if (jsonMatch) {
96
+ jsonText = jsonMatch[1];
97
+ }
98
+
99
+ // Try to find JSON object
100
+ const objectMatch = jsonText.match(/\{[\s\S]*\}/);
101
+ if (objectMatch) {
102
+ jsonText = objectMatch[0];
103
+ }
104
+
105
+ return JSON.parse(jsonText) as AIAnalysisResult;
106
+ } catch (error) {
107
+ logger.warn('Failed to parse AI response as JSON');
108
+ return null;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Apply AI insights to enhance the detected stack
114
+ */
115
+ function applyEnhancements(
116
+ stack: DetectedStack,
117
+ analysis: AIAnalysisResult
118
+ ): DetectedStack {
119
+ const enhanced = { ...stack };
120
+
121
+ // Enhance framework detection with AI insights
122
+ if (analysis.frameworkInsights && enhanced.framework) {
123
+ // If AI detected a more specific variant with high confidence
124
+ if (
125
+ analysis.frameworkInsights.variant &&
126
+ analysis.frameworkInsights.confidence === 'high'
127
+ ) {
128
+ enhanced.framework = {
129
+ ...enhanced.framework,
130
+ variant: analysis.frameworkInsights.variant,
131
+ evidence: [
132
+ ...enhanced.framework.evidence,
133
+ `AI: ${analysis.frameworkInsights.notes || 'variant detected'}`,
134
+ ],
135
+ };
136
+ }
137
+ }
138
+
139
+ // Enhance MCP recommendations
140
+ if (analysis.recommendedMcpServers && analysis.recommendedMcpServers.length > 0) {
141
+ const aiRecommended = analysis.recommendedMcpServers.map(r => r.name);
142
+
143
+ enhanced.mcp = {
144
+ ...enhanced.mcp,
145
+ recommended: [
146
+ ...(enhanced.mcp?.recommended || []),
147
+ ...aiRecommended.filter(r => !enhanced.mcp?.recommended?.includes(r)),
148
+ ],
149
+ };
150
+ }
151
+
152
+ return enhanced;
153
+ }
154
+
155
+ /**
156
+ * AI Enhancer class
157
+ * Provides AI-powered analysis to enhance scan results
158
+ */
159
+ export class AIEnhancer {
160
+ private provider: AIProvider;
161
+ private verbose: boolean;
162
+
163
+ constructor(options: EnhancerOptions = {}) {
164
+ this.provider = options.provider || 'anthropic';
165
+ this.verbose = options.verbose || false;
166
+ }
167
+
168
+ /**
169
+ * Check if AI enhancement is available
170
+ */
171
+ isAvailable(): boolean {
172
+ return hasApiKey(this.provider);
173
+ }
174
+
175
+ /**
176
+ * Get the required environment variable for the current provider
177
+ */
178
+ getRequiredEnvVar(): string {
179
+ return getApiKeyEnvVar(this.provider);
180
+ }
181
+
182
+ /**
183
+ * Enhance scan results with AI analysis
184
+ */
185
+ async enhance(scanResult: ScanResult): Promise<EnhancedScanResult> {
186
+ // Check if API key is available
187
+ if (!this.isAvailable()) {
188
+ const envVar = this.getRequiredEnvVar();
189
+ return {
190
+ ...scanResult,
191
+ aiEnhanced: false,
192
+ aiError: `API key not found. Set ${envVar} to enable AI enhancement.`,
193
+ };
194
+ }
195
+
196
+ try {
197
+ // Get the configured model
198
+ const { model, provider, modelId } = getModel(this.provider);
199
+
200
+ if (this.verbose) {
201
+ logger.info(`Using AI provider: ${provider} (${modelId})`);
202
+ }
203
+
204
+ // Create the analysis prompt
205
+ const prompt = createAnalysisPrompt(scanResult);
206
+
207
+ // Call the AI model
208
+ const { text } = await generateText({
209
+ model,
210
+ system: SYSTEM_PROMPT,
211
+ prompt,
212
+ maxOutputTokens: 2000,
213
+ temperature: 0.3, // Lower temperature for more consistent output
214
+ });
215
+
216
+ // Parse the response
217
+ const analysis = parseAIResponse(text);
218
+
219
+ if (!analysis) {
220
+ return {
221
+ ...scanResult,
222
+ aiEnhanced: false,
223
+ aiProvider: this.provider,
224
+ aiError: 'Failed to parse AI analysis response',
225
+ };
226
+ }
227
+
228
+ // Apply enhancements to the stack
229
+ const enhancedStack = applyEnhancements(scanResult.stack, analysis);
230
+
231
+ return {
232
+ ...scanResult,
233
+ stack: enhancedStack,
234
+ aiAnalysis: analysis,
235
+ aiEnhanced: true,
236
+ aiProvider: this.provider,
237
+ };
238
+ } catch (error) {
239
+ const errorMessage = error instanceof Error ? error.message : String(error);
240
+ logger.error(`AI enhancement failed: ${errorMessage}`);
241
+
242
+ return {
243
+ ...scanResult,
244
+ aiEnhanced: false,
245
+ aiProvider: this.provider,
246
+ aiError: errorMessage,
247
+ };
248
+ }
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Convenience function to enhance scan results with AI
254
+ */
255
+ export async function enhanceWithAI(
256
+ scanResult: ScanResult,
257
+ options?: EnhancerOptions
258
+ ): Promise<EnhancedScanResult> {
259
+ const enhancer = new AIEnhancer(options);
260
+ return enhancer.enhance(scanResult);
261
+ }
262
+
263
+ /**
264
+ * Format AI analysis result for display
265
+ */
266
+ export function formatAIAnalysis(analysis: AIAnalysisResult): string {
267
+ const lines: string[] = [];
268
+
269
+ lines.push('=== AI Analysis ===');
270
+ lines.push('');
271
+
272
+ // Framework insights
273
+ if (analysis.frameworkInsights) {
274
+ lines.push('Framework Insights:');
275
+ if (analysis.frameworkInsights.variant) {
276
+ lines.push(` Variant: ${analysis.frameworkInsights.variant}`);
277
+ }
278
+ lines.push(` Confidence: ${analysis.frameworkInsights.confidence}`);
279
+ if (analysis.frameworkInsights.notes) {
280
+ lines.push(` Notes: ${analysis.frameworkInsights.notes}`);
281
+ }
282
+ lines.push('');
283
+ }
284
+
285
+ // Architectural patterns
286
+ if (analysis.architecturalPatterns && analysis.architecturalPatterns.length > 0) {
287
+ lines.push('Architectural Patterns:');
288
+ for (const pattern of analysis.architecturalPatterns) {
289
+ lines.push(` - ${pattern.pattern} [${pattern.confidence}]`);
290
+ lines.push(` Evidence: ${pattern.evidence}`);
291
+ }
292
+ lines.push('');
293
+ }
294
+
295
+ // Coding conventions
296
+ if (analysis.codingConventions && analysis.codingConventions.length > 0) {
297
+ lines.push('Coding Conventions:');
298
+ for (const convention of analysis.codingConventions) {
299
+ lines.push(` - ${convention.convention}`);
300
+ lines.push(` Suggestion: ${convention.suggestion}`);
301
+ }
302
+ lines.push('');
303
+ }
304
+
305
+ // MCP recommendations
306
+ if (analysis.recommendedMcpServers && analysis.recommendedMcpServers.length > 0) {
307
+ lines.push('Recommended MCP Servers:');
308
+ for (const server of analysis.recommendedMcpServers) {
309
+ lines.push(` - ${server.name}`);
310
+ lines.push(` Reason: ${server.reason}`);
311
+ }
312
+ lines.push('');
313
+ }
314
+
315
+ // Custom prompt suggestions
316
+ if (analysis.customPromptSuggestions && analysis.customPromptSuggestions.length > 0) {
317
+ lines.push('Custom Prompt Suggestions:');
318
+ for (const suggestion of analysis.customPromptSuggestions) {
319
+ lines.push(` - ${suggestion}`);
320
+ }
321
+ lines.push('');
322
+ }
323
+
324
+ // Additional detections
325
+ if (analysis.additionalDetections) {
326
+ if (
327
+ analysis.additionalDetections.possibleMissed &&
328
+ analysis.additionalDetections.possibleMissed.length > 0
329
+ ) {
330
+ lines.push('Possibly Missed Technologies:');
331
+ for (const tech of analysis.additionalDetections.possibleMissed) {
332
+ lines.push(` - ${tech}`);
333
+ }
334
+ lines.push('');
335
+ }
336
+
337
+ if (
338
+ analysis.additionalDetections.refinements &&
339
+ analysis.additionalDetections.refinements.length > 0
340
+ ) {
341
+ lines.push('Detection Refinements:');
342
+ for (const refinement of analysis.additionalDetections.refinements) {
343
+ lines.push(` - ${refinement}`);
344
+ }
345
+ lines.push('');
346
+ }
347
+ }
348
+
349
+ return lines.join('\n');
350
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * AI Module
3
+ * Main export for AI-enhanced analysis functionality
4
+ */
5
+
6
+ // Provider configuration
7
+ export {
8
+ type AIProvider,
9
+ type ProviderConfig,
10
+ getModel,
11
+ hasApiKey,
12
+ getAvailableProvider,
13
+ getApiKeyEnvVar,
14
+ } from './providers.js';
15
+
16
+ // Analysis prompts
17
+ export {
18
+ formatStackForPrompt,
19
+ SYSTEM_PROMPT,
20
+ createAnalysisPrompt,
21
+ createValidationPrompt,
22
+ createRecommendationsPrompt,
23
+ } from './prompts.js';
24
+
25
+ // AI enhancer
26
+ export {
27
+ type FrameworkInsights,
28
+ type ArchitecturalPattern,
29
+ type CodingConvention,
30
+ type McpRecommendation,
31
+ type AdditionalDetections,
32
+ type AIAnalysisResult,
33
+ type EnhancedScanResult,
34
+ type EnhancerOptions,
35
+ AIEnhancer,
36
+ enhanceWithAI,
37
+ formatAIAnalysis,
38
+ } from './enhancer.js';