@j0hanz/code-assistant 0.9.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 (54) hide show
  1. package/README.md +437 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +72 -0
  4. package/dist/lib/concurrency.d.ts +13 -0
  5. package/dist/lib/concurrency.js +77 -0
  6. package/dist/lib/config.d.ts +43 -0
  7. package/dist/lib/config.js +87 -0
  8. package/dist/lib/diff.d.ts +49 -0
  9. package/dist/lib/diff.js +241 -0
  10. package/dist/lib/errors.d.ts +8 -0
  11. package/dist/lib/errors.js +69 -0
  12. package/dist/lib/format.d.ts +14 -0
  13. package/dist/lib/format.js +33 -0
  14. package/dist/lib/gemini.d.ts +45 -0
  15. package/dist/lib/gemini.js +833 -0
  16. package/dist/lib/progress.d.ts +72 -0
  17. package/dist/lib/progress.js +204 -0
  18. package/dist/lib/tools.d.ts +274 -0
  19. package/dist/lib/tools.js +646 -0
  20. package/dist/prompts/index.d.ts +11 -0
  21. package/dist/prompts/index.js +96 -0
  22. package/dist/resources/index.d.ts +12 -0
  23. package/dist/resources/index.js +115 -0
  24. package/dist/resources/instructions.d.ts +1 -0
  25. package/dist/resources/instructions.js +71 -0
  26. package/dist/resources/server-config.d.ts +1 -0
  27. package/dist/resources/server-config.js +75 -0
  28. package/dist/resources/tool-catalog.d.ts +1 -0
  29. package/dist/resources/tool-catalog.js +30 -0
  30. package/dist/resources/tool-info.d.ts +5 -0
  31. package/dist/resources/tool-info.js +105 -0
  32. package/dist/resources/workflows.d.ts +1 -0
  33. package/dist/resources/workflows.js +59 -0
  34. package/dist/schemas/inputs.d.ts +21 -0
  35. package/dist/schemas/inputs.js +46 -0
  36. package/dist/schemas/outputs.d.ts +121 -0
  37. package/dist/schemas/outputs.js +162 -0
  38. package/dist/server.d.ts +6 -0
  39. package/dist/server.js +88 -0
  40. package/dist/tools/analyze-complexity.d.ts +2 -0
  41. package/dist/tools/analyze-complexity.js +50 -0
  42. package/dist/tools/analyze-pr-impact.d.ts +2 -0
  43. package/dist/tools/analyze-pr-impact.js +62 -0
  44. package/dist/tools/detect-api-breaking.d.ts +2 -0
  45. package/dist/tools/detect-api-breaking.js +49 -0
  46. package/dist/tools/generate-diff.d.ts +2 -0
  47. package/dist/tools/generate-diff.js +140 -0
  48. package/dist/tools/generate-review-summary.d.ts +2 -0
  49. package/dist/tools/generate-review-summary.js +71 -0
  50. package/dist/tools/generate-test-plan.d.ts +2 -0
  51. package/dist/tools/generate-test-plan.js +67 -0
  52. package/dist/tools/index.d.ts +2 -0
  53. package/dist/tools/index.js +19 -0
  54. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,437 @@
1
+ # Code Assistant MCP Server
2
+
3
+ <!-- mcp-name: io.github.j0hanz/code-assistant -->
4
+
5
+ [![npm](https://img.shields.io/npm/v/%40j0hanz%2Fcode-assistant-mcp?style=flat-square&logo=npm&logoColor=white&color=CB3837)](https://www.npmjs.com/package/@j0hanz/code-assistant-mcp) [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D24-339933?style=flat-square&logo=nodedotjs&logoColor=white)](package.json) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9%2B-3178C6?style=flat-square&logo=typescript&logoColor=white)](package.json) [![MCP SDK](https://img.shields.io/badge/MCP_SDK-1.26%2B-6f42c1?style=flat-square)](package.json) [![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](package.json)
6
+
7
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D&quality=insiders) [![Install in Visual Studio](https://img.shields.io/badge/Visual_Studio-Install_Server-C16FDE?logo=visualstudio&logoColor=white)](https://vs-open.link/mcp-install?%7B%22name%22%3A%22code-assistant%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D)
8
+
9
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=code-assistant&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovY29kZS1hc3Npc3RhbnQtbWNwQGxhdGVzdCJdfQ==)
10
+
11
+ Gemini-powered MCP server for code analysis with structured outputs for findings, risk assessment, and focused patch suggestions.
12
+
13
+ ## Overview
14
+
15
+ This server accepts unified diffs and returns structured JSON results — findings with severity, impact categories, merge risk, test plans, and verbatim search/replace fixes. It uses Gemini Thinking models (Flash for fast tools, Flash for deep analysis) and runs over **stdio transport**.
16
+
17
+ ## Key Features
18
+
19
+ - **Impact Analysis** — Objective severity scoring, breaking change detection, and rollback complexity assessment.
20
+ - **Review Summary** — Concise PR digest with merge recommendation and change statistics.
21
+ - **Deep Code Inspection** — Flash model with high thinking level for context-aware analysis using full file contents.
22
+ - **Search & Replace Fixes** — Verbatim, copy-paste-ready code fixes tied to specific findings.
23
+ - **Test Plan Generation** — Systematic test case generation with priority ranking and pseudocode.
24
+ - **Async Task Support** — All tools support MCP task lifecycle with progress notifications.
25
+
26
+ ## Requirements
27
+
28
+ - Node.js `>=24`
29
+ - One API key: `GEMINI_API_KEY` or `GOOGLE_API_KEY`
30
+ - MCP client that supports stdio servers and tool calls
31
+
32
+ ## Quick Start
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "code-assistant": {
38
+ "command": "npx",
39
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
40
+ "env": {
41
+ "GEMINI_API_KEY": "YOUR_API_KEY"
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ## Client Configuration
49
+
50
+ <details>
51
+ <summary><b>VS Code / VS Code Insiders</b></summary>
52
+
53
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D&quality=insiders)
54
+
55
+ Add to `.vscode/mcp.json`:
56
+
57
+ ```json
58
+ {
59
+ "servers": {
60
+ "code-assistant": {
61
+ "command": "npx",
62
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
63
+ "env": {
64
+ "GEMINI_API_KEY": "YOUR_API_KEY"
65
+ }
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ Or via CLI:
72
+
73
+ ```bash
74
+ code --add-mcp '{"name":"code-assistant","command":"npx","args":["-y","@j0hanz/code-assistant-mcp@latest"]}'
75
+ ```
76
+
77
+ </details>
78
+
79
+ <details>
80
+ <summary><b>Cursor</b></summary>
81
+
82
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=code-assistant&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovY29kZS1hc3Npc3RhbnQtbWNwQGxhdGVzdCJdfQ==)
83
+
84
+ Add to `~/.cursor/mcp.json`:
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "code-assistant": {
90
+ "command": "npx",
91
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
92
+ "env": {
93
+ "GEMINI_API_KEY": "YOUR_API_KEY"
94
+ }
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ </details>
101
+
102
+ <details>
103
+ <summary><b>Visual Studio</b></summary>
104
+
105
+ [![Install in Visual Studio](https://img.shields.io/badge/Visual_Studio-Install_Server-C16FDE?logo=visualstudio&logoColor=white)](https://vs-open.link/mcp-install?%7B%22name%22%3A%22code-assistant%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D)
106
+
107
+ For more info, see [Visual Studio MCP docs](https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers).
108
+
109
+ </details>
110
+
111
+ <details>
112
+ <summary><b>Claude Desktop</b></summary>
113
+
114
+ Add to `claude_desktop_config.json`:
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ "code-assistant": {
120
+ "command": "npx",
121
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
122
+ "env": {
123
+ "GEMINI_API_KEY": "YOUR_API_KEY"
124
+ }
125
+ }
126
+ }
127
+ }
128
+ ```
129
+
130
+ For more info, see [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user).
131
+
132
+ </details>
133
+
134
+ <details>
135
+ <summary><b>Claude Code</b></summary>
136
+
137
+ ```bash
138
+ claude mcp add code-assistant -- npx -y @j0hanz/code-assistant-mcp@latest
139
+ ```
140
+
141
+ For more info, see [Claude Code MCP docs](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/tutorials#set-up-model-context-protocol-mcp).
142
+
143
+ </details>
144
+
145
+ <details>
146
+ <summary><b>Windsurf</b></summary>
147
+
148
+ Add to MCP config:
149
+
150
+ ```json
151
+ {
152
+ "mcpServers": {
153
+ "code-assistant": {
154
+ "command": "npx",
155
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
156
+ "env": {
157
+ "GEMINI_API_KEY": "YOUR_API_KEY"
158
+ }
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ For more info, see [Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp).
165
+
166
+ </details>
167
+
168
+ <details>
169
+ <summary><b>Amp</b></summary>
170
+
171
+ ```bash
172
+ amp mcp add code-assistant -- npx -y @j0hanz/code-assistant-mcp@latest
173
+ ```
174
+
175
+ For more info, see [Amp MCP docs](https://docs.amp.dev/mcp).
176
+
177
+ </details>
178
+
179
+ <details>
180
+ <summary><b>Cline</b></summary>
181
+
182
+ Add to `cline_mcp_settings.json`:
183
+
184
+ ```json
185
+ {
186
+ "mcpServers": {
187
+ "code-assistant": {
188
+ "command": "npx",
189
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
190
+ "env": {
191
+ "GEMINI_API_KEY": "YOUR_API_KEY"
192
+ }
193
+ }
194
+ }
195
+ }
196
+ ```
197
+
198
+ For more info, see [Cline MCP docs](https://docs.cline.bot/mcp-servers/configuring-mcp-servers).
199
+
200
+ </details>
201
+
202
+ <details>
203
+ <summary><b>Zed</b></summary>
204
+
205
+ Add to Zed `settings.json`:
206
+
207
+ ```json
208
+ {
209
+ "context_servers": {
210
+ "code-assistant": {
211
+ "command": {
212
+ "path": "npx",
213
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
214
+ "env": {
215
+ "GEMINI_API_KEY": "YOUR_API_KEY"
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+ ```
222
+
223
+ For more info, see [Zed MCP docs](https://zed.dev/docs/assistant/model-context-protocol).
224
+
225
+ </details>
226
+
227
+ <details>
228
+ <summary><b>Augment</b></summary>
229
+
230
+ Add to `settings.json`:
231
+
232
+ ```json
233
+ {
234
+ "augment.advanced": {
235
+ "mcpServers": [
236
+ {
237
+ "name": "code-assistant",
238
+ "command": "npx",
239
+ "args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
240
+ "env": {
241
+ "GEMINI_API_KEY": "YOUR_API_KEY"
242
+ }
243
+ }
244
+ ]
245
+ }
246
+ }
247
+ ```
248
+
249
+ </details>
250
+
251
+ <details>
252
+ <summary><b>Docker</b></summary>
253
+
254
+ ```json
255
+ {
256
+ "mcpServers": {
257
+ "code-assistant": {
258
+ "command": "docker",
259
+ "args": [
260
+ "run",
261
+ "-i",
262
+ "--rm",
263
+ "-e",
264
+ "GEMINI_API_KEY=YOUR_API_KEY",
265
+ "ghcr.io/j0hanz/code-assistant-mcp:latest"
266
+ ]
267
+ }
268
+ }
269
+ }
270
+ ```
271
+
272
+ Or build locally:
273
+
274
+ ```bash
275
+ docker build -t code-assistant-mcp .
276
+ ```
277
+
278
+ </details>
279
+
280
+ ## Tools
281
+
282
+ > [!IMPORTANT]
283
+ > Call `generate_diff` first (`mode: "unstaged"` or `"staged"`). All review tools read the cached server-side diff (`diff://current`) and do not accept a direct `diff` parameter.
284
+
285
+ ### `generate_diff`
286
+
287
+ Generate and cache the current branch diff for downstream review tools.
288
+
289
+ | Parameter | Type | Required | Description |
290
+ | --------- | -------- | -------- | -------------------------------------------------- |
291
+ | `mode` | `string` | Yes | `unstaged` (working tree) or `staged` (git index). |
292
+
293
+ **Returns:** `diffRef`, `stats` (files, added, deleted), `generatedAt`, `mode`, `message`.
294
+
295
+ ### `analyze_pr_impact`
296
+
297
+ Assess the impact and risk of cached pull request changes using the Flash model.
298
+
299
+ | Parameter | Type | Required | Description |
300
+ | ------------ | -------- | -------- | ---------------------------------------- |
301
+ | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
302
+ | `language` | `string` | No | Primary language hint. |
303
+
304
+ **Returns:** `severity` (low/medium/high/critical), `categories[]`, `breakingChanges[]`, `affectedAreas[]`, `rollbackComplexity`, `summary`.
305
+
306
+ ### `generate_review_summary`
307
+
308
+ Summarize a pull request diff and assess high-level risk using the Flash model.
309
+
310
+ | Parameter | Type | Required | Description |
311
+ | ------------ | -------- | -------- | ---------------------------------------- |
312
+ | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
313
+ | `language` | `string` | No | Primary language hint. |
314
+
315
+ **Returns:** `summary`, `overallRisk` (low/medium/high), `keyChanges[]`, `recommendation`, `stats` (filesChanged, linesAdded, linesRemoved).
316
+
317
+ ### `generate_test_plan`
318
+
319
+ Create a test plan covering the changes in the diff using the Flash model with thinking (8K token budget).
320
+
321
+ | Parameter | Type | Required | Description |
322
+ | --------------- | -------- | -------- | ------------------------------------------- |
323
+ | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
324
+ | `language` | `string` | No | Primary language hint. |
325
+ | `testFramework` | `string` | No | Test framework (e.g. jest, vitest, pytest). |
326
+ | `maxTestCases` | `number` | No | Maximum test cases to return (1-30). |
327
+
328
+ **Returns:** `summary`, `testCases[]` (name, type, file, description, pseudoCode, priority), `coverageSummary`.
329
+
330
+ ## Resources
331
+
332
+ | URI | Type | Description |
333
+ | ------------------------- | --------------- | -------------------------- |
334
+ | `internal://instructions` | `text/markdown` | Server usage instructions. |
335
+
336
+ ## Prompts
337
+
338
+ | Name | Arguments | Description |
339
+ | -------------- | ------------------- | --------------------------------------------------- |
340
+ | `get-help` | — | Return the server usage instructions. |
341
+ | `review-guide` | `tool`, `focusArea` | Guided workflow for a specific tool and focus area. |
342
+
343
+ ## Configuration
344
+
345
+ ### CLI Arguments
346
+
347
+ | Option | Description | Env Var Equivalent |
348
+ | ------------------ | ---------------------- | ------------------ |
349
+ | `--model`, `-m` | Override default model | `GEMINI_MODEL` |
350
+ | `--max-diff-chars` | Override max diff size | `MAX_DIFF_CHARS` |
351
+
352
+ ### Environment Variables
353
+
354
+ | Variable | Description | Default | Required |
355
+ | ------------------------------- | ---------------------------------------------------- | ------------ | -------- |
356
+ | `GEMINI_API_KEY` | Gemini API key | — | Yes |
357
+ | `GOOGLE_API_KEY` | Alternative API key (if `GEMINI_API_KEY` not set) | — | No |
358
+ | `GEMINI_MODEL` | Override default model selection | — | No |
359
+ | `GEMINI_HARM_BLOCK_THRESHOLD` | Safety threshold (BLOCK_NONE, BLOCK_ONLY_HIGH, etc.) | `BLOCK_NONE` | No |
360
+ | `MAX_DIFF_CHARS` | Max chars for diff input | `120000` | No |
361
+ | `MAX_CONCURRENT_CALLS` | Max concurrent Gemini requests | `10` | No |
362
+ | `MAX_CONCURRENT_BATCH_CALLS` | Max concurrent inline batch requests | `2` | No |
363
+ | `MAX_CONCURRENT_CALLS_WAIT_MS` | Max wait time for a free Gemini slot | `2000` | No |
364
+ | `MAX_SCHEMA_RETRY_ERROR_CHARS` | Max chars from schema error injected into retry text | `1500` | No |
365
+ | `GEMINI_BATCH_MODE` | Request mode for Gemini calls (`off`, `inline`) | `off` | No |
366
+ | `GEMINI_BATCH_POLL_INTERVAL_MS` | Poll interval for batch job status | `2000` | No |
367
+ | `GEMINI_BATCH_TIMEOUT_MS` | Max wait for batch completion | `120000` | No |
368
+
369
+ ### Models
370
+
371
+ | Tool | Model | Thinking Level |
372
+ | ------------------------- | ------------------------ | -------------- |
373
+ | `analyze_pr_impact` | `gemini-3-flash-preview` | `minimal` |
374
+ | `generate_review_summary` | `gemini-3-flash-preview` | `minimal` |
375
+ | `generate_test_plan` | `gemini-3-flash-preview` | `medium` |
376
+
377
+ ## Workflows
378
+
379
+ ### Quick PR Triage
380
+
381
+ 1. Call `analyze_pr_impact` to get severity and category breakdown.
382
+ 2. If low/medium — call `generate_review_summary` for a quick digest.
383
+ 3. If high/critical — proceed to deep inspection.
384
+
385
+ ### Testing
386
+
387
+ 1. Call `generate_test_plan` to create a verification strategy.
388
+ 2. Implement tests based on returned test cases and coverage summary.
389
+
390
+ ## Development
391
+
392
+ ```bash
393
+ npm ci # Install dependencies
394
+ npm run dev # TypeScript watch mode
395
+ npm run dev:run # Run built server with .env and --watch
396
+ ```
397
+
398
+ | Script | Command | Purpose |
399
+ | -------------------- | ----------------------------------- | ------------------------------ |
400
+ | `npm run build` | `node scripts/tasks.mjs build` | Clean, compile, validate, copy |
401
+ | `npm test` | `node scripts/tasks.mjs test` | Build + run all tests |
402
+ | `npm run test:fast` | `node --test --import tsx/esm ...` | Run tests without build |
403
+ | `npm run lint` | `eslint .` | Lint all files |
404
+ | `npm run lint:fix` | `eslint . --fix` | Lint and auto-fix |
405
+ | `npm run format` | `prettier --write .` | Format all files |
406
+ | `npm run type-check` | `node scripts/tasks.mjs type-check` | Type-check without emitting |
407
+ | `npm run inspector` | Build + launch MCP Inspector | Debug with MCP Inspector |
408
+
409
+ ### Debugging with MCP Inspector
410
+
411
+ ```bash
412
+ npx @modelcontextprotocol/inspector node dist/index.js
413
+ ```
414
+
415
+ ## Build & Release
416
+
417
+ Releases are triggered via GitHub Actions `workflow_dispatch` with version bump selection (patch/minor/major/custom).
418
+
419
+ The pipeline runs lint, type-check, test, and build, then publishes to three targets in parallel:
420
+
421
+ - **npm** — `@j0hanz/code-assistant-mcp` with OIDC trusted publishing and provenance
422
+ - **Docker** — `ghcr.io/j0hanz/code-assistant-mcp` (linux/amd64, linux/arm64)
423
+ - **MCP Registry** — `io.github.j0hanz/code-assistant`
424
+
425
+ ## Troubleshooting
426
+
427
+ | Issue | Solution |
428
+ | ------------------------------------------ | ------------------------------------------------------------------------------------ |
429
+ | `Missing GEMINI_API_KEY or GOOGLE_API_KEY` | Set one of the API key env vars in your MCP client config. |
430
+ | `E_INPUT_TOO_LARGE` | Diff exceeds budget. Split into smaller diffs. |
431
+ | `Gemini request timed out` | Deep analysis tasks may take 60-120s. Increase your client timeout. |
432
+ | `Too many concurrent Gemini calls` | Reduce parallel tool calls or increase `MAX_CONCURRENT_CALLS`. |
433
+ | No tool output visible | Ensure your MCP client is not swallowing `stderr` — the server uses stdio transport. |
434
+
435
+ ## License
436
+
437
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'node:util';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { getErrorMessage } from './lib/errors.js';
5
+ import { createServer } from './server.js';
6
+ const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
7
+ // --- CLI Parsing ---
8
+ const ARG_OPTION_MODEL = 'model';
9
+ const ARG_OPTION_MAX_DIFF_CHARS = 'max-diff-chars';
10
+ const PROCESS_ARGS_START_INDEX = 2;
11
+ const CLI_ENV_MAPPINGS = [
12
+ { option: ARG_OPTION_MODEL, envVar: 'GEMINI_MODEL' },
13
+ { option: ARG_OPTION_MAX_DIFF_CHARS, envVar: 'MAX_DIFF_CHARS' },
14
+ ];
15
+ const CLI_OPTIONS = {
16
+ [ARG_OPTION_MODEL]: {
17
+ type: 'string',
18
+ short: 'm',
19
+ },
20
+ [ARG_OPTION_MAX_DIFF_CHARS]: {
21
+ type: 'string',
22
+ },
23
+ };
24
+ function setStringEnv(name, value) {
25
+ if (typeof value !== 'string') {
26
+ return;
27
+ }
28
+ process.env[name] = value;
29
+ }
30
+ function applyCliEnvironmentOverrides(values) {
31
+ for (const mapping of CLI_ENV_MAPPINGS) {
32
+ setStringEnv(mapping.envVar, values[mapping.option]);
33
+ }
34
+ }
35
+ function parseCommandLineArgs() {
36
+ const { values } = parseArgs({
37
+ args: process.argv.slice(PROCESS_ARGS_START_INDEX),
38
+ options: CLI_OPTIONS,
39
+ strict: false,
40
+ });
41
+ applyCliEnvironmentOverrides(values);
42
+ }
43
+ let shuttingDown = false;
44
+ async function shutdown(server) {
45
+ if (shuttingDown) {
46
+ return;
47
+ }
48
+ shuttingDown = true;
49
+ await server.shutdown();
50
+ process.exit(0);
51
+ }
52
+ function registerShutdownHandlers(server) {
53
+ for (const signal of SHUTDOWN_SIGNALS) {
54
+ process.once(signal, () => {
55
+ shutdown(server).catch((error) => {
56
+ console.error(`[fatal] ${getErrorMessage(error)}`);
57
+ process.exit(1);
58
+ });
59
+ });
60
+ }
61
+ }
62
+ async function main() {
63
+ parseCommandLineArgs();
64
+ const server = createServer();
65
+ const transport = new StdioServerTransport();
66
+ registerShutdownHandlers(server);
67
+ await server.server.connect(transport);
68
+ }
69
+ main().catch((error) => {
70
+ console.error(`[fatal] ${getErrorMessage(error)}`);
71
+ process.exit(1);
72
+ });
@@ -0,0 +1,13 @@
1
+ export declare class ConcurrencyLimiter {
2
+ private readonly maxConcurrent;
3
+ private readonly waitTimeoutMs;
4
+ private readonly formatTimeoutError;
5
+ private readonly formatCancelError;
6
+ private activeCount;
7
+ private readonly waiters;
8
+ constructor(maxConcurrent: () => number, waitTimeoutMs: () => number, formatTimeoutError: (limit: number, timeoutMs: number) => string, formatCancelError: () => string);
9
+ get pendingCount(): number;
10
+ get active(): number;
11
+ acquire(signal?: AbortSignal): Promise<void>;
12
+ release(): void;
13
+ }
@@ -0,0 +1,77 @@
1
+ export class ConcurrencyLimiter {
2
+ maxConcurrent;
3
+ waitTimeoutMs;
4
+ formatTimeoutError;
5
+ formatCancelError;
6
+ activeCount = 0;
7
+ waiters = new Set();
8
+ constructor(maxConcurrent, waitTimeoutMs, formatTimeoutError, formatCancelError) {
9
+ this.maxConcurrent = maxConcurrent;
10
+ this.waitTimeoutMs = waitTimeoutMs;
11
+ this.formatTimeoutError = formatTimeoutError;
12
+ this.formatCancelError = formatCancelError;
13
+ }
14
+ get pendingCount() {
15
+ return this.waiters.size;
16
+ }
17
+ get active() {
18
+ return this.activeCount;
19
+ }
20
+ acquire(signal) {
21
+ const limit = this.maxConcurrent();
22
+ if (this.activeCount < limit) {
23
+ this.activeCount++;
24
+ return Promise.resolve();
25
+ }
26
+ return new Promise((resolve, reject) => {
27
+ let isSettled = false;
28
+ const waiter = () => {
29
+ if (isSettled) {
30
+ return;
31
+ }
32
+ isSettled = true;
33
+ clearTimeout(timeoutId);
34
+ signal?.removeEventListener('abort', onAbort);
35
+ this.activeCount++;
36
+ resolve();
37
+ };
38
+ const onAbort = () => {
39
+ if (isSettled) {
40
+ return;
41
+ }
42
+ isSettled = true;
43
+ clearTimeout(timeoutId);
44
+ this.waiters.delete(waiter);
45
+ reject(new Error(this.formatCancelError()));
46
+ };
47
+ const onTimeout = () => {
48
+ if (isSettled) {
49
+ return;
50
+ }
51
+ isSettled = true;
52
+ signal?.removeEventListener('abort', onAbort);
53
+ this.waiters.delete(waiter);
54
+ reject(new Error(this.formatTimeoutError(limit, this.waitTimeoutMs())));
55
+ };
56
+ if (signal) {
57
+ if (signal.aborted) {
58
+ reject(new Error(this.formatCancelError()));
59
+ return;
60
+ }
61
+ signal.addEventListener('abort', onAbort, { once: true });
62
+ }
63
+ const timeoutId = setTimeout(onTimeout, this.waitTimeoutMs());
64
+ this.waiters.add(waiter);
65
+ });
66
+ }
67
+ release() {
68
+ if (this.activeCount > 0) {
69
+ this.activeCount--;
70
+ }
71
+ const next = this.waiters.values().next().value;
72
+ if (next) {
73
+ this.waiters.delete(next);
74
+ next();
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,43 @@
1
+ export interface CachedEnvInt {
2
+ get(): number;
3
+ reset(): void;
4
+ }
5
+ /** Creates a cached integer value from an environment variable, with a default fallback. */
6
+ export declare function createCachedEnvInt(envVar: string, defaultValue: number): CachedEnvInt;
7
+ /** Fast, cost-effective model for summarization and light analysis. */
8
+ export declare const FLASH_MODEL = "gemini-3-flash-preview";
9
+ /** Default language hint. */
10
+ export declare const DEFAULT_LANGUAGE = "detect";
11
+ /** Default test-framework hint. */
12
+ export declare const DEFAULT_FRAMEWORK = "detect";
13
+ /** Extended timeout for deep analysis calls (ms). */
14
+ export declare const DEFAULT_TIMEOUT_EXTENDED_MS = 120000;
15
+ export declare const MODEL_TIMEOUT_MS: Readonly<{
16
+ readonly extended: 120000;
17
+ }>;
18
+ /** Thinking level for Flash triage. */
19
+ export declare const FLASH_TRIAGE_THINKING_LEVEL: "minimal";
20
+ /** Thinking level for Flash analysis. */
21
+ export declare const FLASH_THINKING_LEVEL: "medium";
22
+ /** Thinking level for Flash deep analysis. */
23
+ export declare const FLASH_HIGH_THINKING_LEVEL: "high";
24
+ /** Output cap for Flash API breaking-change detection. */
25
+ export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = 65536;
26
+ /** Output cap for Flash complexity analysis. */
27
+ export declare const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = 65536;
28
+ /** Output cap for Flash test-plan generation. */
29
+ export declare const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = 65536;
30
+ /** Output cap for Flash triage tools. */
31
+ export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = 65536;
32
+ /** Output cap for Flash patch generation. */
33
+ export declare const FLASH_PATCH_MAX_OUTPUT_TOKENS = 65536;
34
+ /** Output cap for Flash deep review findings. */
35
+ export declare const FLASH_REVIEW_MAX_OUTPUT_TOKENS = 65536;
36
+ /** Temperature for analytical tools. */
37
+ export declare const ANALYSIS_TEMPERATURE: 1;
38
+ /** Temperature for creative synthesis (test plans). */
39
+ export declare const CREATIVE_TEMPERATURE: 1;
40
+ /** Temperature for code patch generation. */
41
+ export declare const PATCH_TEMPERATURE: 1;
42
+ /** Temperature for triage/classification tools. */
43
+ export declare const TRIAGE_TEMPERATURE: 1;