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 @@
|
|
|
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
|
+
}
|
package/src/ai/index.ts
ADDED
|
@@ -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';
|