@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.
Files changed (58) hide show
  1. package/.env.example +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +342 -0
  4. package/dist/config.d.ts +48 -0
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +61 -0
  7. package/dist/constants.d.ts +33 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +36 -0
  10. package/dist/errors.d.ts +53 -0
  11. package/dist/errors.d.ts.map +1 -0
  12. package/dist/errors.js +92 -0
  13. package/dist/index.d.ts +7 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +79 -0
  16. package/dist/logger.d.ts +22 -0
  17. package/dist/logger.d.ts.map +1 -0
  18. package/dist/logger.js +62 -0
  19. package/dist/prompts/backend-review.d.ts +6 -0
  20. package/dist/prompts/backend-review.d.ts.map +1 -0
  21. package/dist/prompts/backend-review.js +28 -0
  22. package/dist/prompts/code-review.d.ts +6 -0
  23. package/dist/prompts/code-review.d.ts.map +1 -0
  24. package/dist/prompts/code-review.js +18 -0
  25. package/dist/prompts/frontend-review.d.ts +6 -0
  26. package/dist/prompts/frontend-review.d.ts.map +1 -0
  27. package/dist/prompts/frontend-review.js +28 -0
  28. package/dist/prompts/plan-review.d.ts +6 -0
  29. package/dist/prompts/plan-review.d.ts.map +1 -0
  30. package/dist/prompts/plan-review.js +29 -0
  31. package/dist/review-client.d.ts +75 -0
  32. package/dist/review-client.d.ts.map +1 -0
  33. package/dist/review-client.js +116 -0
  34. package/dist/schemas.d.ts +60 -0
  35. package/dist/schemas.d.ts.map +1 -0
  36. package/dist/schemas.js +46 -0
  37. package/dist/tools/factory.d.ts +20 -0
  38. package/dist/tools/factory.d.ts.map +1 -0
  39. package/dist/tools/factory.js +55 -0
  40. package/dist/tools/list-config.d.ts +9 -0
  41. package/dist/tools/list-config.d.ts.map +1 -0
  42. package/dist/tools/list-config.js +31 -0
  43. package/dist/tools/review-backend.d.ts +22 -0
  44. package/dist/tools/review-backend.d.ts.map +1 -0
  45. package/dist/tools/review-backend.js +38 -0
  46. package/dist/tools/review-code.d.ts +15 -0
  47. package/dist/tools/review-code.d.ts.map +1 -0
  48. package/dist/tools/review-code.js +29 -0
  49. package/dist/tools/review-frontend.d.ts +22 -0
  50. package/dist/tools/review-frontend.d.ts.map +1 -0
  51. package/dist/tools/review-frontend.js +38 -0
  52. package/dist/tools/review-plan.d.ts +22 -0
  53. package/dist/tools/review-plan.d.ts.map +1 -0
  54. package/dist/tools/review-plan.js +35 -0
  55. package/dist/utils/parallel-executor.d.ts +10 -0
  56. package/dist/utils/parallel-executor.d.ts.map +1 -0
  57. package/dist/utils/parallel-executor.js +21 -0
  58. 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
@@ -0,0 +1,7 @@
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
+ //# sourceMappingURL=index.d.ts.map
@@ -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
@@ -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