@klitchevo/code-council 0.0.1
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/.env.example +21 -0
- package/LICENSE +21 -0
- package/README.md +342 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +61 -0
- package/dist/constants.d.ts +33 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +36 -0
- package/dist/errors.d.ts +53 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +92 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +62 -0
- package/dist/prompts/backend-review.d.ts +6 -0
- package/dist/prompts/backend-review.d.ts.map +1 -0
- package/dist/prompts/backend-review.js +28 -0
- package/dist/prompts/code-review.d.ts +6 -0
- package/dist/prompts/code-review.d.ts.map +1 -0
- package/dist/prompts/code-review.js +18 -0
- package/dist/prompts/frontend-review.d.ts +6 -0
- package/dist/prompts/frontend-review.d.ts.map +1 -0
- package/dist/prompts/frontend-review.js +28 -0
- package/dist/prompts/plan-review.d.ts +6 -0
- package/dist/prompts/plan-review.d.ts.map +1 -0
- package/dist/prompts/plan-review.js +29 -0
- package/dist/review-client.d.ts +75 -0
- package/dist/review-client.d.ts.map +1 -0
- package/dist/review-client.js +116 -0
- package/dist/schemas.d.ts +60 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +46 -0
- package/dist/tools/factory.d.ts +20 -0
- package/dist/tools/factory.d.ts.map +1 -0
- package/dist/tools/factory.js +55 -0
- package/dist/tools/list-config.d.ts +9 -0
- package/dist/tools/list-config.d.ts.map +1 -0
- package/dist/tools/list-config.js +31 -0
- package/dist/tools/review-backend.d.ts +22 -0
- package/dist/tools/review-backend.d.ts.map +1 -0
- package/dist/tools/review-backend.js +38 -0
- package/dist/tools/review-code.d.ts +15 -0
- package/dist/tools/review-code.d.ts.map +1 -0
- package/dist/tools/review-code.js +29 -0
- package/dist/tools/review-frontend.d.ts +22 -0
- package/dist/tools/review-frontend.d.ts.map +1 -0
- package/dist/tools/review-frontend.js +38 -0
- package/dist/tools/review-plan.d.ts +22 -0
- package/dist/tools/review-plan.d.ts.map +1 -0
- package/dist/tools/review-plan.js +35 -0
- package/dist/utils/parallel-executor.d.ts +10 -0
- package/dist/utils/parallel-executor.d.ts.map +1 -0
- package/dist/utils/parallel-executor.js +21 -0
- package/package.json +81 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for better error handling and user feedback.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for all application errors
|
|
6
|
+
*/
|
|
7
|
+
export class AppError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
userMessage;
|
|
10
|
+
constructor(message, code, userMessage) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.userMessage = userMessage;
|
|
14
|
+
this.name = this.constructor.name;
|
|
15
|
+
Error.captureStackTrace(this, this.constructor);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Error thrown when OpenRouter API calls fail
|
|
20
|
+
*/
|
|
21
|
+
export class OpenRouterError extends AppError {
|
|
22
|
+
statusCode;
|
|
23
|
+
retryable;
|
|
24
|
+
constructor(message, statusCode, retryable = false) {
|
|
25
|
+
super(message, "OPENROUTER_ERROR", retryable
|
|
26
|
+
? "The AI service is temporarily unavailable. Please try again in a moment."
|
|
27
|
+
: "Unable to complete the review. Please check your API key and try again.");
|
|
28
|
+
this.statusCode = statusCode;
|
|
29
|
+
this.retryable = retryable;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown when configuration is invalid
|
|
34
|
+
*/
|
|
35
|
+
export class ConfigurationError extends AppError {
|
|
36
|
+
field;
|
|
37
|
+
constructor(message, field) {
|
|
38
|
+
super(message, "CONFIGURATION_ERROR", `Configuration error: ${message}`);
|
|
39
|
+
this.field = field;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Error thrown when input validation fails
|
|
44
|
+
*/
|
|
45
|
+
export class ValidationError extends AppError {
|
|
46
|
+
field;
|
|
47
|
+
constructor(message, field) {
|
|
48
|
+
super(message, "VALIDATION_ERROR", `Invalid input for ${field}: ${message}`);
|
|
49
|
+
this.field = field;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Format any error for display to users (string format)
|
|
54
|
+
*/
|
|
55
|
+
export function formatErrorMessage(error) {
|
|
56
|
+
if (error instanceof AppError) {
|
|
57
|
+
return error.userMessage || error.message;
|
|
58
|
+
}
|
|
59
|
+
if (error instanceof Error) {
|
|
60
|
+
// Sanitize error messages to avoid leaking sensitive info
|
|
61
|
+
const sanitized = error.message
|
|
62
|
+
.replace(/sk-or-v1-[a-zA-Z0-9]+/g, "[REDACTED]")
|
|
63
|
+
.replace(/Bearer [a-zA-Z0-9-_]+/g, "Bearer [REDACTED]");
|
|
64
|
+
// Map common errors to user-friendly messages
|
|
65
|
+
if (sanitized.includes("401") || sanitized.includes("Unauthorized")) {
|
|
66
|
+
return "API authentication failed. Please check your OPENROUTER_API_KEY environment variable.";
|
|
67
|
+
}
|
|
68
|
+
if (sanitized.includes("429") || sanitized.includes("rate limit")) {
|
|
69
|
+
return "Rate limit exceeded. Please wait a moment and try again.";
|
|
70
|
+
}
|
|
71
|
+
if (sanitized.includes("timeout") || sanitized.includes("ETIMEDOUT")) {
|
|
72
|
+
return "Request timed out. The AI service may be slow. Please try again.";
|
|
73
|
+
}
|
|
74
|
+
return sanitized;
|
|
75
|
+
}
|
|
76
|
+
return "An unexpected error occurred. Please try again.";
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Format error for MCP tool response
|
|
80
|
+
*/
|
|
81
|
+
export function formatError(error) {
|
|
82
|
+
return {
|
|
83
|
+
content: [
|
|
84
|
+
{
|
|
85
|
+
type: "text",
|
|
86
|
+
text: `Error: ${formatErrorMessage(error)}`,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
isError: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=errors.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Code Council MCP Server
|
|
4
|
+
* Multi-model AI code review server using OpenRouter API
|
|
5
|
+
*/
|
|
6
|
+
import "dotenv/config";
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import { BACKEND_REVIEW_MODELS, CODE_REVIEW_MODELS, FRONTEND_REVIEW_MODELS, PLAN_REVIEW_MODELS, } from "./config";
|
|
10
|
+
import { logger } from "./logger";
|
|
11
|
+
import { ReviewClient } from "./review-client";
|
|
12
|
+
import { createReviewTool } from "./tools/factory";
|
|
13
|
+
import { handleListConfig } from "./tools/list-config";
|
|
14
|
+
import { backendReviewSchema, handleBackendReview, } from "./tools/review-backend";
|
|
15
|
+
import { codeReviewSchema, handleCodeReview } from "./tools/review-code";
|
|
16
|
+
import { frontendReviewSchema, handleFrontendReview, } from "./tools/review-frontend";
|
|
17
|
+
import { handlePlanReview, planReviewSchema } from "./tools/review-plan";
|
|
18
|
+
// Validate API key
|
|
19
|
+
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY;
|
|
20
|
+
if (!OPENROUTER_API_KEY) {
|
|
21
|
+
console.error("Error: OPENROUTER_API_KEY environment variable is required");
|
|
22
|
+
console.error("For MCP clients, add it to the 'env' section of your server config.");
|
|
23
|
+
console.error("For local development, create a .env file with: OPENROUTER_API_KEY=your-key");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
// Initialize client and server
|
|
27
|
+
const client = new ReviewClient(OPENROUTER_API_KEY);
|
|
28
|
+
const server = new McpServer({
|
|
29
|
+
name: "code-council",
|
|
30
|
+
version: "1.0.0",
|
|
31
|
+
});
|
|
32
|
+
// Register review tools
|
|
33
|
+
createReviewTool(server, {
|
|
34
|
+
name: "review_code",
|
|
35
|
+
description: "Review code for quality, bugs, performance, and security issues using multiple AI models in parallel",
|
|
36
|
+
inputSchema: codeReviewSchema,
|
|
37
|
+
handler: (input) => handleCodeReview(client, input),
|
|
38
|
+
});
|
|
39
|
+
createReviewTool(server, {
|
|
40
|
+
name: "review_frontend",
|
|
41
|
+
description: "Review frontend code for accessibility, performance, UX, and best practices using multiple AI models in parallel",
|
|
42
|
+
inputSchema: frontendReviewSchema,
|
|
43
|
+
handler: (input) => handleFrontendReview(client, input),
|
|
44
|
+
});
|
|
45
|
+
createReviewTool(server, {
|
|
46
|
+
name: "review_backend",
|
|
47
|
+
description: "Review backend code for security, performance, architecture, and best practices using multiple AI models in parallel",
|
|
48
|
+
inputSchema: backendReviewSchema,
|
|
49
|
+
handler: (input) => handleBackendReview(client, input),
|
|
50
|
+
});
|
|
51
|
+
createReviewTool(server, {
|
|
52
|
+
name: "review_plan",
|
|
53
|
+
description: "Review implementation plans BEFORE coding to catch issues early using multiple AI models in parallel",
|
|
54
|
+
inputSchema: planReviewSchema,
|
|
55
|
+
handler: (input) => handlePlanReview(client, input),
|
|
56
|
+
});
|
|
57
|
+
// Register config tool
|
|
58
|
+
server.registerTool("list_review_config", { description: "Show current model configuration" }, async () => {
|
|
59
|
+
const { text } = await handleListConfig();
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text }],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
// Start server
|
|
65
|
+
async function main() {
|
|
66
|
+
const transport = new StdioServerTransport();
|
|
67
|
+
await server.connect(transport);
|
|
68
|
+
logger.info("Code Council MCP server started", {
|
|
69
|
+
codeReviewModels: CODE_REVIEW_MODELS,
|
|
70
|
+
frontendReviewModels: FRONTEND_REVIEW_MODELS,
|
|
71
|
+
backendReviewModels: BACKEND_REVIEW_MODELS,
|
|
72
|
+
planReviewModels: PLAN_REVIEW_MODELS,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
main().catch((error) => {
|
|
76
|
+
logger.error("Fatal error during server startup", error);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging utility for better observability.
|
|
3
|
+
* Logs to stderr in JSON format for easy parsing.
|
|
4
|
+
*/
|
|
5
|
+
interface LogContext {
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
declare class Logger {
|
|
9
|
+
private isDevelopment;
|
|
10
|
+
private debugEnabled;
|
|
11
|
+
private log;
|
|
12
|
+
debug(message: string, context?: LogContext): void;
|
|
13
|
+
info(message: string, context?: LogContext): void;
|
|
14
|
+
warn(message: string, context?: LogContext): void;
|
|
15
|
+
error(message: string, error?: Error | unknown, context?: LogContext): void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Global logger instance
|
|
19
|
+
*/
|
|
20
|
+
export declare const logger: Logger;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,UAAU,UAAU;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,cAAM,MAAM;IACX,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,YAAY,CAAgC;IAEpD,OAAO,CAAC,GAAG;IA2BX,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAMlD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIjD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;CAiB3E;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging utility for better observability.
|
|
3
|
+
* Logs to stderr in JSON format for easy parsing.
|
|
4
|
+
*/
|
|
5
|
+
class Logger {
|
|
6
|
+
isDevelopment = process.env.NODE_ENV === "development";
|
|
7
|
+
debugEnabled = process.env.DEBUG === "true";
|
|
8
|
+
log(level, message, context) {
|
|
9
|
+
const logEntry = {
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
level,
|
|
12
|
+
message,
|
|
13
|
+
...context,
|
|
14
|
+
};
|
|
15
|
+
// In development, use pretty printing
|
|
16
|
+
if (this.isDevelopment) {
|
|
17
|
+
const emoji = {
|
|
18
|
+
debug: "🔍",
|
|
19
|
+
info: "ℹ️",
|
|
20
|
+
warn: "⚠️",
|
|
21
|
+
error: "❌",
|
|
22
|
+
}[level];
|
|
23
|
+
console.error(`${emoji} [${level.toUpperCase()}] ${message}`, context ? JSON.stringify(context, null, 2) : "");
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// In production, use JSON for structured logging
|
|
27
|
+
console.error(JSON.stringify(logEntry));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
debug(message, context) {
|
|
31
|
+
if (this.debugEnabled) {
|
|
32
|
+
this.log("debug", message, context);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
info(message, context) {
|
|
36
|
+
this.log("info", message, context);
|
|
37
|
+
}
|
|
38
|
+
warn(message, context) {
|
|
39
|
+
this.log("warn", message, context);
|
|
40
|
+
}
|
|
41
|
+
error(message, error, context) {
|
|
42
|
+
const errorContext = {
|
|
43
|
+
...context,
|
|
44
|
+
};
|
|
45
|
+
if (error instanceof Error) {
|
|
46
|
+
errorContext.error = {
|
|
47
|
+
name: error.name,
|
|
48
|
+
message: error.message,
|
|
49
|
+
stack: error.stack,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
else if (error) {
|
|
53
|
+
errorContext.error = error;
|
|
54
|
+
}
|
|
55
|
+
this.log("error", message, errorContext);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Global logger instance
|
|
60
|
+
*/
|
|
61
|
+
export const logger = new Logger();
|
|
62
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for backend code review
|
|
3
|
+
*/
|
|
4
|
+
export declare const SYSTEM_PROMPT = "You are an expert backend developer and security specialist. Review backend code for security, performance, and architecture.";
|
|
5
|
+
export declare function buildUserMessage(code: string, reviewType?: string, language?: string, context?: string): string;
|
|
6
|
+
//# sourceMappingURL=backend-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-review.d.ts","sourceRoot":"","sources":["../../src/prompts/backend-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,aAAa,kIAAkI,CAAC;AAE7J,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAe,EAC3B,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACd,MAAM,CAWR"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for backend code review
|
|
3
|
+
*/
|
|
4
|
+
export const SYSTEM_PROMPT = `You are an expert backend developer and security specialist. Review backend code for security, performance, and architecture.`;
|
|
5
|
+
export function buildUserMessage(code, reviewType = "full", language, context) {
|
|
6
|
+
const focusArea = getFocusArea(reviewType);
|
|
7
|
+
const languageContext = language ? `Language/Framework: ${language}\n` : "";
|
|
8
|
+
const additionalContext = context ? `${context}\n` : "";
|
|
9
|
+
return `${languageContext}${additionalContext}${focusArea}
|
|
10
|
+
|
|
11
|
+
Code to review:
|
|
12
|
+
\`\`\`
|
|
13
|
+
${code}
|
|
14
|
+
\`\`\``;
|
|
15
|
+
}
|
|
16
|
+
function getFocusArea(reviewType) {
|
|
17
|
+
switch (reviewType) {
|
|
18
|
+
case "security":
|
|
19
|
+
return "Focus specifically on security (authentication, authorization, input validation, SQL injection, XSS, CSRF, secrets management).";
|
|
20
|
+
case "performance":
|
|
21
|
+
return "Focus specifically on backend performance (database queries, caching, async operations, resource usage, scalability).";
|
|
22
|
+
case "architecture":
|
|
23
|
+
return "Focus specifically on architecture (design patterns, separation of concerns, modularity, maintainability, scalability).";
|
|
24
|
+
default:
|
|
25
|
+
return "Provide a comprehensive backend review covering security, performance, and architecture.";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=backend-review.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for code review
|
|
3
|
+
*/
|
|
4
|
+
export declare const SYSTEM_PROMPT = "You are an expert code reviewer. Analyze the code for:\n- Code quality and best practices\n- Potential bugs and edge cases\n- Performance issues\n- Security vulnerabilities\n- Maintainability concerns\n\nProvide specific, actionable feedback.";
|
|
5
|
+
export declare function buildUserMessage(code: string, context?: string): string;
|
|
6
|
+
//# sourceMappingURL=code-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-review.d.ts","sourceRoot":"","sources":["../../src/prompts/code-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,aAAa,uPAOa,CAAC;AAExC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for code review
|
|
3
|
+
*/
|
|
4
|
+
export const SYSTEM_PROMPT = `You are an expert code reviewer. Analyze the code for:
|
|
5
|
+
- Code quality and best practices
|
|
6
|
+
- Potential bugs and edge cases
|
|
7
|
+
- Performance issues
|
|
8
|
+
- Security vulnerabilities
|
|
9
|
+
- Maintainability concerns
|
|
10
|
+
|
|
11
|
+
Provide specific, actionable feedback.`;
|
|
12
|
+
export function buildUserMessage(code, context) {
|
|
13
|
+
if (context) {
|
|
14
|
+
return `${context}\n\nCode to review:\n\`\`\`\n${code}\n\`\`\``;
|
|
15
|
+
}
|
|
16
|
+
return `Code to review:\n\`\`\`\n${code}\n\`\`\``;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=code-review.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for frontend code review
|
|
3
|
+
*/
|
|
4
|
+
export declare const SYSTEM_PROMPT = "You are an expert frontend developer and UX specialist. Review frontend code for best practices.";
|
|
5
|
+
export declare function buildUserMessage(code: string, reviewType?: string, framework?: string, context?: string): string;
|
|
6
|
+
//# sourceMappingURL=frontend-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontend-review.d.ts","sourceRoot":"","sources":["../../src/prompts/frontend-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,aAAa,qGAAqG,CAAC;AAEhI,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAe,EAC3B,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACd,MAAM,CAWR"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for frontend code review
|
|
3
|
+
*/
|
|
4
|
+
export const SYSTEM_PROMPT = `You are an expert frontend developer and UX specialist. Review frontend code for best practices.`;
|
|
5
|
+
export function buildUserMessage(code, reviewType = "full", framework, context) {
|
|
6
|
+
const focusArea = getFocusArea(reviewType);
|
|
7
|
+
const frameworkContext = framework ? `Framework: ${framework}\n` : "";
|
|
8
|
+
const additionalContext = context ? `${context}\n` : "";
|
|
9
|
+
return `${frameworkContext}${additionalContext}${focusArea}
|
|
10
|
+
|
|
11
|
+
Code to review:
|
|
12
|
+
\`\`\`
|
|
13
|
+
${code}
|
|
14
|
+
\`\`\``;
|
|
15
|
+
}
|
|
16
|
+
function getFocusArea(reviewType) {
|
|
17
|
+
switch (reviewType) {
|
|
18
|
+
case "accessibility":
|
|
19
|
+
return "Focus specifically on accessibility (WCAG compliance, ARIA labels, keyboard navigation, screen reader support).";
|
|
20
|
+
case "performance":
|
|
21
|
+
return "Focus specifically on frontend performance (bundle size, render optimization, lazy loading, Core Web Vitals).";
|
|
22
|
+
case "ux":
|
|
23
|
+
return "Focus specifically on user experience (intuitive design, error handling, loading states, responsive design).";
|
|
24
|
+
default:
|
|
25
|
+
return "Provide a comprehensive frontend review covering accessibility, performance, and user experience.";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=frontend-review.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for implementation plan review
|
|
3
|
+
*/
|
|
4
|
+
export declare const SYSTEM_PROMPT = "You are an expert software architect and project planner. Review implementation plans before code is written to catch issues early.";
|
|
5
|
+
export declare function buildUserMessage(plan: string, reviewType?: string, context?: string): string;
|
|
6
|
+
//# sourceMappingURL=plan-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-review.d.ts","sourceRoot":"","sources":["../../src/prompts/plan-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,aAAa,wIAAwI,CAAC;AAEnK,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAe,EAC3B,OAAO,CAAC,EAAE,MAAM,GACd,MAAM,CAUR"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for implementation plan review
|
|
3
|
+
*/
|
|
4
|
+
export const SYSTEM_PROMPT = `You are an expert software architect and project planner. Review implementation plans before code is written to catch issues early.`;
|
|
5
|
+
export function buildUserMessage(plan, reviewType = "full", context) {
|
|
6
|
+
const focusArea = getFocusArea(reviewType);
|
|
7
|
+
const additionalContext = context ? `${context}\n` : "";
|
|
8
|
+
return `${additionalContext}${focusArea}
|
|
9
|
+
|
|
10
|
+
Implementation plan to review:
|
|
11
|
+
\`\`\`
|
|
12
|
+
${plan}
|
|
13
|
+
\`\`\``;
|
|
14
|
+
}
|
|
15
|
+
function getFocusArea(reviewType) {
|
|
16
|
+
switch (reviewType) {
|
|
17
|
+
case "feasibility":
|
|
18
|
+
return "Focus specifically on feasibility (technical complexity, resource requirements, potential blockers, dependencies).";
|
|
19
|
+
case "completeness":
|
|
20
|
+
return "Focus specifically on completeness (missing requirements, edge cases, error handling, testing strategy).";
|
|
21
|
+
case "risks":
|
|
22
|
+
return "Focus specifically on risks (technical risks, security concerns, scalability issues, maintenance burden).";
|
|
23
|
+
case "timeline":
|
|
24
|
+
return "Focus specifically on timeline (realistic estimates, task breakdown, critical path, potential delays).";
|
|
25
|
+
default:
|
|
26
|
+
return "Provide a comprehensive plan review covering feasibility, completeness, risks, and timeline.";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=plan-review.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-model review client for code, frontend, backend, and plan reviews
|
|
3
|
+
* Uses OpenRouter API to access multiple LLM providers
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Result from a single model's review.
|
|
7
|
+
* Either contains a review or an error, never both.
|
|
8
|
+
*/
|
|
9
|
+
export interface ModelReviewResult {
|
|
10
|
+
/** The model identifier (e.g., "anthropic/claude-3.5-sonnet") */
|
|
11
|
+
model: string;
|
|
12
|
+
/** The review content from the model */
|
|
13
|
+
review: string;
|
|
14
|
+
/** Error message if the review failed */
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Client for performing multi-model code reviews.
|
|
19
|
+
* Supports parallel execution across multiple AI models for diverse perspectives.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const client = new ReviewClient(process.env.OPENROUTER_API_KEY);
|
|
24
|
+
* const results = await client.reviewCode(
|
|
25
|
+
* 'function add(a, b) { return a + b; }',
|
|
26
|
+
* ['anthropic/claude-3.5-sonnet', 'openai/gpt-4-turbo'],
|
|
27
|
+
* 'JavaScript addition function'
|
|
28
|
+
* );
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class ReviewClient {
|
|
32
|
+
private client;
|
|
33
|
+
constructor(apiKey: string);
|
|
34
|
+
/**
|
|
35
|
+
* Send a chat request to OpenRouter API
|
|
36
|
+
* @param model - Model identifier (e.g., "anthropic/claude-3.5-sonnet")
|
|
37
|
+
* @param systemPrompt - System prompt for the model
|
|
38
|
+
* @param userMessage - User message/question
|
|
39
|
+
* @returns The model's response content
|
|
40
|
+
* @throws {OpenRouterError} If the API call fails
|
|
41
|
+
*/
|
|
42
|
+
private chat;
|
|
43
|
+
/**
|
|
44
|
+
* Review code for quality, bugs, performance, and security
|
|
45
|
+
* @param code - Code to review
|
|
46
|
+
* @param models - Array of model identifiers to use
|
|
47
|
+
* @param context - Optional context (language, description, etc.)
|
|
48
|
+
* @returns Array of review results from each model
|
|
49
|
+
*/
|
|
50
|
+
reviewCode(code: string, models: string[], context?: string): Promise<ModelReviewResult[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Review frontend code for accessibility, performance, and UX
|
|
53
|
+
*/
|
|
54
|
+
reviewFrontend(code: string, models: string[], options?: {
|
|
55
|
+
framework?: string;
|
|
56
|
+
reviewType?: "accessibility" | "performance" | "ux" | "full";
|
|
57
|
+
context?: string;
|
|
58
|
+
}): Promise<ModelReviewResult[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Review backend code for security, performance, and architecture
|
|
61
|
+
*/
|
|
62
|
+
reviewBackend(code: string, models: string[], options?: {
|
|
63
|
+
language?: string;
|
|
64
|
+
reviewType?: "security" | "performance" | "architecture" | "full";
|
|
65
|
+
context?: string;
|
|
66
|
+
}): Promise<ModelReviewResult[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Review implementation plans before code is written
|
|
69
|
+
*/
|
|
70
|
+
reviewPlan(plan: string, models: string[], options?: {
|
|
71
|
+
reviewType?: "feasibility" | "completeness" | "risks" | "timeline" | "full";
|
|
72
|
+
context?: string;
|
|
73
|
+
}): Promise<ModelReviewResult[]>;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=review-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-client.d.ts","sourceRoot":"","sources":["../src/review-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,MAAM;IAM1B;;;;;;;OAOG;YACW,IAAI;IAoDlB;;;;;;OAMG;IACG,UAAU,CACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAQ/B;;OAEG;IACG,cAAc,CACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,eAAe,GAAG,aAAa,GAAG,IAAI,GAAG,MAAM,CAAC;QAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GACC,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAa/B;;OAEG;IACG,aAAa,CAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE;QACT,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,cAAc,GAAG,MAAM,CAAC;QAClE,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GACC,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAa/B;;OAEG;IACG,UAAU,CACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE;QACT,UAAU,CAAC,EACR,aAAa,GACb,cAAc,GACd,OAAO,GACP,UAAU,GACV,MAAM,CAAC;QACV,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GACC,OAAO,CAAC,iBAAiB,EAAE,CAAC;CAW/B"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-model review client for code, frontend, backend, and plan reviews
|
|
3
|
+
* Uses OpenRouter API to access multiple LLM providers
|
|
4
|
+
*/
|
|
5
|
+
import { OpenRouter } from "@openrouter/sdk";
|
|
6
|
+
import { LLM_CONFIG } from "./constants";
|
|
7
|
+
import { OpenRouterError } from "./errors";
|
|
8
|
+
import { logger } from "./logger";
|
|
9
|
+
import * as backendReviewPrompts from "./prompts/backend-review";
|
|
10
|
+
import * as codeReviewPrompts from "./prompts/code-review";
|
|
11
|
+
import * as frontendReviewPrompts from "./prompts/frontend-review";
|
|
12
|
+
import * as planReviewPrompts from "./prompts/plan-review";
|
|
13
|
+
import { executeInParallel } from "./utils/parallel-executor";
|
|
14
|
+
/**
|
|
15
|
+
* Client for performing multi-model code reviews.
|
|
16
|
+
* Supports parallel execution across multiple AI models for diverse perspectives.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const client = new ReviewClient(process.env.OPENROUTER_API_KEY);
|
|
21
|
+
* const results = await client.reviewCode(
|
|
22
|
+
* 'function add(a, b) { return a + b; }',
|
|
23
|
+
* ['anthropic/claude-3.5-sonnet', 'openai/gpt-4-turbo'],
|
|
24
|
+
* 'JavaScript addition function'
|
|
25
|
+
* );
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class ReviewClient {
|
|
29
|
+
client;
|
|
30
|
+
constructor(apiKey) {
|
|
31
|
+
this.client = new OpenRouter({
|
|
32
|
+
apiKey,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Send a chat request to OpenRouter API
|
|
37
|
+
* @param model - Model identifier (e.g., "anthropic/claude-3.5-sonnet")
|
|
38
|
+
* @param systemPrompt - System prompt for the model
|
|
39
|
+
* @param userMessage - User message/question
|
|
40
|
+
* @returns The model's response content
|
|
41
|
+
* @throws {OpenRouterError} If the API call fails
|
|
42
|
+
*/
|
|
43
|
+
async chat(model, systemPrompt, userMessage) {
|
|
44
|
+
try {
|
|
45
|
+
logger.debug("Sending chat request", {
|
|
46
|
+
model,
|
|
47
|
+
messageLength: userMessage.length,
|
|
48
|
+
});
|
|
49
|
+
const response = await this.client.chat.send({
|
|
50
|
+
model,
|
|
51
|
+
messages: [
|
|
52
|
+
{ role: "system", content: systemPrompt },
|
|
53
|
+
{ role: "user", content: userMessage },
|
|
54
|
+
],
|
|
55
|
+
temperature: LLM_CONFIG.DEFAULT_TEMPERATURE,
|
|
56
|
+
maxTokens: LLM_CONFIG.DEFAULT_MAX_TOKENS,
|
|
57
|
+
});
|
|
58
|
+
const content = response.choices?.[0]?.message?.content;
|
|
59
|
+
if (typeof content === "string") {
|
|
60
|
+
logger.debug("Received response", { model, length: content.length });
|
|
61
|
+
return content;
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(content)) {
|
|
64
|
+
const text = content
|
|
65
|
+
.filter((item) => item.type === "text")
|
|
66
|
+
.map((item) => item.text)
|
|
67
|
+
.join("\n");
|
|
68
|
+
logger.debug("Received array response", { model, length: text.length });
|
|
69
|
+
return text;
|
|
70
|
+
}
|
|
71
|
+
throw new OpenRouterError("No response content from model", 500);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error instanceof OpenRouterError) {
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
78
|
+
logger.error("Chat request failed", error, { model });
|
|
79
|
+
const isRetryable = message.includes("429") || message.includes("rate limit");
|
|
80
|
+
throw new OpenRouterError(message, undefined, isRetryable);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Review code for quality, bugs, performance, and security
|
|
85
|
+
* @param code - Code to review
|
|
86
|
+
* @param models - Array of model identifiers to use
|
|
87
|
+
* @param context - Optional context (language, description, etc.)
|
|
88
|
+
* @returns Array of review results from each model
|
|
89
|
+
*/
|
|
90
|
+
async reviewCode(code, models, context) {
|
|
91
|
+
const userMessage = codeReviewPrompts.buildUserMessage(code, context);
|
|
92
|
+
return executeInParallel(models, (model) => this.chat(model, codeReviewPrompts.SYSTEM_PROMPT, userMessage));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Review frontend code for accessibility, performance, and UX
|
|
96
|
+
*/
|
|
97
|
+
async reviewFrontend(code, models, options) {
|
|
98
|
+
const userMessage = frontendReviewPrompts.buildUserMessage(code, options?.reviewType || "full", options?.framework, options?.context);
|
|
99
|
+
return executeInParallel(models, (model) => this.chat(model, frontendReviewPrompts.SYSTEM_PROMPT, userMessage));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Review backend code for security, performance, and architecture
|
|
103
|
+
*/
|
|
104
|
+
async reviewBackend(code, models, options) {
|
|
105
|
+
const userMessage = backendReviewPrompts.buildUserMessage(code, options?.reviewType || "full", options?.language, options?.context);
|
|
106
|
+
return executeInParallel(models, (model) => this.chat(model, backendReviewPrompts.SYSTEM_PROMPT, userMessage));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Review implementation plans before code is written
|
|
110
|
+
*/
|
|
111
|
+
async reviewPlan(plan, models, options) {
|
|
112
|
+
const userMessage = planReviewPrompts.buildUserMessage(plan, options?.reviewType || "full", options?.context);
|
|
113
|
+
return executeInParallel(models, (model) => this.chat(model, planReviewPrompts.SYSTEM_PROMPT, userMessage));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=review-client.js.map
|