@maxanatsko/llm-cli-bridge 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +203 -0
- package/dist/backends/codex.d.ts +37 -0
- package/dist/backends/codex.d.ts.map +1 -0
- package/dist/backends/codex.js +438 -0
- package/dist/backends/codex.js.map +1 -0
- package/dist/backends/gemini.d.ts +17 -0
- package/dist/backends/gemini.d.ts.map +1 -0
- package/dist/backends/gemini.js +174 -0
- package/dist/backends/gemini.js.map +1 -0
- package/dist/backends/index.d.ts +8 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +9 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/registry.d.ts +33 -0
- package/dist/backends/registry.d.ts.map +1 -0
- package/dist/backends/registry.js +80 -0
- package/dist/backends/registry.js.map +1 -0
- package/dist/backends/types.d.ts +61 -0
- package/dist/backends/types.d.ts.map +1 -0
- package/dist/backends/types.js +5 -0
- package/dist/backends/types.js.map +1 -0
- package/dist/constants.d.ts +223 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +228 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +192 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/ask.tool.d.ts +4 -0
- package/dist/tools/ask.tool.d.ts.map +1 -0
- package/dist/tools/ask.tool.js +113 -0
- package/dist/tools/ask.tool.js.map +1 -0
- package/dist/tools/brainstorm.tool.d.ts +3 -0
- package/dist/tools/brainstorm.tool.d.ts.map +1 -0
- package/dist/tools/brainstorm.tool.js +250 -0
- package/dist/tools/brainstorm.tool.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +42 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +85 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/review-code.tool.d.ts +3 -0
- package/dist/tools/review-code.tool.d.ts.map +1 -0
- package/dist/tools/review-code.tool.js +279 -0
- package/dist/tools/review-code.tool.js.map +1 -0
- package/dist/tools/test-tool.example.d.ts +13 -0
- package/dist/tools/test-tool.example.d.ts.map +1 -0
- package/dist/tools/test-tool.example.js +32 -0
- package/dist/tools/test-tool.example.js.map +1 -0
- package/dist/tools/timeout-test.tool.d.ts +3 -0
- package/dist/tools/timeout-test.tool.d.ts.map +1 -0
- package/dist/tools/timeout-test.tool.js +38 -0
- package/dist/tools/timeout-test.tool.js.map +1 -0
- package/dist/utils/askSessionManager.d.ts +59 -0
- package/dist/utils/askSessionManager.d.ts.map +1 -0
- package/dist/utils/askSessionManager.js +123 -0
- package/dist/utils/askSessionManager.js.map +1 -0
- package/dist/utils/brainstormSessionManager.d.ts +67 -0
- package/dist/utils/brainstormSessionManager.d.ts.map +1 -0
- package/dist/utils/brainstormSessionManager.js +174 -0
- package/dist/utils/brainstormSessionManager.js.map +1 -0
- package/dist/utils/changeModeInstructions.d.ts +17 -0
- package/dist/utils/changeModeInstructions.d.ts.map +1 -0
- package/dist/utils/changeModeInstructions.js +100 -0
- package/dist/utils/changeModeInstructions.js.map +1 -0
- package/dist/utils/changeModeParser.d.ts +15 -0
- package/dist/utils/changeModeParser.d.ts.map +1 -0
- package/dist/utils/changeModeParser.js +81 -0
- package/dist/utils/changeModeParser.js.map +1 -0
- package/dist/utils/changeModeTranslator.d.ts +4 -0
- package/dist/utils/changeModeTranslator.d.ts.map +1 -0
- package/dist/utils/changeModeTranslator.js +42 -0
- package/dist/utils/changeModeTranslator.js.map +1 -0
- package/dist/utils/commandExecutor.d.ts +2 -0
- package/dist/utils/commandExecutor.d.ts.map +1 -0
- package/dist/utils/commandExecutor.js +76 -0
- package/dist/utils/commandExecutor.js.map +1 -0
- package/dist/utils/envAllowlist.d.ts +17 -0
- package/dist/utils/envAllowlist.d.ts.map +1 -0
- package/dist/utils/envAllowlist.js +54 -0
- package/dist/utils/envAllowlist.js.map +1 -0
- package/dist/utils/geminiExecutor.d.ts +3 -0
- package/dist/utils/geminiExecutor.d.ts.map +1 -0
- package/dist/utils/geminiExecutor.js +94 -0
- package/dist/utils/geminiExecutor.js.map +1 -0
- package/dist/utils/gitStateDetector.d.ts +32 -0
- package/dist/utils/gitStateDetector.d.ts.map +1 -0
- package/dist/utils/gitStateDetector.js +68 -0
- package/dist/utils/gitStateDetector.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +42 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/reviewFormatter.d.ts +35 -0
- package/dist/utils/reviewFormatter.d.ts.map +1 -0
- package/dist/utils/reviewFormatter.js +201 -0
- package/dist/utils/reviewFormatter.js.map +1 -0
- package/dist/utils/reviewPromptBuilder.d.ts +43 -0
- package/dist/utils/reviewPromptBuilder.d.ts.map +1 -0
- package/dist/utils/reviewPromptBuilder.js +170 -0
- package/dist/utils/reviewPromptBuilder.js.map +1 -0
- package/dist/utils/reviewResponseParser.d.ts +20 -0
- package/dist/utils/reviewResponseParser.d.ts.map +1 -0
- package/dist/utils/reviewResponseParser.js +149 -0
- package/dist/utils/reviewResponseParser.js.map +1 -0
- package/dist/utils/reviewSessionCache.d.ts +81 -0
- package/dist/utils/reviewSessionCache.d.ts.map +1 -0
- package/dist/utils/reviewSessionCache.js +220 -0
- package/dist/utils/reviewSessionCache.js.map +1 -0
- package/dist/utils/reviewSessionManager.d.ts +52 -0
- package/dist/utils/reviewSessionManager.d.ts.map +1 -0
- package/dist/utils/reviewSessionManager.js +65 -0
- package/dist/utils/reviewSessionManager.js.map +1 -0
- package/dist/utils/sessionManager.d.ts +95 -0
- package/dist/utils/sessionManager.d.ts.map +1 -0
- package/dist/utils/sessionManager.js +382 -0
- package/dist/utils/sessionManager.js.map +1 -0
- package/dist/utils/sessionSchemas.d.ts +140 -0
- package/dist/utils/sessionSchemas.d.ts.map +1 -0
- package/dist/utils/sessionSchemas.js +2 -0
- package/dist/utils/sessionSchemas.js.map +1 -0
- package/dist/utils/timeoutManager.d.ts +2 -0
- package/dist/utils/timeoutManager.d.ts.map +1 -0
- package/dist/utils/timeoutManager.js +2 -0
- package/dist/utils/timeoutManager.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewPromptBuilder.d.ts","sourceRoot":"","sources":["../../src/utils/reviewPromptBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,IAAI,iBAAiB,EAAe,MAAM,qBAAqB,CAAC;AACnG,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,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,QAAQ,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAiDpE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBhE;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,170 @@
|
|
|
1
|
+
import { REVIEW } from '../constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds a context-aware review prompt for the AI backend
|
|
4
|
+
* @param config Review prompt configuration
|
|
5
|
+
* @returns Formatted prompt string
|
|
6
|
+
*/
|
|
7
|
+
export function buildReviewPrompt(config) {
|
|
8
|
+
const { userPrompt, session, files, reviewType, severity, 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
|
+
- Severity Scope: ${severity}
|
|
19
|
+
- Files: ${files?.length || 'all tracked'} ${files ? 'specified' : 'files'}
|
|
20
|
+
|
|
21
|
+
## Review Instructions
|
|
22
|
+
${getReviewTypeInstructions(reviewType)}
|
|
23
|
+
|
|
24
|
+
## Severity Filter
|
|
25
|
+
${getSeverityInstructions(severity)}
|
|
26
|
+
|
|
27
|
+
## Output Format
|
|
28
|
+
For each issue found, use this EXACT format:
|
|
29
|
+
|
|
30
|
+
**[SEVERITY: critical|important|suggestion|question]**
|
|
31
|
+
**File:** {filename}
|
|
32
|
+
**Lines:** {start}-{end} (if applicable, otherwise write "N/A")
|
|
33
|
+
**Issue:** {brief title}
|
|
34
|
+
**Details:** {explanation}
|
|
35
|
+
**Recommendation:** {suggested fix or action}
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
`;
|
|
40
|
+
// Include conversation history if requested and exists
|
|
41
|
+
if (includeHistory && session.rounds.length > 0) {
|
|
42
|
+
prompt += formatPreviousRounds(session);
|
|
43
|
+
}
|
|
44
|
+
// Add user's current request
|
|
45
|
+
prompt += `\n## Current Review Request\n`;
|
|
46
|
+
if (fileRefs) {
|
|
47
|
+
prompt += `${fileRefs}\n\n`;
|
|
48
|
+
}
|
|
49
|
+
prompt += `${userPrompt}\n`;
|
|
50
|
+
return prompt;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns severity-specific instructions so the model does not waste time
|
|
54
|
+
* generating feedback that will be discarded after parsing.
|
|
55
|
+
* @param severity The requested severity scope
|
|
56
|
+
* @returns Formatted instructions string
|
|
57
|
+
*/
|
|
58
|
+
export function getSeverityInstructions(severity) {
|
|
59
|
+
const instructions = {
|
|
60
|
+
'critical-only': `Only report **critical** issues.
|
|
61
|
+
- Do not include important, suggestion, or question items.
|
|
62
|
+
- If no critical issues exist, respond with: "No critical issues found."`,
|
|
63
|
+
'important-and-above': `Only report **critical** and **important** issues.
|
|
64
|
+
- Do not include suggestion or question items.
|
|
65
|
+
- If no critical or important issues exist, respond with: "No critical or important issues found."`,
|
|
66
|
+
all: `Report actionable issues across all supported severities.
|
|
67
|
+
- Prioritize critical and important issues first.
|
|
68
|
+
- Avoid low-value nitpicks.`
|
|
69
|
+
};
|
|
70
|
+
return instructions[severity] || instructions.all;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns review instructions based on review type
|
|
74
|
+
* @param reviewType The type of review to perform
|
|
75
|
+
* @returns Formatted instructions string
|
|
76
|
+
*/
|
|
77
|
+
export function getReviewTypeInstructions(reviewType) {
|
|
78
|
+
const instructions = {
|
|
79
|
+
security: `Focus on:
|
|
80
|
+
- Input validation and sanitization
|
|
81
|
+
- Authentication and authorization flaws
|
|
82
|
+
- SQL injection, XSS, CSRF vulnerabilities
|
|
83
|
+
- Secrets exposure (hardcoded credentials, API keys)
|
|
84
|
+
- Dependency vulnerabilities
|
|
85
|
+
- Insecure cryptography and data handling`,
|
|
86
|
+
performance: `Focus on:
|
|
87
|
+
- Algorithm complexity (O(n) analysis)
|
|
88
|
+
- Unnecessary loops or computations
|
|
89
|
+
- Memory leaks and inefficient data structures
|
|
90
|
+
- Database query optimization (N+1 queries, missing indexes)
|
|
91
|
+
- Caching opportunities
|
|
92
|
+
- Resource cleanup and connection pooling`,
|
|
93
|
+
quality: `Focus on:
|
|
94
|
+
- Code clarity and readability
|
|
95
|
+
- Naming conventions and consistency
|
|
96
|
+
- DRY violations (repeated code)
|
|
97
|
+
- Error handling and edge cases
|
|
98
|
+
- Test coverage gaps
|
|
99
|
+
- Documentation completeness`,
|
|
100
|
+
architecture: `Focus on:
|
|
101
|
+
- Design patterns and principles (SOLID, DRY, KISS)
|
|
102
|
+
- Module coupling and cohesion
|
|
103
|
+
- Scalability concerns
|
|
104
|
+
- API design and contracts
|
|
105
|
+
- Separation of concerns
|
|
106
|
+
- Technical debt and maintainability`,
|
|
107
|
+
general: `Perform a comprehensive review covering:
|
|
108
|
+
- Security vulnerabilities
|
|
109
|
+
- Performance bottlenecks
|
|
110
|
+
- Code quality issues
|
|
111
|
+
- Architectural concerns
|
|
112
|
+
Prioritize critical and important issues.`
|
|
113
|
+
};
|
|
114
|
+
return instructions[reviewType] || instructions.general;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Formats previous review rounds for context inclusion
|
|
118
|
+
* @param session The current review session
|
|
119
|
+
* @returns Formatted history string
|
|
120
|
+
*/
|
|
121
|
+
export function formatPreviousRounds(session) {
|
|
122
|
+
let historyText = `\n## Previous Review Rounds\n`;
|
|
123
|
+
// Get last N rounds based on constant
|
|
124
|
+
const recentRounds = session.rounds.slice(-REVIEW.MAX_HISTORY_ROUNDS);
|
|
125
|
+
for (const round of recentRounds) {
|
|
126
|
+
historyText += `\n### Round ${round.roundNumber} (${new Date(round.timestamp).toLocaleString()})\n`;
|
|
127
|
+
historyText += `**User Request:** ${round.userPrompt}\n`;
|
|
128
|
+
historyText += `**Issues Found:** ${round.commentsGenerated.length}\n`;
|
|
129
|
+
// Include resolved/modified comments
|
|
130
|
+
const resolvedComments = round.commentsGenerated.filter(c => c.status !== 'pending');
|
|
131
|
+
if (resolvedComments.length > 0) {
|
|
132
|
+
historyText += `\n**Resolved Issues:**\n`;
|
|
133
|
+
resolvedComments.forEach(c => {
|
|
134
|
+
const statusEmoji = c.status === 'accepted' ? '✅' : c.status === 'rejected' ? '❌' : '📝';
|
|
135
|
+
historyText += `- [${statusEmoji} ${c.status.toUpperCase()}] ${c.filePattern}: ${c.comment.split('\n')[0]}`;
|
|
136
|
+
if (c.resolution) {
|
|
137
|
+
historyText += ` - ${c.resolution}`;
|
|
138
|
+
}
|
|
139
|
+
historyText += '\n';
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Show pending critical/important issues
|
|
143
|
+
const pendingImportant = round.commentsGenerated.filter(c => c.status === 'pending' && (c.severity === 'critical' || c.severity === 'important'));
|
|
144
|
+
if (pendingImportant.length > 0) {
|
|
145
|
+
historyText += `\n**Still Pending (Critical/Important):**\n`;
|
|
146
|
+
pendingImportant.forEach(c => {
|
|
147
|
+
const emoji = REVIEW.SEVERITY_EMOJI[c.severity];
|
|
148
|
+
historyText += `- ${emoji} ${c.filePattern}: ${c.comment.split('\n')[0]}\n`;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
historyText += `\n**Total Issues Across All Rounds:** ${session.allComments.length}\n`;
|
|
153
|
+
historyText += `**Files Reviewed:** ${session.filesTracked.length}\n\n`;
|
|
154
|
+
return historyText;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Extracts file patterns from a prompt containing @ references
|
|
158
|
+
* @param prompt The prompt to parse
|
|
159
|
+
* @returns Array of file patterns
|
|
160
|
+
*/
|
|
161
|
+
export function extractFilesFromPrompt(prompt) {
|
|
162
|
+
const filePattern = /@([^\s]+)/g;
|
|
163
|
+
const matches = [];
|
|
164
|
+
let match;
|
|
165
|
+
while ((match = filePattern.exec(prompt)) !== null) {
|
|
166
|
+
matches.push(match[1]);
|
|
167
|
+
}
|
|
168
|
+
return matches;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=reviewPromptBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewPromptBuilder.js","sourceRoot":"","sources":["../../src/utils/reviewPromptBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReviewComment } from './sessionSchemas.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses review response into structured ReviewComment objects
|
|
4
|
+
* @param responseText The raw response from the AI backend
|
|
5
|
+
* @param roundNumber The current review round number
|
|
6
|
+
* @returns Array of parsed review comments
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseReviewResponse(responseText: 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,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,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 review response into structured ReviewComment objects
|
|
5
|
+
* @param responseText The raw response from the AI backend
|
|
6
|
+
* @param roundNumber The current review round number
|
|
7
|
+
* @returns Array of parsed review comments
|
|
8
|
+
*/
|
|
9
|
+
export function parseReviewResponse(responseText, 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(responseText)) !== 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 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(responseText, 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 responseText 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(responseText, 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(responseText)) !== 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 && responseText.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: responseText.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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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated This file is deprecated. Session management has been migrated to the shared infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* - For session operations, use: src/utils/reviewSessionManager.ts
|
|
5
|
+
* - For type definitions, use: src/utils/sessionSchemas.ts
|
|
6
|
+
*
|
|
7
|
+
* This file is kept only for backward compatibility and type exports (ReviewComment, ReviewRound).
|
|
8
|
+
* The actual session cache functions (save/load/create) have been moved to reviewSessionManager.ts
|
|
9
|
+
*/
|
|
10
|
+
import { GitState } from './gitStateDetector.js';
|
|
11
|
+
export interface ReviewComment {
|
|
12
|
+
id: string;
|
|
13
|
+
filePattern: string;
|
|
14
|
+
lineRange?: {
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
};
|
|
18
|
+
severity: 'critical' | 'important' | 'suggestion' | 'question';
|
|
19
|
+
comment: string;
|
|
20
|
+
roundGenerated: number;
|
|
21
|
+
status: 'pending' | 'accepted' | 'rejected' | 'modified' | 'deferred';
|
|
22
|
+
resolution?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ReviewRound {
|
|
25
|
+
roundNumber: number;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
filesReviewed: string[];
|
|
28
|
+
userPrompt: string;
|
|
29
|
+
response: string;
|
|
30
|
+
commentsGenerated: ReviewComment[];
|
|
31
|
+
gitState: GitState;
|
|
32
|
+
}
|
|
33
|
+
export interface CodeReviewSession {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
createdAt: number;
|
|
36
|
+
lastAccessedAt: number;
|
|
37
|
+
gitState: GitState;
|
|
38
|
+
currentGitState: GitState;
|
|
39
|
+
rounds: ReviewRound[];
|
|
40
|
+
allComments: ReviewComment[];
|
|
41
|
+
filesTracked: string[];
|
|
42
|
+
focusFiles?: string[];
|
|
43
|
+
reviewScope?: 'full' | 'changes-only' | 'focused';
|
|
44
|
+
totalRounds: number;
|
|
45
|
+
sessionState: 'active' | 'paused' | 'completed';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Saves a review session to the cache
|
|
49
|
+
* @param session The session to save
|
|
50
|
+
*/
|
|
51
|
+
export declare function saveReviewSession(session: CodeReviewSession): void;
|
|
52
|
+
/**
|
|
53
|
+
* Loads a review session from the cache
|
|
54
|
+
* @param sessionId The session ID to load
|
|
55
|
+
* @returns The session or null if not found/expired
|
|
56
|
+
*/
|
|
57
|
+
export declare function loadReviewSession(sessionId: string): CodeReviewSession | null;
|
|
58
|
+
/**
|
|
59
|
+
* Lists all active review sessions
|
|
60
|
+
* @returns Array of active sessions
|
|
61
|
+
*/
|
|
62
|
+
export declare function listActiveSessions(): CodeReviewSession[];
|
|
63
|
+
/**
|
|
64
|
+
* Creates a new review session
|
|
65
|
+
* @param sessionId The session ID
|
|
66
|
+
* @param gitState The initial git state
|
|
67
|
+
* @param focusFiles Optional files to focus on
|
|
68
|
+
* @returns New CodeReviewSession object
|
|
69
|
+
*/
|
|
70
|
+
export declare function createNewSession(sessionId: string, gitState: GitState, focusFiles?: string[]): CodeReviewSession;
|
|
71
|
+
/**
|
|
72
|
+
* Gets cache statistics
|
|
73
|
+
* @returns Cache stats object
|
|
74
|
+
*/
|
|
75
|
+
export declare function getReviewCacheStats(): {
|
|
76
|
+
size: number;
|
|
77
|
+
ttl: number;
|
|
78
|
+
maxSize: number;
|
|
79
|
+
cacheDir: string;
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=reviewSessionCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewSessionCache.d.ts","sourceRoot":"","sources":["../../src/utils/reviewSessionCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,QAAQ,EAAE,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,CAAC;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,aAAa,EAAE,CAAC;IACnC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,QAAQ,CAAC;IAC1B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;CACjD;AAuBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAqBlE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CA6B7E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,iBAAiB,EAAE,CA6BxD;AAiED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,iBAAiB,CAgBnB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAeA"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated This file is deprecated. Session management has been migrated to the shared infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* - For session operations, use: src/utils/reviewSessionManager.ts
|
|
5
|
+
* - For type definitions, use: src/utils/sessionSchemas.ts
|
|
6
|
+
*
|
|
7
|
+
* This file is kept only for backward compatibility and type exports (ReviewComment, ReviewRound).
|
|
8
|
+
* The actual session cache functions (save/load/create) have been moved to reviewSessionManager.ts
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import * as os from 'os';
|
|
13
|
+
import { Logger } from './logger.js';
|
|
14
|
+
// Use persistent storage in user's home directory instead of tmp for session persistence across reboots
|
|
15
|
+
const REVIEW_CACHE_DIR = path.join(os.homedir(), '.gemini-mcp', 'review-sessions');
|
|
16
|
+
const REVIEW_SESSION_TTL = 24 * 60 * 60 * 1000; // 24 hours (increased from 60 min for better persistence)
|
|
17
|
+
const MAX_REVIEW_SESSIONS = 20;
|
|
18
|
+
/**
|
|
19
|
+
* Ensures the review cache directory exists
|
|
20
|
+
*/
|
|
21
|
+
function ensureCacheDir() {
|
|
22
|
+
if (!fs.existsSync(REVIEW_CACHE_DIR)) {
|
|
23
|
+
fs.mkdirSync(REVIEW_CACHE_DIR, { recursive: true });
|
|
24
|
+
Logger.debug(`Created review cache directory: ${REVIEW_CACHE_DIR}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Saves a review session to the cache
|
|
29
|
+
* @param session The session to save
|
|
30
|
+
*/
|
|
31
|
+
export function saveReviewSession(session) {
|
|
32
|
+
ensureCacheDir();
|
|
33
|
+
cleanExpiredSessions();
|
|
34
|
+
const filePath = path.join(REVIEW_CACHE_DIR, `${session.sessionId}.json`);
|
|
35
|
+
const cacheEntry = {
|
|
36
|
+
session,
|
|
37
|
+
timestamp: Date.now(),
|
|
38
|
+
expiryTime: Date.now() + REVIEW_SESSION_TTL
|
|
39
|
+
};
|
|
40
|
+
try {
|
|
41
|
+
fs.writeFileSync(filePath, JSON.stringify(cacheEntry, null, 2));
|
|
42
|
+
Logger.debug(`Saved review session: ${session.sessionId} (${session.totalRounds} rounds)`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
Logger.error(`Failed to save review session: ${error}`);
|
|
46
|
+
throw new Error(`Failed to save review session: ${error}`);
|
|
47
|
+
}
|
|
48
|
+
enforceSessionLimits();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Loads a review session from the cache
|
|
52
|
+
* @param sessionId The session ID to load
|
|
53
|
+
* @returns The session or null if not found/expired
|
|
54
|
+
*/
|
|
55
|
+
export function loadReviewSession(sessionId) {
|
|
56
|
+
const filePath = path.join(REVIEW_CACHE_DIR, `${sessionId}.json`);
|
|
57
|
+
try {
|
|
58
|
+
if (!fs.existsSync(filePath)) {
|
|
59
|
+
Logger.debug(`Session not found: ${sessionId}`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
63
|
+
const cacheEntry = JSON.parse(fileContent);
|
|
64
|
+
// Check expiry
|
|
65
|
+
if (Date.now() > cacheEntry.expiryTime) {
|
|
66
|
+
fs.unlinkSync(filePath);
|
|
67
|
+
Logger.debug(`Session expired and deleted: ${sessionId}`);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
Logger.debug(`Loaded review session: ${sessionId} (${cacheEntry.session.totalRounds} rounds)`);
|
|
71
|
+
return cacheEntry.session;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
Logger.error(`Failed to load review session ${sessionId}: ${error}`);
|
|
75
|
+
// Clean up corrupted file
|
|
76
|
+
try {
|
|
77
|
+
fs.unlinkSync(filePath);
|
|
78
|
+
}
|
|
79
|
+
catch { }
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Lists all active review sessions
|
|
85
|
+
* @returns Array of active sessions
|
|
86
|
+
*/
|
|
87
|
+
export function listActiveSessions() {
|
|
88
|
+
ensureCacheDir();
|
|
89
|
+
const sessions = [];
|
|
90
|
+
try {
|
|
91
|
+
const files = fs.readdirSync(REVIEW_CACHE_DIR);
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
if (!file.endsWith('.json'))
|
|
95
|
+
continue;
|
|
96
|
+
const filePath = path.join(REVIEW_CACHE_DIR, file);
|
|
97
|
+
try {
|
|
98
|
+
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
99
|
+
const cacheEntry = JSON.parse(fileContent);
|
|
100
|
+
// Skip expired sessions
|
|
101
|
+
if (now <= cacheEntry.expiryTime) {
|
|
102
|
+
sessions.push(cacheEntry.session);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
Logger.debug(`Error reading session file ${file}: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
Logger.error(`Failed to list active sessions: ${error}`);
|
|
112
|
+
}
|
|
113
|
+
return sessions;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Cleans up expired session files
|
|
117
|
+
*/
|
|
118
|
+
function cleanExpiredSessions() {
|
|
119
|
+
try {
|
|
120
|
+
ensureCacheDir();
|
|
121
|
+
const files = fs.readdirSync(REVIEW_CACHE_DIR);
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
let cleaned = 0;
|
|
124
|
+
for (const file of files) {
|
|
125
|
+
if (!file.endsWith('.json'))
|
|
126
|
+
continue;
|
|
127
|
+
const filePath = path.join(REVIEW_CACHE_DIR, file);
|
|
128
|
+
try {
|
|
129
|
+
const stats = fs.statSync(filePath);
|
|
130
|
+
if (now - stats.mtimeMs > REVIEW_SESSION_TTL) {
|
|
131
|
+
fs.unlinkSync(filePath);
|
|
132
|
+
cleaned++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
Logger.debug(`Error checking session file ${file}: ${error}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (cleaned > 0) {
|
|
140
|
+
Logger.debug(`Cleaned ${cleaned} expired review sessions`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
Logger.debug(`Session cleanup error: ${error}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Enforces the maximum session limit using FIFO
|
|
149
|
+
*/
|
|
150
|
+
function enforceSessionLimits() {
|
|
151
|
+
try {
|
|
152
|
+
const files = fs
|
|
153
|
+
.readdirSync(REVIEW_CACHE_DIR)
|
|
154
|
+
.filter(f => f.endsWith('.json'))
|
|
155
|
+
.map(f => ({
|
|
156
|
+
name: f,
|
|
157
|
+
path: path.join(REVIEW_CACHE_DIR, f),
|
|
158
|
+
mtime: fs.statSync(path.join(REVIEW_CACHE_DIR, f)).mtimeMs
|
|
159
|
+
}))
|
|
160
|
+
.sort((a, b) => a.mtime - b.mtime); // Oldest first
|
|
161
|
+
// Remove oldest files if over limit
|
|
162
|
+
if (files.length > MAX_REVIEW_SESSIONS) {
|
|
163
|
+
const toRemove = files.slice(0, files.length - MAX_REVIEW_SESSIONS);
|
|
164
|
+
for (const file of toRemove) {
|
|
165
|
+
try {
|
|
166
|
+
fs.unlinkSync(file.path);
|
|
167
|
+
}
|
|
168
|
+
catch { }
|
|
169
|
+
}
|
|
170
|
+
Logger.debug(`Removed ${toRemove.length} old review sessions to enforce limit`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
Logger.debug(`Error enforcing session limits: ${error}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Creates a new review session
|
|
179
|
+
* @param sessionId The session ID
|
|
180
|
+
* @param gitState The initial git state
|
|
181
|
+
* @param focusFiles Optional files to focus on
|
|
182
|
+
* @returns New CodeReviewSession object
|
|
183
|
+
*/
|
|
184
|
+
export function createNewSession(sessionId, gitState, focusFiles) {
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
return {
|
|
187
|
+
sessionId,
|
|
188
|
+
createdAt: now,
|
|
189
|
+
lastAccessedAt: now,
|
|
190
|
+
gitState,
|
|
191
|
+
currentGitState: gitState,
|
|
192
|
+
rounds: [],
|
|
193
|
+
allComments: [],
|
|
194
|
+
filesTracked: [],
|
|
195
|
+
focusFiles,
|
|
196
|
+
reviewScope: focusFiles ? 'focused' : 'full',
|
|
197
|
+
totalRounds: 0,
|
|
198
|
+
sessionState: 'active'
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Gets cache statistics
|
|
203
|
+
* @returns Cache stats object
|
|
204
|
+
*/
|
|
205
|
+
export function getReviewCacheStats() {
|
|
206
|
+
ensureCacheDir();
|
|
207
|
+
let size = 0;
|
|
208
|
+
try {
|
|
209
|
+
const files = fs.readdirSync(REVIEW_CACHE_DIR);
|
|
210
|
+
size = files.filter(f => f.endsWith('.json')).length;
|
|
211
|
+
}
|
|
212
|
+
catch { }
|
|
213
|
+
return {
|
|
214
|
+
size,
|
|
215
|
+
ttl: REVIEW_SESSION_TTL,
|
|
216
|
+
maxSize: MAX_REVIEW_SESSIONS,
|
|
217
|
+
cacheDir: REVIEW_CACHE_DIR
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=reviewSessionCache.js.map
|