@maxanatsko/gemini-mcp-tool 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +230 -0
  3. package/dist/constants.d.ts +153 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +150 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +188 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/tools/ask-gemini.tool.d.ts +3 -0
  12. package/dist/tools/ask-gemini.tool.d.ts.map +1 -0
  13. package/dist/tools/ask-gemini.tool.js +74 -0
  14. package/dist/tools/ask-gemini.tool.js.map +1 -0
  15. package/dist/tools/brainstorm.tool.d.ts +3 -0
  16. package/dist/tools/brainstorm.tool.d.ts.map +1 -0
  17. package/dist/tools/brainstorm.tool.js +202 -0
  18. package/dist/tools/brainstorm.tool.js.map +1 -0
  19. package/dist/tools/fetch-chunk.tool.d.ts +3 -0
  20. package/dist/tools/fetch-chunk.tool.d.ts.map +1 -0
  21. package/dist/tools/fetch-chunk.tool.js +62 -0
  22. package/dist/tools/fetch-chunk.tool.js.map +1 -0
  23. package/dist/tools/index.d.ts +2 -0
  24. package/dist/tools/index.d.ts.map +1 -0
  25. package/dist/tools/index.js +11 -0
  26. package/dist/tools/index.js.map +1 -0
  27. package/dist/tools/registry.d.ts +25 -0
  28. package/dist/tools/registry.d.ts.map +1 -0
  29. package/dist/tools/registry.js +80 -0
  30. package/dist/tools/registry.js.map +1 -0
  31. package/dist/tools/review-code.tool.d.ts +3 -0
  32. package/dist/tools/review-code.tool.d.ts.map +1 -0
  33. package/dist/tools/review-code.tool.js +186 -0
  34. package/dist/tools/review-code.tool.js.map +1 -0
  35. package/dist/tools/simple-tools.d.ts +4 -0
  36. package/dist/tools/simple-tools.d.ts.map +1 -0
  37. package/dist/tools/simple-tools.js +32 -0
  38. package/dist/tools/simple-tools.js.map +1 -0
  39. package/dist/tools/test-tool.example.d.ts +13 -0
  40. package/dist/tools/test-tool.example.d.ts.map +1 -0
  41. package/dist/tools/test-tool.example.js +32 -0
  42. package/dist/tools/test-tool.example.js.map +1 -0
  43. package/dist/tools/timeout-test.tool.d.ts +3 -0
  44. package/dist/tools/timeout-test.tool.d.ts.map +1 -0
  45. package/dist/tools/timeout-test.tool.js +32 -0
  46. package/dist/tools/timeout-test.tool.js.map +1 -0
  47. package/dist/utils/askGeminiSessionManager.d.ts +57 -0
  48. package/dist/utils/askGeminiSessionManager.d.ts.map +1 -0
  49. package/dist/utils/askGeminiSessionManager.js +110 -0
  50. package/dist/utils/askGeminiSessionManager.js.map +1 -0
  51. package/dist/utils/brainstormSessionManager.d.ts +67 -0
  52. package/dist/utils/brainstormSessionManager.d.ts.map +1 -0
  53. package/dist/utils/brainstormSessionManager.js +165 -0
  54. package/dist/utils/brainstormSessionManager.js.map +1 -0
  55. package/dist/utils/changeModeChunker.d.ts +11 -0
  56. package/dist/utils/changeModeChunker.d.ts.map +1 -0
  57. package/dist/utils/changeModeChunker.js +89 -0
  58. package/dist/utils/changeModeChunker.js.map +1 -0
  59. package/dist/utils/changeModeParser.d.ts +15 -0
  60. package/dist/utils/changeModeParser.d.ts.map +1 -0
  61. package/dist/utils/changeModeParser.js +67 -0
  62. package/dist/utils/changeModeParser.js.map +1 -0
  63. package/dist/utils/changeModeTranslator.d.ts +8 -0
  64. package/dist/utils/changeModeTranslator.d.ts.map +1 -0
  65. package/dist/utils/changeModeTranslator.js +70 -0
  66. package/dist/utils/changeModeTranslator.js.map +1 -0
  67. package/dist/utils/chunkCache.d.ts +22 -0
  68. package/dist/utils/chunkCache.d.ts.map +1 -0
  69. package/dist/utils/chunkCache.js +161 -0
  70. package/dist/utils/chunkCache.js.map +1 -0
  71. package/dist/utils/commandExecutor.d.ts +2 -0
  72. package/dist/utils/commandExecutor.d.ts.map +1 -0
  73. package/dist/utils/commandExecutor.js +74 -0
  74. package/dist/utils/commandExecutor.js.map +1 -0
  75. package/dist/utils/geminiExecutor.d.ts +3 -0
  76. package/dist/utils/geminiExecutor.d.ts.map +1 -0
  77. package/dist/utils/geminiExecutor.js +170 -0
  78. package/dist/utils/geminiExecutor.js.map +1 -0
  79. package/dist/utils/gitStateDetector.d.ts +31 -0
  80. package/dist/utils/gitStateDetector.d.ts.map +1 -0
  81. package/dist/utils/gitStateDetector.js +67 -0
  82. package/dist/utils/gitStateDetector.js.map +1 -0
  83. package/dist/utils/logger.d.ts +13 -0
  84. package/dist/utils/logger.d.ts.map +1 -0
  85. package/dist/utils/logger.js +42 -0
  86. package/dist/utils/logger.js.map +1 -0
  87. package/dist/utils/reviewFormatter.d.ts +35 -0
  88. package/dist/utils/reviewFormatter.d.ts.map +1 -0
  89. package/dist/utils/reviewFormatter.js +198 -0
  90. package/dist/utils/reviewFormatter.js.map +1 -0
  91. package/dist/utils/reviewPromptBuilder.d.ts +35 -0
  92. package/dist/utils/reviewPromptBuilder.d.ts.map +1 -0
  93. package/dist/utils/reviewPromptBuilder.js +146 -0
  94. package/dist/utils/reviewPromptBuilder.js.map +1 -0
  95. package/dist/utils/reviewResponseParser.d.ts +20 -0
  96. package/dist/utils/reviewResponseParser.d.ts.map +1 -0
  97. package/dist/utils/reviewResponseParser.js +149 -0
  98. package/dist/utils/reviewResponseParser.js.map +1 -0
  99. package/dist/utils/reviewSessionCache.d.ts +81 -0
  100. package/dist/utils/reviewSessionCache.d.ts.map +1 -0
  101. package/dist/utils/reviewSessionCache.js +220 -0
  102. package/dist/utils/reviewSessionCache.js.map +1 -0
  103. package/dist/utils/reviewSessionManager.d.ts +52 -0
  104. package/dist/utils/reviewSessionManager.d.ts.map +1 -0
  105. package/dist/utils/reviewSessionManager.js +65 -0
  106. package/dist/utils/reviewSessionManager.js.map +1 -0
  107. package/dist/utils/sessionManager.d.ts +94 -0
  108. package/dist/utils/sessionManager.d.ts.map +1 -0
  109. package/dist/utils/sessionManager.js +374 -0
  110. package/dist/utils/sessionManager.js.map +1 -0
  111. package/dist/utils/sessionSchemas.d.ts +126 -0
  112. package/dist/utils/sessionSchemas.d.ts.map +1 -0
  113. package/dist/utils/sessionSchemas.js +2 -0
  114. package/dist/utils/sessionSchemas.js.map +1 -0
  115. package/dist/utils/timeoutManager.d.ts +2 -0
  116. package/dist/utils/timeoutManager.d.ts.map +1 -0
  117. package/dist/utils/timeoutManager.js +2 -0
  118. package/dist/utils/timeoutManager.js.map +1 -0
  119. package/package.json +71 -0
@@ -0,0 +1,35 @@
1
+ import { CodeReviewSession, ReviewRound, ReviewComment } from './reviewSessionCache.js';
2
+ export interface ReviewFormatterConfig {
3
+ session: CodeReviewSession;
4
+ currentRound: ReviewRound;
5
+ newComments: ReviewComment[];
6
+ showHistory: boolean;
7
+ }
8
+ /**
9
+ * Formats the review response for Claude
10
+ * @param config Formatter configuration
11
+ * @returns Formatted markdown string
12
+ */
13
+ export declare function formatReviewResponse(config: ReviewFormatterConfig): string;
14
+ /**
15
+ * Groups comments by file pattern
16
+ * @param comments Array of comments
17
+ * @returns Map of file patterns to comments
18
+ */
19
+ export declare function groupCommentsByFile(comments: ReviewComment[]): Map<string, ReviewComment[]>;
20
+ /**
21
+ * Formats a message when session expires or is not found
22
+ * @param sessionId The session ID that was requested
23
+ * @param currentGitBranch Current git branch
24
+ * @param currentGitCommit Current git commit hash
25
+ * @returns Formatted error message
26
+ */
27
+ export declare function formatSessionNotFound(sessionId: string, currentGitBranch: string, currentGitCommit: string): string;
28
+ /**
29
+ * Formats a warning message for git state changes
30
+ * @param reason The reason for the warning
31
+ * @param continuing Whether the session is continuing anyway
32
+ * @returns Formatted warning string
33
+ */
34
+ export declare function formatGitStateWarning(reason: string, continuing: boolean): string;
35
+ //# sourceMappingURL=reviewFormatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewFormatter.d.ts","sourceRoot":"","sources":["../../src/utils/reviewFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxF,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,YAAY,EAAE,WAAW,CAAC;IAC1B,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CA+B1E;AAyDD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAgB3F;AA8ED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAeR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,CAUjF"}
@@ -0,0 +1,198 @@
1
+ import { REVIEW } from '../constants.js';
2
+ /**
3
+ * Formats the review response for Claude
4
+ * @param config Formatter configuration
5
+ * @returns Formatted markdown string
6
+ */
7
+ export function formatReviewResponse(config) {
8
+ const { session, currentRound, newComments, showHistory } = config;
9
+ let output = `# Code Review - Round ${currentRound.roundNumber}\n\n`;
10
+ // Session info
11
+ output += `**Session:** \`${session.sessionId}\`\n`;
12
+ output += `**Branch:** ${session.currentGitState.branch} @ ${session.currentGitState.commitHash.slice(0, 8)}\n`;
13
+ output += `**Files Reviewed:** ${currentRound.filesReviewed.length}\n\n`;
14
+ // Summary
15
+ output += formatSummary(newComments);
16
+ // Comments by file
17
+ if (newComments.length > 0) {
18
+ output += `## Issues Found\n\n`;
19
+ output += formatCommentsByFile(newComments);
20
+ }
21
+ else {
22
+ output += `## Result\n\n`;
23
+ output += `✅ No new issues found in this round.\n\n`;
24
+ }
25
+ // Session continuation instructions
26
+ output += formatContinuationInstructions(session);
27
+ // History summary if enabled
28
+ if (showHistory && session.rounds.length > 1) {
29
+ output += formatHistorySummary(session);
30
+ }
31
+ return output;
32
+ }
33
+ /**
34
+ * Formats the summary section with severity counts
35
+ * @param comments Array of comments to summarize
36
+ * @returns Formatted summary string
37
+ */
38
+ function formatSummary(comments) {
39
+ const criticalCount = comments.filter(c => c.severity === 'critical').length;
40
+ const importantCount = comments.filter(c => c.severity === 'important').length;
41
+ const suggestionCount = comments.filter(c => c.severity === 'suggestion').length;
42
+ const questionCount = comments.filter(c => c.severity === 'question').length;
43
+ let summary = `## Summary\n`;
44
+ summary += `- 🔴 Critical: ${criticalCount}\n`;
45
+ summary += `- 🟠 Important: ${importantCount}\n`;
46
+ summary += `- 🟡 Suggestions: ${suggestionCount}\n`;
47
+ summary += `- 💬 Questions: ${questionCount}\n`;
48
+ summary += `- **Total:** ${comments.length} issues\n\n`;
49
+ return summary;
50
+ }
51
+ /**
52
+ * Formats comments grouped by file
53
+ * @param comments Array of comments to format
54
+ * @returns Formatted comments string
55
+ */
56
+ function formatCommentsByFile(comments) {
57
+ const commentsByFile = groupCommentsByFile(comments);
58
+ let output = '';
59
+ for (const [file, fileComments] of commentsByFile) {
60
+ output += `### ${file}\n\n`;
61
+ fileComments.forEach((comment, idx) => {
62
+ const severityEmoji = REVIEW.SEVERITY_EMOJI[comment.severity] || '📌';
63
+ output += `#### ${severityEmoji} Issue ${idx + 1}\n`;
64
+ output += `**Comment ID:** \`${comment.id}\`\n`;
65
+ if (comment.lineRange) {
66
+ if (comment.lineRange.start === comment.lineRange.end) {
67
+ output += `**Line:** ${comment.lineRange.start}\n`;
68
+ }
69
+ else {
70
+ output += `**Lines:** ${comment.lineRange.start}-${comment.lineRange.end}\n`;
71
+ }
72
+ }
73
+ output += `\n${comment.comment}\n\n`;
74
+ output += `---\n\n`;
75
+ });
76
+ }
77
+ return output;
78
+ }
79
+ /**
80
+ * Groups comments by file pattern
81
+ * @param comments Array of comments
82
+ * @returns Map of file patterns to comments
83
+ */
84
+ export function groupCommentsByFile(comments) {
85
+ const groups = new Map();
86
+ // Sort comments by severity first
87
+ const sortedComments = [...comments].sort((a, b) => {
88
+ const severityOrder = { critical: 0, important: 1, suggestion: 2, question: 3 };
89
+ return severityOrder[a.severity] - severityOrder[b.severity];
90
+ });
91
+ sortedComments.forEach(comment => {
92
+ const existing = groups.get(comment.filePattern) || [];
93
+ existing.push(comment);
94
+ groups.set(comment.filePattern, existing);
95
+ });
96
+ return groups;
97
+ }
98
+ /**
99
+ * Formats continuation instructions
100
+ * @param session The current session
101
+ * @returns Formatted instructions string
102
+ */
103
+ function formatContinuationInstructions(session) {
104
+ const expiryDate = new Date(session.lastAccessedAt + REVIEW.SESSION.TTL);
105
+ let instructions = `## Continue Review\n\n`;
106
+ instructions += `To continue this review session:\n`;
107
+ instructions += `1. Make your code changes based on the feedback above\n`;
108
+ instructions += `2. Call the \`review-code\` tool again (session auto-detected from git state)\n`;
109
+ instructions += `3. Optionally provide \`commentDecisions\` to track which issues you've addressed\n\n`;
110
+ instructions += `**Example:**\n`;
111
+ instructions += '```json\n';
112
+ instructions += `{
113
+ "name": "review-code",
114
+ "arguments": {
115
+ "prompt": "I've fixed the security issues. Please review.",
116
+ "commentDecisions": [
117
+ {"commentId": "cmt-xxx", "decision": "accepted", "notes": "Fixed"}
118
+ ]
119
+ }
120
+ }
121
+ `;
122
+ instructions += '```\n\n';
123
+ instructions += `**Session Details:**\n`;
124
+ instructions += `- Session ID: \`${session.sessionId}\`\n`;
125
+ instructions += `- Expires: ${expiryDate.toLocaleString()}\n`;
126
+ instructions += `- Git State: ${session.currentGitState.branch} @ ${session.currentGitState.commitHash.slice(0, 8)}\n\n`;
127
+ return instructions;
128
+ }
129
+ /**
130
+ * Formats the history summary
131
+ * @param session The current session
132
+ * @returns Formatted history string
133
+ */
134
+ function formatHistorySummary(session) {
135
+ let history = `## Review History\n\n`;
136
+ // Exclude current (last) round from history summary
137
+ const previousRounds = session.rounds.slice(0, -1);
138
+ if (previousRounds.length === 0) {
139
+ return '';
140
+ }
141
+ history += `| Round | Files | Issues | Resolved | Pending |\n`;
142
+ history += `|-------|-------|--------|----------|----------|\n`;
143
+ previousRounds.forEach(round => {
144
+ const resolved = round.commentsGenerated.filter(c => c.status !== 'pending').length;
145
+ const pending = round.commentsGenerated.filter(c => c.status === 'pending').length;
146
+ history += `| ${round.roundNumber} | ${round.filesReviewed.length} | ${round.commentsGenerated.length} | ${resolved} | ${pending} |\n`;
147
+ });
148
+ history += `\n`;
149
+ // Overall statistics
150
+ const totalResolved = session.allComments.filter(c => c.status !== 'pending').length;
151
+ const totalPending = session.allComments.filter(c => c.status === 'pending').length;
152
+ history += `**Overall Progress:**\n`;
153
+ history += `- Total Issues: ${session.allComments.length}\n`;
154
+ history += `- Resolved: ${totalResolved}\n`;
155
+ history += `- Pending: ${totalPending}\n`;
156
+ history += `- Files Tracked: ${session.filesTracked.length}\n\n`;
157
+ return history;
158
+ }
159
+ /**
160
+ * Formats a message when session expires or is not found
161
+ * @param sessionId The session ID that was requested
162
+ * @param currentGitBranch Current git branch
163
+ * @param currentGitCommit Current git commit hash
164
+ * @returns Formatted error message
165
+ */
166
+ export function formatSessionNotFound(sessionId, currentGitBranch, currentGitCommit) {
167
+ return `⚠️ **Session Not Found or Expired**
168
+
169
+ The review session \`${sessionId}\` was not found or has expired.
170
+
171
+ **Current Git State:**
172
+ - Branch: ${currentGitBranch}
173
+ - Commit: ${currentGitCommit.slice(0, 8)}
174
+
175
+ **Available Options:**
176
+ 1. Start a new review session with \`forceNewSession: true\`
177
+ 2. Wait if you just made a commit (session auto-creates based on current git state)
178
+
179
+ **Note:** Review sessions expire after 60 minutes of inactivity.
180
+ `;
181
+ }
182
+ /**
183
+ * Formats a warning message for git state changes
184
+ * @param reason The reason for the warning
185
+ * @param continuing Whether the session is continuing anyway
186
+ * @returns Formatted warning string
187
+ */
188
+ export function formatGitStateWarning(reason, continuing) {
189
+ let warning = `⚠️ **Git State Changed**\n\n${reason}\n\n`;
190
+ if (continuing) {
191
+ warning += `Continuing with existing session. Use \`forceNewSession: true\` to start fresh.\n`;
192
+ }
193
+ else {
194
+ warning += `Creating new session for current git state.\n`;
195
+ }
196
+ return warning;
197
+ }
198
+ //# sourceMappingURL=reviewFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewFormatter.js","sourceRoot":"","sources":["../../src/utils/reviewFormatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { CodeReviewSession } from './reviewSessionCache.js';
2
+ import { GitState } from './gitStateDetector.js';
3
+ export interface ReviewPromptConfig {
4
+ userPrompt: string;
5
+ session: CodeReviewSession;
6
+ files?: string[];
7
+ reviewType: string;
8
+ includeHistory: boolean;
9
+ currentGitState: GitState;
10
+ }
11
+ /**
12
+ * Builds a context-aware review prompt for Gemini
13
+ * @param config Review prompt configuration
14
+ * @returns Formatted prompt string
15
+ */
16
+ export declare function buildReviewPrompt(config: ReviewPromptConfig): string;
17
+ /**
18
+ * Returns review instructions based on review type
19
+ * @param reviewType The type of review to perform
20
+ * @returns Formatted instructions string
21
+ */
22
+ export declare function getReviewTypeInstructions(reviewType: string): string;
23
+ /**
24
+ * Formats previous review rounds for context inclusion
25
+ * @param session The current review session
26
+ * @returns Formatted history string
27
+ */
28
+ export declare function formatPreviousRounds(session: CodeReviewSession): string;
29
+ /**
30
+ * Extracts file patterns from a prompt containing @ references
31
+ * @param prompt The prompt to parse
32
+ * @returns Array of file patterns
33
+ */
34
+ export declare function extractFilesFromPrompt(prompt: string): string[];
35
+ //# sourceMappingURL=reviewPromptBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewPromptBuilder.d.ts","sourceRoot":"","sources":["../../src/utils/reviewPromptBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAe,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,QAAQ,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA6CpE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA2CpE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CA8CvE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAU/D"}
@@ -0,0 +1,146 @@
1
+ import { REVIEW } from '../constants.js';
2
+ /**
3
+ * Builds a context-aware review prompt for Gemini
4
+ * @param config Review prompt configuration
5
+ * @returns Formatted prompt string
6
+ */
7
+ export function buildReviewPrompt(config) {
8
+ const { userPrompt, session, files, reviewType, includeHistory, currentGitState } = config;
9
+ // Build file references with @ syntax
10
+ const fileRefs = files?.map(f => `@${f}`).join(' ') || '';
11
+ let prompt = `# CODE REVIEW SESSION (Round ${session.totalRounds + 1})
12
+
13
+ ## Review Context
14
+ - Session ID: ${session.sessionId}
15
+ - Branch: ${currentGitState.branch}
16
+ - Commit: ${currentGitState.commitHash.slice(0, 8)}
17
+ - Review Type: ${reviewType}
18
+ - Files: ${files?.length || 'all tracked'} ${files ? 'specified' : 'files'}
19
+
20
+ ## Review Instructions
21
+ ${getReviewTypeInstructions(reviewType)}
22
+
23
+ ## Output Format
24
+ For each issue found, use this EXACT format:
25
+
26
+ **[SEVERITY: critical|important|suggestion|question]**
27
+ **File:** {filename}
28
+ **Lines:** {start}-{end} (if applicable, otherwise write "N/A")
29
+ **Issue:** {brief title}
30
+ **Details:** {explanation}
31
+ **Recommendation:** {suggested fix or action}
32
+
33
+ ---
34
+
35
+ `;
36
+ // Include conversation history if requested and exists
37
+ if (includeHistory && session.rounds.length > 0) {
38
+ prompt += formatPreviousRounds(session);
39
+ }
40
+ // Add user's current request
41
+ prompt += `\n## Current Review Request\n`;
42
+ if (fileRefs) {
43
+ prompt += `${fileRefs}\n\n`;
44
+ }
45
+ prompt += `${userPrompt}\n`;
46
+ return prompt;
47
+ }
48
+ /**
49
+ * Returns review instructions based on review type
50
+ * @param reviewType The type of review to perform
51
+ * @returns Formatted instructions string
52
+ */
53
+ export function getReviewTypeInstructions(reviewType) {
54
+ const instructions = {
55
+ security: `Focus on:
56
+ - Input validation and sanitization
57
+ - Authentication and authorization flaws
58
+ - SQL injection, XSS, CSRF vulnerabilities
59
+ - Secrets exposure (hardcoded credentials, API keys)
60
+ - Dependency vulnerabilities
61
+ - Insecure cryptography and data handling`,
62
+ performance: `Focus on:
63
+ - Algorithm complexity (O(n) analysis)
64
+ - Unnecessary loops or computations
65
+ - Memory leaks and inefficient data structures
66
+ - Database query optimization (N+1 queries, missing indexes)
67
+ - Caching opportunities
68
+ - Resource cleanup and connection pooling`,
69
+ quality: `Focus on:
70
+ - Code clarity and readability
71
+ - Naming conventions and consistency
72
+ - DRY violations (repeated code)
73
+ - Error handling and edge cases
74
+ - Test coverage gaps
75
+ - Documentation completeness`,
76
+ architecture: `Focus on:
77
+ - Design patterns and principles (SOLID, DRY, KISS)
78
+ - Module coupling and cohesion
79
+ - Scalability concerns
80
+ - API design and contracts
81
+ - Separation of concerns
82
+ - Technical debt and maintainability`,
83
+ general: `Perform a comprehensive review covering:
84
+ - Security vulnerabilities
85
+ - Performance bottlenecks
86
+ - Code quality issues
87
+ - Architectural concerns
88
+ Prioritize critical and important issues.`
89
+ };
90
+ return instructions[reviewType] || instructions.general;
91
+ }
92
+ /**
93
+ * Formats previous review rounds for context inclusion
94
+ * @param session The current review session
95
+ * @returns Formatted history string
96
+ */
97
+ export function formatPreviousRounds(session) {
98
+ let historyText = `\n## Previous Review Rounds\n`;
99
+ // Get last N rounds based on constant
100
+ const recentRounds = session.rounds.slice(-REVIEW.MAX_HISTORY_ROUNDS);
101
+ for (const round of recentRounds) {
102
+ historyText += `\n### Round ${round.roundNumber} (${new Date(round.timestamp).toLocaleString()})\n`;
103
+ historyText += `**User Request:** ${round.userPrompt}\n`;
104
+ historyText += `**Issues Found:** ${round.commentsGenerated.length}\n`;
105
+ // Include resolved/modified comments
106
+ const resolvedComments = round.commentsGenerated.filter(c => c.status !== 'pending');
107
+ if (resolvedComments.length > 0) {
108
+ historyText += `\n**Resolved Issues:**\n`;
109
+ resolvedComments.forEach(c => {
110
+ const statusEmoji = c.status === 'accepted' ? '✅' : c.status === 'rejected' ? '❌' : '📝';
111
+ historyText += `- [${statusEmoji} ${c.status.toUpperCase()}] ${c.filePattern}: ${c.comment.split('\n')[0]}`;
112
+ if (c.resolution) {
113
+ historyText += ` - ${c.resolution}`;
114
+ }
115
+ historyText += '\n';
116
+ });
117
+ }
118
+ // Show pending critical/important issues
119
+ const pendingImportant = round.commentsGenerated.filter(c => c.status === 'pending' && (c.severity === 'critical' || c.severity === 'important'));
120
+ if (pendingImportant.length > 0) {
121
+ historyText += `\n**Still Pending (Critical/Important):**\n`;
122
+ pendingImportant.forEach(c => {
123
+ const emoji = REVIEW.SEVERITY_EMOJI[c.severity];
124
+ historyText += `- ${emoji} ${c.filePattern}: ${c.comment.split('\n')[0]}\n`;
125
+ });
126
+ }
127
+ }
128
+ historyText += `\n**Total Issues Across All Rounds:** ${session.allComments.length}\n`;
129
+ historyText += `**Files Reviewed:** ${session.filesTracked.length}\n\n`;
130
+ return historyText;
131
+ }
132
+ /**
133
+ * Extracts file patterns from a prompt containing @ references
134
+ * @param prompt The prompt to parse
135
+ * @returns Array of file patterns
136
+ */
137
+ export function extractFilesFromPrompt(prompt) {
138
+ const filePattern = /@([^\s]+)/g;
139
+ const matches = [];
140
+ let match;
141
+ while ((match = filePattern.exec(prompt)) !== null) {
142
+ matches.push(match[1]);
143
+ }
144
+ return matches;
145
+ }
146
+ //# sourceMappingURL=reviewPromptBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewPromptBuilder.js","sourceRoot":"","sources":["../../src/utils/reviewPromptBuilder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAWzC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA0B;IAC1D,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC;IAE3F,sCAAsC;IACtC,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAE1D,IAAI,MAAM,GAAG,gCAAgC,OAAO,CAAC,WAAW,GAAG,CAAC;;;gBAGtD,OAAO,CAAC,SAAS;YACrB,eAAe,CAAC,MAAM;YACtB,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iBACjC,UAAU;WAChB,KAAK,EAAE,MAAM,IAAI,aAAa,IAAI,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO;;;EAGxE,yBAAyB,CAAC,UAAU,CAAC;;;;;;;;;;;;;;CActC,CAAC;IAEA,uDAAuD;IACvD,IAAI,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,6BAA6B;IAC7B,MAAM,IAAI,+BAA+B,CAAC;IAC1C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,QAAQ,MAAM,CAAC;IAC9B,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,IAAI,CAAC;IAE5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAAkB;IAC1D,MAAM,YAAY,GAA2B;QAC3C,QAAQ,EAAE;;;;;;0CAM4B;QAEtC,WAAW,EAAE;;;;;;0CAMyB;QAEtC,OAAO,EAAE;;;;;;6BAMgB;QAEzB,YAAY,EAAE;;;;;;qCAMmB;QAEjC,OAAO,EAAE;;;;;0CAK6B;KACvC,CAAC;IAEF,OAAO,YAAY,CAAC,UAAU,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA0B;IAC7D,IAAI,WAAW,GAAG,+BAA+B,CAAC;IAElD,sCAAsC;IACtC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAEtE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,WAAW,IAAI,eAAe,KAAK,CAAC,WAAW,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,KAAK,CAAC;QACpG,WAAW,IAAI,qBAAqB,KAAK,CAAC,UAAU,IAAI,CAAC;QACzD,WAAW,IAAI,qBAAqB,KAAK,CAAC,iBAAiB,CAAC,MAAM,IAAI,CAAC;QAEvE,qCAAqC;QACrC,MAAM,gBAAgB,GAAG,KAAK,CAAC,iBAAiB,CAAC,MAAM,CACrD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAC5B,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,WAAW,IAAI,0BAA0B,CAAC;YAC1C,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;gBAC3B,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;gBACzF,WAAW,IAAI,MAAM,WAAW,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5G,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;oBACjB,WAAW,IAAI,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;gBACtC,CAAC;gBACD,WAAW,IAAI,IAAI,CAAC;YACtB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,yCAAyC;QACzC,MAAM,gBAAgB,GAAG,KAAK,CAAC,iBAAiB,CAAC,MAAM,CACrD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC,CACzF,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,WAAW,IAAI,6CAA6C,CAAC;YAC7D,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;gBAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,QAA8C,CAAC,CAAC;gBACtF,WAAW,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9E,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,WAAW,IAAI,yCAAyC,OAAO,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC;IACvF,WAAW,IAAI,uBAAuB,OAAO,CAAC,YAAY,CAAC,MAAM,MAAM,CAAC;IAExE,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,MAAM,WAAW,GAAG,YAAY,CAAC;IACjC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,KAAK,CAAC;IAEV,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { ReviewComment } from './reviewSessionCache.js';
2
+ /**
3
+ * Parses Gemini's review response into structured ReviewComment objects
4
+ * @param geminiResponse The raw response from Gemini
5
+ * @param roundNumber The current review round number
6
+ * @returns Array of parsed review comments
7
+ */
8
+ export declare function parseReviewResponse(geminiResponse: string, roundNumber: number): ReviewComment[];
9
+ /**
10
+ * Generates a unique comment ID using cryptographically secure UUID
11
+ * @returns Comment ID string
12
+ */
13
+ export declare function generateCommentId(): string;
14
+ /**
15
+ * Validates parsed comments for completeness
16
+ * @param comments Array of comments to validate
17
+ * @returns Array of valid comments
18
+ */
19
+ export declare function validateComments(comments: ReviewComment[]): ReviewComment[];
20
+ //# sourceMappingURL=reviewResponseParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewResponseParser.d.ts","sourceRoot":"","sources":["../../src/utils/reviewResponseParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,aAAa,EAAE,CA+DjB;AAiBD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAqDD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAe3E"}
@@ -0,0 +1,149 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { Logger } from './logger.js';
3
+ /**
4
+ * Parses Gemini's review response into structured ReviewComment objects
5
+ * @param geminiResponse The raw response from Gemini
6
+ * @param roundNumber The current review round number
7
+ * @returns Array of parsed review comments
8
+ */
9
+ export function parseReviewResponse(geminiResponse, roundNumber) {
10
+ const comments = [];
11
+ try {
12
+ // Pattern to match review comments with more flexible formatting
13
+ // Handles variations in whitespace, asterisk count, and casing that LLMs might produce
14
+ // More robust: \*{2,3} allows 2-3 asterisks, \s+ for flexible spacing, case-insensitive matching
15
+ const commentPattern = /\*{2,3}\s*\[\s*SEVERITY\s*:\s*(critical|important|suggestion|question)\s*\]\s*\*{2,3}\s+\*{2,3}\s*File\s*:\s*\*{2,3}\s*([^\n]+?)\s+\*{2,3}\s*Lines\s*:\s*\*{2,3}\s*([^\n]+?)\s+\*{2,3}\s*Issue\s*:\s*\*{2,3}\s*([^\n]+?)\s+\*{2,3}\s*Details\s*:\s*\*{2,3}\s*([\s\S]+?)\s+\*{2,3}\s*Recommendation\s*:\s*\*{2,3}\s*([\s\S]+?)(?=\n\s*\*{2,3}\s*\[\s*SEVERITY|---|$)/gi;
16
+ let match;
17
+ let matchCount = 0;
18
+ while ((match = commentPattern.exec(geminiResponse)) !== null) {
19
+ matchCount++;
20
+ const [_, severity, file, lines, issue, details, recommendation] = match;
21
+ // Parse line range
22
+ let lineRange;
23
+ const linesStr = lines.trim();
24
+ if (linesStr !== 'N/A' && linesStr.toLowerCase() !== 'n/a') {
25
+ const lineMatch = linesStr.match(/(\d+)-(\d+)/);
26
+ if (lineMatch) {
27
+ lineRange = {
28
+ start: parseInt(lineMatch[1], 10),
29
+ end: parseInt(lineMatch[2], 10)
30
+ };
31
+ }
32
+ else {
33
+ // Single line number
34
+ const singleLine = parseInt(linesStr, 10);
35
+ if (!isNaN(singleLine)) {
36
+ lineRange = { start: singleLine, end: singleLine };
37
+ }
38
+ }
39
+ }
40
+ const comment = {
41
+ id: generateCommentId(),
42
+ filePattern: file.trim(),
43
+ lineRange,
44
+ severity: severity.trim().toLowerCase(),
45
+ comment: formatCommentText(issue.trim(), details.trim(), recommendation.trim()),
46
+ roundGenerated: roundNumber,
47
+ status: 'pending'
48
+ };
49
+ comments.push(comment);
50
+ }
51
+ Logger.debug(`Parsed ${matchCount} review comments from Gemini response`);
52
+ // If no structured comments found, try fallback parsing
53
+ if (comments.length === 0) {
54
+ Logger.debug('No structured comments found, attempting fallback parsing');
55
+ const fallbackComments = fallbackParse(geminiResponse, roundNumber);
56
+ comments.push(...fallbackComments);
57
+ }
58
+ }
59
+ catch (error) {
60
+ Logger.error(`Error parsing review response: ${error}`);
61
+ // Return empty array on parse error - caller can handle
62
+ }
63
+ return comments;
64
+ }
65
+ /**
66
+ * Formats the comment text from parsed components
67
+ * @param issue Brief issue title
68
+ * @param details Detailed explanation
69
+ * @param recommendation Suggested fix
70
+ * @returns Formatted comment string
71
+ */
72
+ function formatCommentText(issue, details, recommendation) {
73
+ return `${issue}
74
+
75
+ ${details}
76
+
77
+ **Recommendation:** ${recommendation}`;
78
+ }
79
+ /**
80
+ * Generates a unique comment ID using cryptographically secure UUID
81
+ * @returns Comment ID string
82
+ */
83
+ export function generateCommentId() {
84
+ return `cmt-${randomUUID()}`;
85
+ }
86
+ /**
87
+ * Fallback parser for when structured format isn't followed
88
+ * Attempts to extract any review-like content
89
+ * @param geminiResponse The raw response
90
+ * @param roundNumber The round number
91
+ * @returns Array of comments (may be empty or contain unstructured feedback)
92
+ */
93
+ function fallbackParse(geminiResponse, roundNumber) {
94
+ const comments = [];
95
+ // Look for common issue indicators
96
+ const issuePatterns = [
97
+ /(?:issue|problem|concern|warning|error):\s*(.+?)(?:\n\n|$)/gi,
98
+ /(?:critical|important|security|vulnerability):\s*(.+?)(?:\n\n|$)/gi,
99
+ /(?:recommendation|suggestion|fix):\s*(.+?)(?:\n\n|$)/gi,
100
+ ];
101
+ let foundAny = false;
102
+ for (const pattern of issuePatterns) {
103
+ let match;
104
+ while ((match = pattern.exec(geminiResponse)) !== null) {
105
+ foundAny = true;
106
+ const comment = {
107
+ id: generateCommentId(),
108
+ filePattern: 'Unknown',
109
+ severity: 'suggestion',
110
+ comment: match[1].trim(),
111
+ roundGenerated: roundNumber,
112
+ status: 'pending'
113
+ };
114
+ comments.push(comment);
115
+ }
116
+ }
117
+ // If still nothing found and response has substantial content, create a general comment
118
+ if (!foundAny && geminiResponse.trim().length > 50) {
119
+ Logger.debug('Creating general unstructured comment from response');
120
+ comments.push({
121
+ id: generateCommentId(),
122
+ filePattern: 'General',
123
+ severity: 'question',
124
+ comment: geminiResponse.trim(),
125
+ roundGenerated: roundNumber,
126
+ status: 'pending'
127
+ });
128
+ }
129
+ return comments;
130
+ }
131
+ /**
132
+ * Validates parsed comments for completeness
133
+ * @param comments Array of comments to validate
134
+ * @returns Array of valid comments
135
+ */
136
+ export function validateComments(comments) {
137
+ return comments.filter(comment => {
138
+ const isValid = comment.id &&
139
+ comment.filePattern &&
140
+ comment.severity &&
141
+ comment.comment &&
142
+ comment.comment.trim().length > 0;
143
+ if (!isValid) {
144
+ Logger.debug(`Filtered out invalid comment: ${JSON.stringify(comment)}`);
145
+ }
146
+ return isValid;
147
+ });
148
+ }
149
+ //# sourceMappingURL=reviewResponseParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewResponseParser.js","sourceRoot":"","sources":["../../src/utils/reviewResponseParser.ts"],"names":[],"mappings":"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"}