better-gemini-mcp 1.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.

Potentially problematic release.


This version of better-gemini-mcp might be problematic. Click here for more details.

Files changed (88) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/LICENSE.md +13 -0
  3. package/README.md +291 -0
  4. package/dist/constants.d.ts +148 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/constants.js +295 -0
  7. package/dist/constants.js.map +1 -0
  8. package/dist/index.d.ts +11 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +280 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/setup/index.d.ts +7 -0
  13. package/dist/setup/index.d.ts.map +1 -0
  14. package/dist/setup/index.js +6 -0
  15. package/dist/setup/index.js.map +1 -0
  16. package/dist/setup/wizard.d.ts +39 -0
  17. package/dist/setup/wizard.d.ts.map +1 -0
  18. package/dist/setup/wizard.js +222 -0
  19. package/dist/setup/wizard.js.map +1 -0
  20. package/dist/tools/analyze-directory.tool.d.ts +8 -0
  21. package/dist/tools/analyze-directory.tool.d.ts.map +1 -0
  22. package/dist/tools/analyze-directory.tool.js +195 -0
  23. package/dist/tools/analyze-directory.tool.js.map +1 -0
  24. package/dist/tools/deep-research.tool.d.ts +8 -0
  25. package/dist/tools/deep-research.tool.d.ts.map +1 -0
  26. package/dist/tools/deep-research.tool.js +153 -0
  27. package/dist/tools/deep-research.tool.js.map +1 -0
  28. package/dist/tools/fetch-chunk.tool.d.ts +8 -0
  29. package/dist/tools/fetch-chunk.tool.d.ts.map +1 -0
  30. package/dist/tools/fetch-chunk.tool.js +123 -0
  31. package/dist/tools/fetch-chunk.tool.js.map +1 -0
  32. package/dist/tools/health-check.tool.d.ts +8 -0
  33. package/dist/tools/health-check.tool.d.ts.map +1 -0
  34. package/dist/tools/health-check.tool.js +113 -0
  35. package/dist/tools/health-check.tool.js.map +1 -0
  36. package/dist/tools/index.d.ts +16 -0
  37. package/dist/tools/index.d.ts.map +1 -0
  38. package/dist/tools/index.js +35 -0
  39. package/dist/tools/index.js.map +1 -0
  40. package/dist/tools/quick-query.tool.d.ts +8 -0
  41. package/dist/tools/quick-query.tool.d.ts.map +1 -0
  42. package/dist/tools/quick-query.tool.js +154 -0
  43. package/dist/tools/quick-query.tool.js.map +1 -0
  44. package/dist/tools/registry.d.ts +52 -0
  45. package/dist/tools/registry.d.ts.map +1 -0
  46. package/dist/tools/registry.js +95 -0
  47. package/dist/tools/registry.js.map +1 -0
  48. package/dist/tools/validate-paths.tool.d.ts +8 -0
  49. package/dist/tools/validate-paths.tool.d.ts.map +1 -0
  50. package/dist/tools/validate-paths.tool.js +64 -0
  51. package/dist/tools/validate-paths.tool.js.map +1 -0
  52. package/dist/types.d.ts +221 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +5 -0
  55. package/dist/types.js.map +1 -0
  56. package/dist/utils/commandExecutor.d.ts +28 -0
  57. package/dist/utils/commandExecutor.d.ts.map +1 -0
  58. package/dist/utils/commandExecutor.js +105 -0
  59. package/dist/utils/commandExecutor.js.map +1 -0
  60. package/dist/utils/geminiExecutor.d.ts +71 -0
  61. package/dist/utils/geminiExecutor.d.ts.map +1 -0
  62. package/dist/utils/geminiExecutor.js +281 -0
  63. package/dist/utils/geminiExecutor.js.map +1 -0
  64. package/dist/utils/ignorePatterns.d.ts +69 -0
  65. package/dist/utils/ignorePatterns.d.ts.map +1 -0
  66. package/dist/utils/ignorePatterns.js +178 -0
  67. package/dist/utils/ignorePatterns.js.map +1 -0
  68. package/dist/utils/index.d.ts +11 -0
  69. package/dist/utils/index.d.ts.map +1 -0
  70. package/dist/utils/index.js +18 -0
  71. package/dist/utils/index.js.map +1 -0
  72. package/dist/utils/logger.d.ts +39 -0
  73. package/dist/utils/logger.d.ts.map +1 -0
  74. package/dist/utils/logger.js +160 -0
  75. package/dist/utils/logger.js.map +1 -0
  76. package/dist/utils/pathValidator.d.ts +55 -0
  77. package/dist/utils/pathValidator.d.ts.map +1 -0
  78. package/dist/utils/pathValidator.js +137 -0
  79. package/dist/utils/pathValidator.js.map +1 -0
  80. package/dist/utils/responseCache.d.ts +80 -0
  81. package/dist/utils/responseCache.d.ts.map +1 -0
  82. package/dist/utils/responseCache.js +179 -0
  83. package/dist/utils/responseCache.js.map +1 -0
  84. package/dist/utils/responseChunker.d.ts +36 -0
  85. package/dist/utils/responseChunker.d.ts.map +1 -0
  86. package/dist/utils/responseChunker.js +96 -0
  87. package/dist/utils/responseChunker.js.map +1 -0
  88. package/package.json +62 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Gemini CLI executor utility
3
+ * Handles all interactions with the Gemini CLI binary
4
+ * Implements 3-tier model fallback strategy (PRD §7.3)
5
+ */
6
+ import { SYSTEM_PROMPT, MODEL_TIERS, CLI, ERROR_MESSAGES, STATUS_MESSAGES } from "../constants.js";
7
+ import { Logger } from "./logger.js";
8
+ import { executeCommand, commandExists, getCommandVersion } from "./commandExecutor.js";
9
+ // ============================================================================
10
+ // Helper Functions
11
+ // ============================================================================
12
+ /**
13
+ * Get model tiers for a specific tool
14
+ *
15
+ * @param toolName - The tool requesting Gemini execution
16
+ * @returns Array of model names to try in order (null = auto-select)
17
+ */
18
+ function getModelTiers(toolName) {
19
+ const config = MODEL_TIERS[toolName] ?? MODEL_TIERS.quick_query;
20
+ return [config.tier1, config.tier2, config.tier3];
21
+ }
22
+ /**
23
+ * Check if an error is a quota/capacity error that should trigger fallback
24
+ *
25
+ * @param error - The error to check
26
+ * @returns true if this is a quota error
27
+ */
28
+ function isQuotaError(error) {
29
+ if (!(error instanceof Error)) {
30
+ return false;
31
+ }
32
+ const message = error.message.toLowerCase();
33
+ return (message.includes("quota") ||
34
+ message.includes("resource_exhausted") ||
35
+ message.includes("rate limit") ||
36
+ message.includes("capacity") ||
37
+ message.includes("too many requests") ||
38
+ message.includes("429"));
39
+ }
40
+ /**
41
+ * Build Gemini CLI arguments
42
+ *
43
+ * @param prompt - The full prompt to send
44
+ * @param model - Model name or null for auto-select
45
+ * @returns Array of CLI arguments
46
+ */
47
+ function buildGeminiArgs(prompt, model) {
48
+ const args = [];
49
+ // Add model flag if specified (Tier 3 uses auto-select with no -m flag)
50
+ if (model !== null) {
51
+ args.push(CLI.FLAGS.MODEL, model);
52
+ }
53
+ // Required flags for headless mode
54
+ args.push(CLI.FLAGS.YES); // Auto-approve file reads
55
+ args.push(CLI.FLAGS.OUTPUT_FORMAT, CLI.OUTPUT_FORMATS.JSON);
56
+ // Add prompt
57
+ args.push(CLI.FLAGS.PROMPT, prompt);
58
+ // NEVER add --yolo flag (read-only enforcement)
59
+ return args;
60
+ }
61
+ /**
62
+ * Parse JSON output from Gemini CLI
63
+ *
64
+ * @param output - Raw stdout from Gemini CLI
65
+ * @returns Parsed response data
66
+ */
67
+ function parseGeminiOutput(output) {
68
+ try {
69
+ // Try to parse as JSON
70
+ const parsed = JSON.parse(output);
71
+ // Handle different possible response structures
72
+ if (typeof parsed === "object" && parsed !== null) {
73
+ // Look for common response fields
74
+ const text = parsed.response ||
75
+ parsed.text ||
76
+ parsed.content ||
77
+ parsed.answer ||
78
+ parsed.result ||
79
+ (typeof parsed === "string" ? parsed : JSON.stringify(parsed, null, 2));
80
+ return {
81
+ text: String(text),
82
+ tokensUsed: parsed.usage?.totalTokens || parsed.tokensUsed || parsed.tokens,
83
+ toolCalls: parsed.toolCalls || parsed.tool_calls?.length || 0,
84
+ filesAccessed: extractFilesFromResponse(parsed),
85
+ };
86
+ }
87
+ return { text: output };
88
+ }
89
+ catch {
90
+ // If not valid JSON, return raw output
91
+ // This handles cases where Gemini outputs plain text
92
+ return { text: output };
93
+ }
94
+ }
95
+ /**
96
+ * Extract file paths from Gemini response
97
+ *
98
+ * @param response - Parsed Gemini response object
99
+ * @returns Array of file paths that were accessed
100
+ */
101
+ function extractFilesFromResponse(response) {
102
+ const files = [];
103
+ if (typeof response !== "object" || response === null) {
104
+ return files;
105
+ }
106
+ const obj = response;
107
+ // Check common fields for file references
108
+ if (Array.isArray(obj.filesAccessed)) {
109
+ files.push(...obj.filesAccessed);
110
+ }
111
+ if (Array.isArray(obj.files)) {
112
+ files.push(...obj.files);
113
+ }
114
+ // Extract from tool calls if present
115
+ if (Array.isArray(obj.tool_calls)) {
116
+ for (const call of obj.tool_calls) {
117
+ if (call.name === "read_file" && typeof call.path === "string") {
118
+ files.push(call.path);
119
+ }
120
+ }
121
+ }
122
+ // Parse "Files Referenced" section from text if present
123
+ const text = String(obj.response || obj.text || obj.content || "");
124
+ const fileMatches = text.match(/## Files Referenced\n([\s\S]*?)(?:\n##|$)/);
125
+ if (fileMatches) {
126
+ const fileLines = fileMatches[1]
127
+ .split("\n")
128
+ .map((line) => line.replace(/^[-*]\s*/, "").trim())
129
+ .filter((line) => line.length > 0 && !line.startsWith("#"));
130
+ files.push(...fileLines);
131
+ }
132
+ // Deduplicate
133
+ return [...new Set(files)];
134
+ }
135
+ // ============================================================================
136
+ // Main Execution Function
137
+ // ============================================================================
138
+ /**
139
+ * Execute a prompt using Gemini CLI with model fallback
140
+ *
141
+ * @param prompt - The user's research prompt
142
+ * @param toolName - The tool initiating this request (determines model selection)
143
+ * @param onProgress - Optional callback for progress updates
144
+ * @returns GeminiResponse with the answer and metadata
145
+ */
146
+ export async function executeGeminiCLI(prompt, toolName, onProgress) {
147
+ const startTime = Date.now();
148
+ // Prepend system prompt
149
+ const finalPrompt = `${SYSTEM_PROMPT}\n\n---\n\nUSER REQUEST:\n${prompt}`;
150
+ // Get model tiers for this tool
151
+ const modelTiers = getModelTiers(toolName);
152
+ Logger.info(`Executing Gemini CLI for tool: ${toolName}`);
153
+ // Try each tier with fallback
154
+ let lastError = null;
155
+ for (let i = 0; i < modelTiers.length; i++) {
156
+ const model = modelTiers[i];
157
+ const tierName = model ?? "auto-select";
158
+ try {
159
+ Logger.debug(`Attempting tier ${i + 1} with model: ${tierName}`);
160
+ if (i > 0) {
161
+ // Log fallback attempt
162
+ const message = i === 1 ? STATUS_MESSAGES.FALLBACK_RETRY : STATUS_MESSAGES.AUTO_SELECT_RETRY;
163
+ Logger.warn(message);
164
+ onProgress?.(message + "\n");
165
+ }
166
+ const args = buildGeminiArgs(finalPrompt, model);
167
+ const output = await executeCommand(CLI.COMMANDS.GEMINI, args, onProgress);
168
+ // Parse the output
169
+ const parsed = parseGeminiOutput(output);
170
+ const latencyMs = Date.now() - startTime;
171
+ Logger.info(`Gemini CLI completed in ${latencyMs}ms with model: ${tierName}`);
172
+ if (i > 0) {
173
+ Logger.info(STATUS_MESSAGES.FALLBACK_SUCCESS);
174
+ }
175
+ return {
176
+ answer: parsed.text,
177
+ filesAccessed: parsed.filesAccessed || [],
178
+ stats: {
179
+ tokensUsed: parsed.tokensUsed || 0,
180
+ toolCalls: parsed.toolCalls || 0,
181
+ latencyMs,
182
+ },
183
+ model: model ?? "auto",
184
+ };
185
+ }
186
+ catch (error) {
187
+ lastError = error instanceof Error ? error : new Error(String(error));
188
+ // Check if this is a quota error and we have more tiers to try
189
+ if (isQuotaError(error) && i < modelTiers.length - 1) {
190
+ Logger.warn(`${ERROR_MESSAGES.QUOTA_EXCEEDED_SHORT} (tier ${i + 1})`);
191
+ continue; // Try next tier
192
+ }
193
+ // Not a quota error or no more tiers - throw
194
+ Logger.error(`Gemini CLI failed: ${lastError.message}`);
195
+ throw lastError;
196
+ }
197
+ }
198
+ // Should not reach here, but just in case
199
+ throw lastError ?? new Error("Gemini CLI execution failed");
200
+ }
201
+ // ============================================================================
202
+ // Validation Functions
203
+ // ============================================================================
204
+ /**
205
+ * Check if Gemini CLI is installed and accessible
206
+ *
207
+ * @returns true if gemini command exists on PATH
208
+ */
209
+ export async function isGeminiCLIInstalled() {
210
+ return commandExists(CLI.COMMANDS.GEMINI);
211
+ }
212
+ /**
213
+ * Get Gemini CLI version
214
+ *
215
+ * @returns Version string or null if not installed
216
+ */
217
+ export async function getGeminiVersion() {
218
+ return getCommandVersion(CLI.COMMANDS.GEMINI);
219
+ }
220
+ /**
221
+ * Check if Gemini CLI authentication is configured
222
+ * Checks for GEMINI_API_KEY env var or existing authenticated session
223
+ *
224
+ * @returns Object with auth status
225
+ */
226
+ export async function checkGeminiAuth() {
227
+ // Check for API key
228
+ if (process.env.GEMINI_API_KEY) {
229
+ return { configured: true, method: "api_key" };
230
+ }
231
+ // Check for Vertex AI credentials
232
+ if (process.env.GOOGLE_APPLICATION_CREDENTIALS || process.env.VERTEX_AI_PROJECT) {
233
+ return { configured: true, method: "vertex_ai" };
234
+ }
235
+ // Try a minimal test invocation to check for Google login session
236
+ try {
237
+ await executeCommand(CLI.COMMANDS.GEMINI, [
238
+ CLI.FLAGS.PROMPT,
239
+ "test",
240
+ CLI.FLAGS.OUTPUT_FORMAT,
241
+ CLI.OUTPUT_FORMATS.JSON,
242
+ ]);
243
+ return { configured: true, method: "google_login" };
244
+ }
245
+ catch (error) {
246
+ const message = error instanceof Error ? error.message : String(error);
247
+ if (message.includes("auth") || message.includes("login") || message.includes("credential")) {
248
+ return { configured: false };
249
+ }
250
+ // Other errors might still mean auth is configured
251
+ return { configured: true, method: "google_login" };
252
+ }
253
+ }
254
+ /**
255
+ * Validate Gemini CLI setup (installation + auth)
256
+ *
257
+ * @returns Object with validation results
258
+ */
259
+ export async function validateGeminiSetup() {
260
+ const errors = [];
261
+ // Check installation
262
+ const installed = await isGeminiCLIInstalled();
263
+ if (!installed) {
264
+ errors.push(ERROR_MESSAGES.GEMINI_CLI_NOT_FOUND);
265
+ }
266
+ // Get version
267
+ const version = installed ? await getGeminiVersion() : null;
268
+ // Check auth
269
+ const auth = installed ? await checkGeminiAuth() : { configured: false };
270
+ if (installed && !auth.configured) {
271
+ errors.push(ERROR_MESSAGES.AUTH_MISSING);
272
+ }
273
+ return {
274
+ installed,
275
+ version,
276
+ authenticated: auth.configured,
277
+ authMethod: auth.method,
278
+ errors,
279
+ };
280
+ }
281
+ //# sourceMappingURL=geminiExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geminiExecutor.js","sourceRoot":"","sources":["../../src/utils/geminiExecutor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Ignore patterns utility for directory enumeration
3
+ * Respects .gitignore and hard-coded exclusions (PRD §6.3)
4
+ */
5
+ import { type Ignore } from "ignore";
6
+ /**
7
+ * Hard-coded ignore patterns that are always applied
8
+ * These are common directories that should never be sent to Gemini
9
+ */
10
+ export declare const HARD_CODED_IGNORES: readonly string[];
11
+ /**
12
+ * Parse .gitignore file and return an ignore instance
13
+ *
14
+ * @param projectRoot - The project root directory
15
+ * @returns Ignore instance configured with .gitignore rules
16
+ */
17
+ export declare function parseGitignore(projectRoot: string): Ignore;
18
+ /**
19
+ * Check if a file path should be ignored
20
+ *
21
+ * @param filePath - Relative file path (from project root)
22
+ * @param projectRoot - The project root directory
23
+ * @returns true if the file should be ignored
24
+ */
25
+ export declare function isIgnored(filePath: string, projectRoot: string): boolean;
26
+ /**
27
+ * Create an ignore filter function
28
+ *
29
+ * @param projectRoot - The project root directory
30
+ * @returns Function that returns true if a path should be ignored
31
+ */
32
+ export declare function createIgnoreFilter(projectRoot: string): (filePath: string) => boolean;
33
+ /**
34
+ * Directory entry for enumeration results
35
+ */
36
+ export interface DirectoryEnumerationEntry {
37
+ path: string;
38
+ relativePath: string;
39
+ isDirectory: boolean;
40
+ }
41
+ /**
42
+ * Enumerate files in a directory, respecting ignore rules
43
+ *
44
+ * @param dirPath - Absolute path to directory to enumerate
45
+ * @param projectRoot - The project root directory
46
+ * @param maxFiles - Maximum number of files to return (default: 500)
47
+ * @param maxDepth - Maximum traversal depth (default: unlimited = -1)
48
+ * @returns Array of file entries with relative paths
49
+ */
50
+ export declare function enumerateDirectory(dirPath: string, projectRoot: string, maxFiles?: number, maxDepth?: number): Promise<{
51
+ entries: DirectoryEnumerationEntry[];
52
+ truncated: boolean;
53
+ warnings: string[];
54
+ }>;
55
+ /**
56
+ * Get only file entries (not directories) from enumeration
57
+ *
58
+ * @param dirPath - Absolute path to directory to enumerate
59
+ * @param projectRoot - The project root directory
60
+ * @param maxFiles - Maximum number of files to return
61
+ * @param maxDepth - Maximum traversal depth
62
+ * @returns Array of file paths (relative to project root)
63
+ */
64
+ export declare function enumerateFiles(dirPath: string, projectRoot: string, maxFiles?: number, maxDepth?: number): Promise<{
65
+ files: string[];
66
+ truncated: boolean;
67
+ warnings: string[];
68
+ }>;
69
+ //# sourceMappingURL=ignorePatterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignorePatterns.d.ts","sourceRoot":"","sources":["../../src/utils/ignorePatterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAe,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAO7C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAA4B,CAAC;AAE7E;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAkB1D;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAKxE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAMrF;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,MAAY,EACtB,QAAQ,GAAE,MAAW,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA6F3F;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,MAAY,EACtB,QAAQ,GAAE,MAAW,GACpB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAYtE"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Ignore patterns utility for directory enumeration
3
+ * Respects .gitignore and hard-coded exclusions (PRD §6.3)
4
+ */
5
+ import * as fs from "fs";
6
+ import * as path from "path";
7
+ import ignore from "ignore";
8
+ import { DEFAULT_IGNORE_PATTERNS } from "../constants.js";
9
+ import { isWithinProjectRoot } from "./pathValidator.js";
10
+ // Cast the import to the correct type (ESM interop workaround)
11
+ const createIgnore = ignore;
12
+ /**
13
+ * Hard-coded ignore patterns that are always applied
14
+ * These are common directories that should never be sent to Gemini
15
+ */
16
+ export const HARD_CODED_IGNORES = DEFAULT_IGNORE_PATTERNS;
17
+ /**
18
+ * Parse .gitignore file and return an ignore instance
19
+ *
20
+ * @param projectRoot - The project root directory
21
+ * @returns Ignore instance configured with .gitignore rules
22
+ */
23
+ export function parseGitignore(projectRoot) {
24
+ const ig = createIgnore();
25
+ // Always add hard-coded patterns first
26
+ ig.add(HARD_CODED_IGNORES);
27
+ // Try to read .gitignore
28
+ const gitignorePath = path.join(projectRoot, ".gitignore");
29
+ try {
30
+ if (fs.existsSync(gitignorePath)) {
31
+ const content = fs.readFileSync(gitignorePath, "utf-8");
32
+ ig.add(content);
33
+ }
34
+ }
35
+ catch {
36
+ // Silently ignore errors reading .gitignore
37
+ }
38
+ return ig;
39
+ }
40
+ /**
41
+ * Check if a file path should be ignored
42
+ *
43
+ * @param filePath - Relative file path (from project root)
44
+ * @param projectRoot - The project root directory
45
+ * @returns true if the file should be ignored
46
+ */
47
+ export function isIgnored(filePath, projectRoot) {
48
+ const ig = parseGitignore(projectRoot);
49
+ // Normalize path to use forward slashes for ignore matching
50
+ const normalizedPath = filePath.replace(/\\/g, "/");
51
+ return ig.ignores(normalizedPath);
52
+ }
53
+ /**
54
+ * Create an ignore filter function
55
+ *
56
+ * @param projectRoot - The project root directory
57
+ * @returns Function that returns true if a path should be ignored
58
+ */
59
+ export function createIgnoreFilter(projectRoot) {
60
+ const ig = parseGitignore(projectRoot);
61
+ return (filePath) => {
62
+ const normalizedPath = filePath.replace(/\\/g, "/");
63
+ return ig.ignores(normalizedPath);
64
+ };
65
+ }
66
+ /**
67
+ * Enumerate files in a directory, respecting ignore rules
68
+ *
69
+ * @param dirPath - Absolute path to directory to enumerate
70
+ * @param projectRoot - The project root directory
71
+ * @param maxFiles - Maximum number of files to return (default: 500)
72
+ * @param maxDepth - Maximum traversal depth (default: unlimited = -1)
73
+ * @returns Array of file entries with relative paths
74
+ */
75
+ export async function enumerateDirectory(dirPath, projectRoot, maxFiles = 500, maxDepth = -1) {
76
+ const entries = [];
77
+ const warnings = [];
78
+ const ignoreFilter = createIgnoreFilter(projectRoot);
79
+ // Validate that dirPath is within project root
80
+ if (!isWithinProjectRoot(dirPath, projectRoot)) {
81
+ warnings.push(`Directory ${dirPath} is outside project root`);
82
+ return { entries, truncated: false, warnings };
83
+ }
84
+ // Check directory exists
85
+ try {
86
+ const stats = fs.statSync(dirPath);
87
+ if (!stats.isDirectory()) {
88
+ warnings.push(`${dirPath} is not a directory`);
89
+ return { entries, truncated: false, warnings };
90
+ }
91
+ }
92
+ catch {
93
+ warnings.push(`Directory ${dirPath} does not exist or is not accessible`);
94
+ return { entries, truncated: false, warnings };
95
+ }
96
+ // Recursive enumeration with depth tracking
97
+ async function enumerateRecursive(currentPath, currentDepth) {
98
+ // Check depth limit
99
+ if (maxDepth >= 0 && currentDepth > maxDepth) {
100
+ return;
101
+ }
102
+ // Check file limit
103
+ if (entries.length >= maxFiles) {
104
+ return;
105
+ }
106
+ try {
107
+ const items = fs.readdirSync(currentPath, { withFileTypes: true });
108
+ for (const item of items) {
109
+ // Check file limit again for each item
110
+ if (entries.length >= maxFiles) {
111
+ break;
112
+ }
113
+ const absolutePath = path.join(currentPath, item.name);
114
+ const relativePath = path.relative(projectRoot, absolutePath);
115
+ const normalizedRelative = relativePath.replace(/\\/g, "/");
116
+ // Check if this path should be ignored
117
+ // For directories, check with trailing slash
118
+ const checkPath = item.isDirectory()
119
+ ? normalizedRelative + "/"
120
+ : normalizedRelative;
121
+ if (ignoreFilter(checkPath)) {
122
+ continue;
123
+ }
124
+ if (item.isDirectory()) {
125
+ // Add directory entry and recurse
126
+ entries.push({
127
+ path: absolutePath,
128
+ relativePath: normalizedRelative,
129
+ isDirectory: true,
130
+ });
131
+ // Recurse into subdirectory
132
+ await enumerateRecursive(absolutePath, currentDepth + 1);
133
+ }
134
+ else if (item.isFile()) {
135
+ entries.push({
136
+ path: absolutePath,
137
+ relativePath: normalizedRelative,
138
+ isDirectory: false,
139
+ });
140
+ }
141
+ }
142
+ }
143
+ catch (err) {
144
+ const error = err;
145
+ // Log permission errors but continue
146
+ if (error.code === "EACCES" || error.code === "EPERM") {
147
+ warnings.push(`Permission denied: ${currentPath}`);
148
+ }
149
+ }
150
+ }
151
+ await enumerateRecursive(dirPath, 0);
152
+ const truncated = entries.length >= maxFiles;
153
+ if (truncated) {
154
+ warnings.push(`Exceeded maxFiles limit; showing first ${maxFiles} files only`);
155
+ }
156
+ return { entries, truncated, warnings };
157
+ }
158
+ /**
159
+ * Get only file entries (not directories) from enumeration
160
+ *
161
+ * @param dirPath - Absolute path to directory to enumerate
162
+ * @param projectRoot - The project root directory
163
+ * @param maxFiles - Maximum number of files to return
164
+ * @param maxDepth - Maximum traversal depth
165
+ * @returns Array of file paths (relative to project root)
166
+ */
167
+ export async function enumerateFiles(dirPath, projectRoot, maxFiles = 500, maxDepth = -1) {
168
+ const result = await enumerateDirectory(dirPath, projectRoot, maxFiles, maxDepth);
169
+ const files = result.entries
170
+ .filter((e) => !e.isDirectory)
171
+ .map((e) => e.relativePath);
172
+ return {
173
+ files,
174
+ truncated: result.truncated,
175
+ warnings: result.warnings,
176
+ };
177
+ }
178
+ //# sourceMappingURL=ignorePatterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignorePatterns.js","sourceRoot":"","sources":["../../src/utils/ignorePatterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Utility module exports for Better Gemini MCP Server
3
+ */
4
+ export { Logger } from "./logger.js";
5
+ export { executeCommand, commandExists, getCommandVersion, } from "./commandExecutor.js";
6
+ export { executeGeminiCLI, isGeminiCLIInstalled, getGeminiVersion, checkGeminiAuth, validateGeminiSetup, type GeminiResponse, type ToolName, } from "./geminiExecutor.js";
7
+ export { validatePath, isWithinProjectRoot, extractAtPathReferences, validatePromptPaths, checkPromptPathsValid, getProjectRoot, } from "./pathValidator.js";
8
+ export { HARD_CODED_IGNORES, parseGitignore, isIgnored, createIgnoreFilter, enumerateDirectory, enumerateFiles, type DirectoryEnumerationEntry, } from "./ignorePatterns.js";
9
+ export { generateCacheKey, cacheResponse, getResponse, getChunk, hasValidCache, getCacheMetadata, deleteCache, clearExpired, clearAll, getCacheStats, } from "./responseCache.js";
10
+ export { chunkResponse, needsChunking, estimateChunkCount, getChunkSizeKB, } from "./responseChunker.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EACL,cAAc,EACd,aAAa,EACb,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,QAAQ,GACd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,KAAK,yBAAyB,GAC/B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Utility module exports for Better Gemini MCP Server
3
+ */
4
+ // Logging
5
+ export { Logger } from "./logger.js";
6
+ // Command execution
7
+ export { executeCommand, commandExists, getCommandVersion, } from "./commandExecutor.js";
8
+ // Gemini CLI execution
9
+ export { executeGeminiCLI, isGeminiCLIInstalled, getGeminiVersion, checkGeminiAuth, validateGeminiSetup, } from "./geminiExecutor.js";
10
+ // Path validation
11
+ export { validatePath, isWithinProjectRoot, extractAtPathReferences, validatePromptPaths, checkPromptPathsValid, getProjectRoot, } from "./pathValidator.js";
12
+ // Ignore patterns
13
+ export { HARD_CODED_IGNORES, parseGitignore, isIgnored, createIgnoreFilter, enumerateDirectory, enumerateFiles, } from "./ignorePatterns.js";
14
+ // Response caching
15
+ export { generateCacheKey, cacheResponse, getResponse, getChunk, hasValidCache, getCacheMetadata, deleteCache, clearExpired, clearAll, getCacheStats, } from "./responseCache.js";
16
+ // Response chunking
17
+ export { chunkResponse, needsChunking, estimateChunkCount, getChunkSizeKB, } from "./responseChunker.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,UAAU;AACV,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,oBAAoB;AACpB,OAAO,EACL,cAAc,EACd,aAAa,EACb,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,uBAAuB;AACvB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GAGpB,MAAM,qBAAqB,CAAC;AAE7B,kBAAkB;AAClB,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAE5B,kBAAkB;AAClB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GAEf,MAAM,qBAAqB,CAAC;AAE7B,mBAAmB;AACnB,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,oBAAoB;AACpB,OAAO,EACL,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Structured logging utility for Better Gemini MCP Server
3
+ * Implements logging with levels: error, warn, info, debug
4
+ * NEVER logs sensitive credentials like GEMINI_API_KEY
5
+ */
6
+ /**
7
+ * Logger class for structured logging
8
+ */
9
+ export declare class Logger {
10
+ /**
11
+ * Log an error message (always logged)
12
+ */
13
+ static error(message: string, ...args: unknown[]): void;
14
+ /**
15
+ * Log a warning message (always logged)
16
+ */
17
+ static warn(message: string, ...args: unknown[]): void;
18
+ /**
19
+ * Log an info message (always logged)
20
+ */
21
+ static info(message: string, ...args: unknown[]): void;
22
+ /**
23
+ * Log a debug message (only when DEBUG env var is set)
24
+ */
25
+ static debug(message: string, ...args: unknown[]): void;
26
+ /**
27
+ * Log a tool invocation (sanitized parameters, excludes full prompts)
28
+ */
29
+ static toolInvocation(toolName: string, args: Record<string, unknown>): void;
30
+ /**
31
+ * Log command execution (command args, not output)
32
+ */
33
+ static commandExecution(command: string, args: string[], startTime: number): void;
34
+ /**
35
+ * Log command completion with timing
36
+ */
37
+ static commandComplete(startTime: number, exitCode: number | null, outputLength?: number): void;
38
+ }
39
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiEH;;GAEG;AACH,qBAAa,MAAM;IACjB;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAUvD;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAUtD;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAUtD;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAYvD;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAS5E;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAYjF;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;CAOhG"}