code-auditor-mcp 2.6.0 → 2.6.2
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/dist/codeIndexDb.d.ts +8 -7
- package/dist/codeIndexDb.d.ts.map +1 -1
- package/dist/codeIndexDb.js +29 -2
- package/dist/codeIndexDb.js.map +1 -1
- package/dist/mcp-index.js +26 -13
- package/dist/mcp-index.js.map +1 -1
- package/dist/mcp-standalone.js +153 -30
- package/dist/mcp-standalone.js.map +1 -1
- package/dist/mcp-tools/projectTasks.d.ts +34 -1
- package/dist/mcp-tools/projectTasks.d.ts.map +1 -1
- package/dist/mcp-tools/projectTasks.js +116 -12
- package/dist/mcp-tools/projectTasks.js.map +1 -1
- package/dist/mcp.js +158 -30
- package/dist/mcp.js.map +1 -1
- package/dist/mcpDiagnostics.d.ts.map +1 -1
- package/dist/mcpDiagnostics.js +8 -5
- package/dist/mcpDiagnostics.js.map +1 -1
- package/dist/services/ProjectTaskRepository.d.ts +19 -7
- package/dist/services/ProjectTaskRepository.d.ts.map +1 -1
- package/dist/services/ProjectTaskRepository.js +369 -9
- package/dist/services/ProjectTaskRepository.js.map +1 -1
- package/dist/types/projectTask.d.ts +27 -0
- package/dist/types/projectTask.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,47 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { CodeIndexDB } from '../codeIndexDB.js';
|
|
6
|
+
const inFlightReadOps = new Map();
|
|
7
|
+
function buildReadDedupKey(action, args, projectPath) {
|
|
8
|
+
const normalized = { action };
|
|
9
|
+
if (projectPath) {
|
|
10
|
+
normalized.projectPath = projectPath;
|
|
11
|
+
}
|
|
12
|
+
const keyFields = [
|
|
13
|
+
'taskId',
|
|
14
|
+
'status',
|
|
15
|
+
'source',
|
|
16
|
+
'priority',
|
|
17
|
+
'label',
|
|
18
|
+
'parentTaskId',
|
|
19
|
+
'hasChildren',
|
|
20
|
+
'blockedByTaskId',
|
|
21
|
+
'query',
|
|
22
|
+
'overdueOnly',
|
|
23
|
+
'actionableOnly',
|
|
24
|
+
'limit'
|
|
25
|
+
];
|
|
26
|
+
for (const field of keyFields) {
|
|
27
|
+
if (Object.prototype.hasOwnProperty.call(args, field)) {
|
|
28
|
+
normalized[field] = args[field];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return JSON.stringify(normalized);
|
|
32
|
+
}
|
|
33
|
+
async function withReadDedup(key, run) {
|
|
34
|
+
const existing = inFlightReadOps.get(key);
|
|
35
|
+
if (existing) {
|
|
36
|
+
return (await existing);
|
|
37
|
+
}
|
|
38
|
+
const promise = run();
|
|
39
|
+
inFlightReadOps.set(key, promise);
|
|
40
|
+
try {
|
|
41
|
+
return await promise;
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
inFlightReadOps.delete(key);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
6
47
|
/**
|
|
7
48
|
* Resolve project root for list/create. If omitted, uses `process.cwd()` (MCP server working directory),
|
|
8
49
|
* same idea as the audit tool's default path. Prefer passing an absolute project path when cwd may differ
|
|
@@ -15,7 +56,29 @@ export function resolveProjectPathForTasks(args) {
|
|
|
15
56
|
}
|
|
16
57
|
return { projectPath: path.resolve(process.cwd()), projectPathDefaulted: true };
|
|
17
58
|
}
|
|
18
|
-
|
|
59
|
+
function parseListTaskOptions(args) {
|
|
60
|
+
return {
|
|
61
|
+
status: args.status,
|
|
62
|
+
source: args.source,
|
|
63
|
+
priority: args.priority,
|
|
64
|
+
label: typeof args.label === 'string' ? args.label : undefined,
|
|
65
|
+
parentTaskId: args.parentTaskId === null
|
|
66
|
+
? null
|
|
67
|
+
: typeof args.parentTaskId === 'string'
|
|
68
|
+
? args.parentTaskId
|
|
69
|
+
: undefined,
|
|
70
|
+
hasChildren: typeof args.hasChildren === 'boolean' ? args.hasChildren : undefined,
|
|
71
|
+
blockedByTaskId: typeof args.blockedByTaskId === 'string' ? args.blockedByTaskId : undefined,
|
|
72
|
+
query: typeof args.query === 'string' ? args.query : undefined,
|
|
73
|
+
overdueOnly: typeof args.overdueOnly === 'boolean' ? args.overdueOnly : undefined,
|
|
74
|
+
actionableOnly: typeof args.actionableOnly === 'boolean' ? args.actionableOnly : undefined,
|
|
75
|
+
limit: typeof args.limit === 'number' ? args.limit : undefined
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export async function handleProjectTasks(args, options) {
|
|
79
|
+
if (options?.signal?.aborted) {
|
|
80
|
+
throw new Error('project_tasks request aborted');
|
|
81
|
+
}
|
|
19
82
|
const action = String(args.action ?? '')
|
|
20
83
|
.toLowerCase()
|
|
21
84
|
.trim();
|
|
@@ -24,15 +87,12 @@ export async function handleProjectTasks(args) {
|
|
|
24
87
|
try {
|
|
25
88
|
switch (action) {
|
|
26
89
|
case 'list': {
|
|
90
|
+
if (options?.signal?.aborted) {
|
|
91
|
+
throw new Error('project_tasks request aborted');
|
|
92
|
+
}
|
|
27
93
|
const { projectPath, projectPathDefaulted } = resolveProjectPathForTasks(args);
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const limit = typeof args.limit === 'number' ? args.limit : undefined;
|
|
31
|
-
const tasks = await db.listProjectTasks(projectPath, {
|
|
32
|
-
status,
|
|
33
|
-
source,
|
|
34
|
-
limit
|
|
35
|
-
});
|
|
94
|
+
const dedupKey = buildReadDedupKey(action, args, projectPath);
|
|
95
|
+
const tasks = await withReadDedup(dedupKey, () => db.listProjectTasks(projectPath, parseListTaskOptions(args)));
|
|
36
96
|
return {
|
|
37
97
|
success: true,
|
|
38
98
|
projectPath,
|
|
@@ -42,7 +102,26 @@ export async function handleProjectTasks(args) {
|
|
|
42
102
|
note: 'Tasks and analyzer configs persist across sync_index reset; cached audits, code maps, and schema overlays are cleared to avoid stale code references.'
|
|
43
103
|
};
|
|
44
104
|
}
|
|
105
|
+
case 'list_tree': {
|
|
106
|
+
if (options?.signal?.aborted) {
|
|
107
|
+
throw new Error('project_tasks request aborted');
|
|
108
|
+
}
|
|
109
|
+
const { projectPath, projectPathDefaulted } = resolveProjectPathForTasks(args);
|
|
110
|
+
const listOptions = parseListTaskOptions(args);
|
|
111
|
+
const dedupKey = buildReadDedupKey(action, args, projectPath);
|
|
112
|
+
const tree = await withReadDedup(dedupKey, () => db.listProjectTasksTree(projectPath, listOptions));
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
projectPath,
|
|
116
|
+
projectPathDefaulted,
|
|
117
|
+
count: tree.length,
|
|
118
|
+
tree
|
|
119
|
+
};
|
|
120
|
+
}
|
|
45
121
|
case 'create': {
|
|
122
|
+
if (options?.signal?.aborted) {
|
|
123
|
+
throw new Error('project_tasks request aborted');
|
|
124
|
+
}
|
|
46
125
|
const { projectPath, projectPathDefaulted } = resolveProjectPathForTasks(args);
|
|
47
126
|
const title = typeof args.title === 'string' ? args.title.trim() : '';
|
|
48
127
|
if (!title) {
|
|
@@ -79,17 +158,24 @@ export async function handleProjectTasks(args) {
|
|
|
79
158
|
return { success: true, projectPathDefaulted, task };
|
|
80
159
|
}
|
|
81
160
|
case 'get': {
|
|
161
|
+
if (options?.signal?.aborted) {
|
|
162
|
+
throw new Error('project_tasks request aborted');
|
|
163
|
+
}
|
|
82
164
|
const taskId = args.taskId;
|
|
83
165
|
if (!taskId) {
|
|
84
166
|
return { success: false, error: 'taskId is required for get' };
|
|
85
167
|
}
|
|
86
|
-
const
|
|
168
|
+
const dedupKey = buildReadDedupKey(action, args);
|
|
169
|
+
const task = await withReadDedup(dedupKey, () => db.getProjectTask(taskId));
|
|
87
170
|
if (!task) {
|
|
88
171
|
return { success: false, error: `Task not found: ${taskId}` };
|
|
89
172
|
}
|
|
90
173
|
return { success: true, task };
|
|
91
174
|
}
|
|
92
175
|
case 'update': {
|
|
176
|
+
if (options?.signal?.aborted) {
|
|
177
|
+
throw new Error('project_tasks request aborted');
|
|
178
|
+
}
|
|
93
179
|
const taskId = args.taskId;
|
|
94
180
|
if (!taskId) {
|
|
95
181
|
return { success: false, error: 'taskId is required for update' };
|
|
@@ -100,12 +186,30 @@ export async function handleProjectTasks(args) {
|
|
|
100
186
|
}
|
|
101
187
|
return { success: true, task };
|
|
102
188
|
}
|
|
189
|
+
case 'complete_task': {
|
|
190
|
+
if (options?.signal?.aborted) {
|
|
191
|
+
throw new Error('project_tasks request aborted');
|
|
192
|
+
}
|
|
193
|
+
const taskId = args.taskId;
|
|
194
|
+
if (!taskId) {
|
|
195
|
+
return { success: false, error: 'taskId is required for complete_task' };
|
|
196
|
+
}
|
|
197
|
+
const result = await db.completeProjectTask(taskId);
|
|
198
|
+
if (!result) {
|
|
199
|
+
return { success: false, error: `Task not found: ${taskId}` };
|
|
200
|
+
}
|
|
201
|
+
return { success: true, ...result };
|
|
202
|
+
}
|
|
103
203
|
case 'delete': {
|
|
204
|
+
if (options?.signal?.aborted) {
|
|
205
|
+
throw new Error('project_tasks request aborted');
|
|
206
|
+
}
|
|
104
207
|
const taskId = args.taskId;
|
|
105
208
|
if (!taskId) {
|
|
106
209
|
return { success: false, error: 'taskId is required for delete' };
|
|
107
210
|
}
|
|
108
|
-
const
|
|
211
|
+
const mode = args.mode;
|
|
212
|
+
const deleted = await db.deleteProjectTask(taskId, mode);
|
|
109
213
|
return {
|
|
110
214
|
success: deleted,
|
|
111
215
|
taskId,
|
|
@@ -115,7 +219,7 @@ export async function handleProjectTasks(args) {
|
|
|
115
219
|
default:
|
|
116
220
|
return {
|
|
117
221
|
success: false,
|
|
118
|
-
error: `Unknown action "${action}". Use list, create, get, update, or delete.`
|
|
222
|
+
error: `Unknown action "${action}". Use list, list_tree, create, get, update, complete_task, or delete.`
|
|
119
223
|
};
|
|
120
224
|
}
|
|
121
225
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectTasks.js","sourceRoot":"","sources":["../../src/mcp-tools/projectTasks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"projectTasks.js","sourceRoot":"","sources":["../../src/mcp-tools/projectTasks.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp.js
CHANGED
|
@@ -482,8 +482,16 @@ const tools = [
|
|
|
482
482
|
name: 'action',
|
|
483
483
|
type: 'string',
|
|
484
484
|
required: true,
|
|
485
|
-
description: 'list | create | get | update | delete. list/create use projectPath or default to process.cwd(); create
|
|
486
|
-
enum: [
|
|
485
|
+
description: 'list | list_tree | create | get | update | complete_task | delete. list/list_tree/create use projectPath or default to process.cwd(); create needs title; get/update/complete_task/delete need taskId; update needs patch object.',
|
|
486
|
+
enum: [
|
|
487
|
+
'list',
|
|
488
|
+
'list_tree',
|
|
489
|
+
'create',
|
|
490
|
+
'get',
|
|
491
|
+
'update',
|
|
492
|
+
'complete_task',
|
|
493
|
+
'delete'
|
|
494
|
+
],
|
|
487
495
|
},
|
|
488
496
|
{
|
|
489
497
|
name: 'projectPath',
|
|
@@ -495,7 +503,7 @@ const tools = [
|
|
|
495
503
|
name: 'taskId',
|
|
496
504
|
type: 'string',
|
|
497
505
|
required: false,
|
|
498
|
-
description: 'Stable task id (UUID). Required for get, update, delete.',
|
|
506
|
+
description: 'Stable task id (UUID). Required for get, update, complete_task, delete.',
|
|
499
507
|
},
|
|
500
508
|
{
|
|
501
509
|
name: 'title',
|
|
@@ -554,6 +562,42 @@ const tools = [
|
|
|
554
562
|
required: false,
|
|
555
563
|
description: 'Task IDs this item is blocked by (waiting-on).',
|
|
556
564
|
},
|
|
565
|
+
{
|
|
566
|
+
name: 'label',
|
|
567
|
+
type: 'string',
|
|
568
|
+
required: false,
|
|
569
|
+
description: 'Filter/search by label value.',
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
name: 'blockedByTaskId',
|
|
573
|
+
type: 'string',
|
|
574
|
+
required: false,
|
|
575
|
+
description: 'Filter tasks blocked by this task ID.',
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
name: 'query',
|
|
579
|
+
type: 'string',
|
|
580
|
+
required: false,
|
|
581
|
+
description: 'Case-insensitive text search across title/description/labels/files/symbols.',
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
name: 'hasChildren',
|
|
585
|
+
type: 'boolean',
|
|
586
|
+
required: false,
|
|
587
|
+
description: 'Filter tasks that do/do not have direct subtasks.',
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
name: 'overdueOnly',
|
|
591
|
+
type: 'boolean',
|
|
592
|
+
required: false,
|
|
593
|
+
description: 'Filter tasks with dueAt in the past and not closed.',
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: 'actionableOnly',
|
|
597
|
+
type: 'boolean',
|
|
598
|
+
required: false,
|
|
599
|
+
description: 'Filter tasks that are open and unblocked by open dependencies.',
|
|
600
|
+
},
|
|
557
601
|
{
|
|
558
602
|
name: 'dueAt',
|
|
559
603
|
type: 'string',
|
|
@@ -590,9 +634,90 @@ const tools = [
|
|
|
590
634
|
required: false,
|
|
591
635
|
description: 'Max tasks to return for list (default 500, max 1000).',
|
|
592
636
|
},
|
|
637
|
+
{
|
|
638
|
+
name: 'mode',
|
|
639
|
+
type: 'string',
|
|
640
|
+
required: false,
|
|
641
|
+
description: 'Delete mode: reject (default), detach subtasks, or cascade descendants.',
|
|
642
|
+
enum: ['reject', 'detach', 'cascade'],
|
|
643
|
+
},
|
|
593
644
|
],
|
|
594
645
|
},
|
|
595
646
|
];
|
|
647
|
+
class RequestAbortedError extends Error {
|
|
648
|
+
constructor(message = 'MCP request aborted') {
|
|
649
|
+
super(message);
|
|
650
|
+
this.name = 'RequestAbortedError';
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
function throwIfRequestAborted(signal, phase) {
|
|
654
|
+
if (!signal?.aborted) {
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
throw new RequestAbortedError(`Request aborted${phase ? ` during ${phase}` : ''}`);
|
|
658
|
+
}
|
|
659
|
+
async function withAbortSignal(signal, phase, op) {
|
|
660
|
+
throwIfRequestAborted(signal, phase);
|
|
661
|
+
if (!signal) {
|
|
662
|
+
return op();
|
|
663
|
+
}
|
|
664
|
+
return await new Promise((resolve, reject) => {
|
|
665
|
+
const onAbort = () => reject(new RequestAbortedError(`Request aborted during ${phase}`));
|
|
666
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
667
|
+
void op()
|
|
668
|
+
.then(resolve)
|
|
669
|
+
.catch(reject)
|
|
670
|
+
.finally(() => {
|
|
671
|
+
signal.removeEventListener('abort', onAbort);
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
function serializeForMcp(value) {
|
|
676
|
+
try {
|
|
677
|
+
return JSON.stringify(value);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
return JSON.stringify({
|
|
681
|
+
success: false,
|
|
682
|
+
error: `Failed to serialize MCP response: ${error instanceof Error ? error.message : String(error)}`
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function safeJson(value) {
|
|
687
|
+
try {
|
|
688
|
+
return JSON.stringify(value, null, 2);
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
return `[unserializable: ${error instanceof Error ? error.message : String(error)}]`;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
function registerProcessReliabilityHandlers() {
|
|
695
|
+
const g = globalThis;
|
|
696
|
+
const exitOnFatal = process.env.CODE_AUDITOR_EXIT_ON_FATAL === '1' ||
|
|
697
|
+
process.env.CODE_AUDITOR_EXIT_ON_FATAL === 'true';
|
|
698
|
+
if (!g.__codeAuditorUncaughtExceptionHandlerInstalled) {
|
|
699
|
+
process.on('uncaughtException', (error) => {
|
|
700
|
+
console.error(chalk.red('[ERROR]'), 'Uncaught exception:', error);
|
|
701
|
+
console.error(chalk.red('[ERROR]'), 'Stack:', error.stack);
|
|
702
|
+
console.error(chalk.red('[ERROR]'), 'Error details:', safeJson(error));
|
|
703
|
+
if (exitOnFatal) {
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
g.__codeAuditorUncaughtExceptionHandlerInstalled = true;
|
|
708
|
+
}
|
|
709
|
+
if (!g.__codeAuditorUnhandledRejectionHandlerInstalled) {
|
|
710
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
711
|
+
console.error(chalk.red('[ERROR]'), 'Unhandled rejection at:', promise);
|
|
712
|
+
console.error(chalk.red('[ERROR]'), 'Reason:', reason);
|
|
713
|
+
console.error(chalk.red('[ERROR]'), 'Rejection details:', safeJson(reason));
|
|
714
|
+
if (exitOnFatal) {
|
|
715
|
+
process.exit(1);
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
g.__codeAuditorUnhandledRejectionHandlerInstalled = true;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
596
721
|
async function startMcpServer() {
|
|
597
722
|
logMcpInfo('startup', `code-auditor-mcp ${PACKAGE_VERSION} (stdio)`, {
|
|
598
723
|
pid: process.pid,
|
|
@@ -654,10 +779,13 @@ async function startMcpServer() {
|
|
|
654
779
|
mcpTraceStderr(chalk.blue('[DEBUG]'), 'initialize response', JSON.stringify(response, null, 2));
|
|
655
780
|
return response;
|
|
656
781
|
});
|
|
657
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
658
|
-
mcpTraceStderr(chalk.blue('[DEBUG]'), 'CallTool raw', JSON.stringify(request, null, 2));
|
|
782
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
659
783
|
const { name, arguments: args } = request.params;
|
|
660
|
-
mcpTraceStderr(chalk.blue('[DEBUG]'), `CallTool ${name}`, JSON.stringify(
|
|
784
|
+
mcpTraceStderr(chalk.blue('[DEBUG]'), `CallTool ${name}`, JSON.stringify({
|
|
785
|
+
argKeys: args && typeof args === 'object' ? Object.keys(args) : [],
|
|
786
|
+
hasArgs: !!args
|
|
787
|
+
}));
|
|
788
|
+
const requestSignal = extra?.signal;
|
|
661
789
|
const toolStartedAt = Date.now();
|
|
662
790
|
try {
|
|
663
791
|
if (name !== 'audit_status') {
|
|
@@ -668,13 +796,14 @@ async function startMcpServer() {
|
|
|
668
796
|
});
|
|
669
797
|
}
|
|
670
798
|
let result;
|
|
799
|
+
throwIfRequestAborted(requestSignal, `start ${name}`);
|
|
671
800
|
switch (name) {
|
|
672
801
|
case 'start_audit': {
|
|
673
|
-
result = await startAuditJob(args, {
|
|
802
|
+
result = await withAbortSignal(requestSignal, 'start_audit', () => startAuditJob(args, {
|
|
674
803
|
defaultAnalyzers: ['solid', 'dry', 'documentation', 'react', 'data-access'],
|
|
675
804
|
defaultMinSeverity: 'warning',
|
|
676
805
|
defaultGenerateCodeMap: false,
|
|
677
|
-
});
|
|
806
|
+
}));
|
|
678
807
|
break;
|
|
679
808
|
}
|
|
680
809
|
case 'audit_status': {
|
|
@@ -686,11 +815,11 @@ async function startMcpServer() {
|
|
|
686
815
|
break;
|
|
687
816
|
}
|
|
688
817
|
case 'audit_results': {
|
|
689
|
-
result = await getAuditResultsPage(args);
|
|
818
|
+
result = await withAbortSignal(requestSignal, 'audit_results', () => getAuditResultsPage(args));
|
|
690
819
|
break;
|
|
691
820
|
}
|
|
692
821
|
case 'audit': {
|
|
693
|
-
result = await getAuditResultsPage(args);
|
|
822
|
+
result = await withAbortSignal(requestSignal, 'audit', () => getAuditResultsPage(args));
|
|
694
823
|
break;
|
|
695
824
|
}
|
|
696
825
|
case 'audit_health': {
|
|
@@ -1160,7 +1289,9 @@ async function startMcpServer() {
|
|
|
1160
1289
|
}
|
|
1161
1290
|
case 'project_tasks': {
|
|
1162
1291
|
const { handleProjectTasks } = await import('./mcp-tools/projectTasks.js');
|
|
1163
|
-
result = await handleProjectTasks((args || {})
|
|
1292
|
+
result = await withAbortSignal(requestSignal, 'project_tasks', () => handleProjectTasks((args || {}), {
|
|
1293
|
+
signal: requestSignal
|
|
1294
|
+
}));
|
|
1164
1295
|
break;
|
|
1165
1296
|
}
|
|
1166
1297
|
default:
|
|
@@ -1170,14 +1301,23 @@ async function startMcpServer() {
|
|
|
1170
1301
|
content: [
|
|
1171
1302
|
{
|
|
1172
1303
|
type: 'text',
|
|
1173
|
-
text:
|
|
1304
|
+
text: serializeForMcp(result),
|
|
1174
1305
|
},
|
|
1175
1306
|
],
|
|
1176
1307
|
};
|
|
1177
|
-
mcpTraceStderr(chalk.blue('[DEBUG]'), `Tool ${name} ok`,
|
|
1308
|
+
mcpTraceStderr(chalk.blue('[DEBUG]'), `Tool ${name} ok`, `responseBytes=${response.content[0].text.length}`);
|
|
1309
|
+
throwIfRequestAborted(requestSignal, `before response ${name}`);
|
|
1178
1310
|
return response;
|
|
1179
1311
|
}
|
|
1180
1312
|
catch (error) {
|
|
1313
|
+
if (error instanceof RequestAbortedError) {
|
|
1314
|
+
if (name !== 'audit_status') {
|
|
1315
|
+
logMcpDebug('tool', `call ${name} aborted`, {
|
|
1316
|
+
ms: Date.now() - toolStartedAt
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
throw error;
|
|
1320
|
+
}
|
|
1181
1321
|
console.error(chalk.red('[ERROR]'), `Tool ${name} execution failed:`, error);
|
|
1182
1322
|
console.error(chalk.red('[ERROR]'), 'Error stack:', error instanceof Error ? error.stack : 'No stack trace');
|
|
1183
1323
|
if (name !== 'audit_status') {
|
|
@@ -1190,7 +1330,7 @@ async function startMcpServer() {
|
|
|
1190
1330
|
content: [
|
|
1191
1331
|
{
|
|
1192
1332
|
type: 'text',
|
|
1193
|
-
text:
|
|
1333
|
+
text: serializeForMcp(formatMcpToolErrorPayload(name, error)),
|
|
1194
1334
|
},
|
|
1195
1335
|
],
|
|
1196
1336
|
isError: true,
|
|
@@ -1279,27 +1419,15 @@ function getHealthRecommendation(score, result) {
|
|
|
1279
1419
|
}
|
|
1280
1420
|
return 'Code health needs attention - run detailed audit';
|
|
1281
1421
|
}
|
|
1282
|
-
|
|
1283
|
-
process.on('uncaughtException', (error) => {
|
|
1284
|
-
console.error(chalk.red('[ERROR]'), 'Uncaught exception:', error);
|
|
1285
|
-
console.error(chalk.red('[ERROR]'), 'Stack:', error.stack);
|
|
1286
|
-
console.error(chalk.red('[ERROR]'), 'Error details:', JSON.stringify(error, null, 2));
|
|
1287
|
-
process.exit(1);
|
|
1288
|
-
});
|
|
1289
|
-
process.on('unhandledRejection', (reason, promise) => {
|
|
1290
|
-
console.error(chalk.red('[ERROR]'), 'Unhandled rejection at:', promise);
|
|
1291
|
-
console.error(chalk.red('[ERROR]'), 'Reason:', reason);
|
|
1292
|
-
console.error(chalk.red('[ERROR]'), 'Rejection details:', JSON.stringify(reason, null, 2));
|
|
1293
|
-
process.exit(1);
|
|
1294
|
-
});
|
|
1422
|
+
registerProcessReliabilityHandlers();
|
|
1295
1423
|
// Add SIGTERM and SIGINT handlers
|
|
1296
1424
|
process.on('SIGTERM', () => {
|
|
1297
1425
|
console.error(chalk.yellow('[WARN]'), 'Received SIGTERM, shutting down gracefully...');
|
|
1298
|
-
process.
|
|
1426
|
+
process.exitCode = 0;
|
|
1299
1427
|
});
|
|
1300
1428
|
process.on('SIGINT', () => {
|
|
1301
1429
|
console.error(chalk.yellow('[WARN]'), 'Received SIGINT, shutting down gracefully...');
|
|
1302
|
-
process.
|
|
1430
|
+
process.exitCode = 0;
|
|
1303
1431
|
});
|
|
1304
1432
|
// Log when stdin/stdout events occur
|
|
1305
1433
|
process.stdin.on('error', (error) => {
|
|
@@ -1311,6 +1439,6 @@ process.stdout.on('error', (error) => {
|
|
|
1311
1439
|
startMcpServer().catch(error => {
|
|
1312
1440
|
console.error(chalk.red('[ERROR]'), 'Failed to start MCP server:', error);
|
|
1313
1441
|
console.error(chalk.red('[ERROR]'), 'Stack:', error.stack);
|
|
1314
|
-
process.
|
|
1442
|
+
process.exitCode = 1;
|
|
1315
1443
|
});
|
|
1316
1444
|
//# sourceMappingURL=mcp.js.map
|