git-push-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.
@@ -0,0 +1,603 @@
1
+ const { NaturalLanguageProcessor } = require('./nlp-processor');
2
+ const { GitOperator } = require('./git-operator');
3
+ const winston = require('winston');
4
+
5
+ class MCPHandler {
6
+ constructor() {
7
+ // 配置日志
8
+ this.logger = winston.createLogger({
9
+ level: process.env.LOG_LEVEL || 'info',
10
+ format: winston.format.combine(
11
+ winston.format.timestamp(),
12
+ winston.format.errors({ stack: true }),
13
+ winston.format.json()
14
+ ),
15
+ defaultMeta: { service: 'git-push-mcp' },
16
+ transports: [
17
+ new winston.transports.Console({
18
+ format: winston.format.simple()
19
+ })
20
+ ]
21
+ });
22
+
23
+ // 初始化组件,传入logger
24
+ this.nlpProcessor = new NaturalLanguageProcessor(this.logger);
25
+ this.gitOperator = new GitOperator(this.logger);
26
+
27
+ // 支持的操作映射
28
+ this.actionHandlers = {
29
+ commit: this.handleCommit.bind(this),
30
+ add: this.handleAdd.bind(this),
31
+ status: this.handleStatus.bind(this),
32
+ log: this.handleLog.bind(this),
33
+ diff: this.handleDiff.bind(this),
34
+ branch: this.handleBranch.bind(this)
35
+ };
36
+ }
37
+
38
+ /**
39
+ * 处理自然语言请求(新的SDK接口)
40
+ */
41
+ async processNaturalLanguage(text, context = {}) {
42
+ try {
43
+ // 检查是否为Git仓库
44
+ const repoCheck = await this.gitOperator.checkRepository();
45
+ if (!repoCheck.isRepository) {
46
+ return {
47
+ success: false,
48
+ error: '当前目录不是Git仓库',
49
+ suggestion: '请在Git仓库目录中运行此工具',
50
+ service: 'git-push-mcp'
51
+ };
52
+ }
53
+
54
+ // 解析自然语言命令
55
+ const parsedCommand = this.nlpProcessor.parseCommand(text);
56
+ this.logger.info('解析结果', {
57
+ ...parsedCommand,
58
+ originalText: text,
59
+ service: 'git-push-mcp'
60
+ });
61
+
62
+ // 处理命令
63
+ const handler = this.actionHandlers[parsedCommand.command];
64
+ if (handler) {
65
+ const result = await handler(parsedCommand, context);
66
+ return {
67
+ success: true,
68
+ action: parsedCommand.command,
69
+ message: result.message,
70
+ details: result.details,
71
+ service: 'git-push-mcp'
72
+ };
73
+ } else {
74
+ return {
75
+ success: false,
76
+ error: `不支持的命令: ${parsedCommand.command}`,
77
+ service: 'git-push-mcp'
78
+ };
79
+ }
80
+ } catch (error) {
81
+ this.logger.error('处理请求失败', {
82
+ error: error.message,
83
+ stack: error.stack,
84
+ service: 'git-push-mcp'
85
+ });
86
+ return {
87
+ success: false,
88
+ error: error.message,
89
+ service: 'git-push-mcp'
90
+ };
91
+ }
92
+ }
93
+
94
+ /**
95
+ * 获取Git状态(新的SDK接口)
96
+ */
97
+ async getGitStatus() {
98
+ try {
99
+ const repoCheck = await this.gitOperator.checkRepository();
100
+ if (!repoCheck.isRepository) {
101
+ return {
102
+ success: false,
103
+ error: '当前目录不是Git仓库',
104
+ service: 'git-push-mcp'
105
+ };
106
+ }
107
+
108
+ this.logger.info('开始获取Git状态', { service: 'git-push-mcp' });
109
+ const status = await this.gitOperator.getStatus();
110
+ this.logger.info('Git状态获取成功', { status, service: 'git-push-mcp' });
111
+
112
+ return {
113
+ success: true,
114
+ action: 'status',
115
+ details: status,
116
+ service: 'git-push-mcp'
117
+ };
118
+ } catch (error) {
119
+ this.logger.error('获取状态失败详情', {
120
+ error: error.message,
121
+ stack: error.stack,
122
+ typeofError: typeof error,
123
+ errorKeys: Object.keys(error || {}),
124
+ service: 'git-push-mcp'
125
+ });
126
+ return {
127
+ success: false,
128
+ error: error.message,
129
+ service: 'git-push-mcp'
130
+ };
131
+ }
132
+ }
133
+
134
+ /**
135
+ * 提交更改(新的SDK接口)
136
+ */
137
+ async commitChanges(message, files = [], stageAll = true) {
138
+ try {
139
+ const repoCheck = await this.gitOperator.checkRepository();
140
+ if (!repoCheck.isRepository) {
141
+ return {
142
+ success: false,
143
+ error: '当前目录不是Git仓库',
144
+ service: 'git-push-mcp'
145
+ };
146
+ }
147
+
148
+ let result;
149
+ if (stageAll) {
150
+ result = await this.gitOperator.addAllAndCommit(message);
151
+ } else if (files && files.length > 0) {
152
+ result = await this.gitOperator.addFilesAndCommit(files, message);
153
+ } else {
154
+ result = await this.gitOperator.commit(message);
155
+ }
156
+
157
+ return {
158
+ success: true,
159
+ action: 'commit',
160
+ message: result.summary,
161
+ details: result,
162
+ service: 'git-push-mcp'
163
+ };
164
+ } catch (error) {
165
+ this.logger.error('提交失败', {
166
+ error: error.message,
167
+ service: 'git-push-mcp'
168
+ });
169
+ return {
170
+ success: false,
171
+ error: error.message,
172
+ service: 'git-push-mcp'
173
+ };
174
+ }
175
+ }
176
+
177
+ /**
178
+ * 推送更改(新的SDK接口)
179
+ */
180
+ async pushChanges(remote = 'origin', branch) {
181
+ try {
182
+ const repoCheck = await this.gitOperator.checkRepository();
183
+ if (!repoCheck.isRepository) {
184
+ return {
185
+ success: false,
186
+ error: '当前目录不是Git仓库',
187
+ service: 'git-push-mcp'
188
+ };
189
+ }
190
+
191
+ const result = await this.gitOperator.push(remote, branch);
192
+
193
+ return {
194
+ success: true,
195
+ action: 'push',
196
+ message: result.pushed ? '推送成功' : '无需推送',
197
+ details: result,
198
+ service: 'git-push-mcp'
199
+ };
200
+ } catch (error) {
201
+ this.logger.error('推送失败', {
202
+ error: error.message,
203
+ service: 'git-push-mcp'
204
+ });
205
+ return {
206
+ success: false,
207
+ error: error.message,
208
+ service: 'git-push-mcp'
209
+ };
210
+ }
211
+ }
212
+
213
+ /**
214
+ * 处理MCP请求
215
+ */
216
+ async processRequest(request) {
217
+ const { command, text, context = {} } = request;
218
+
219
+ try {
220
+ // 检查是否为Git仓库
221
+ const repoCheck = await this.gitOperator.checkRepository();
222
+ if (!repoCheck.isRepository) {
223
+ return {
224
+ success: false,
225
+ error: '当前目录不是Git仓库',
226
+ suggestion: '请在Git仓库目录中运行此工具',
227
+ timestamp: new Date().toISOString()
228
+ };
229
+ }
230
+
231
+ switch (command) {
232
+ case 'process_natural_language':
233
+ return await this.processNaturalLanguage(text, context);
234
+
235
+ case 'execute_action':
236
+ return await this.executeAction(request.action, request.params);
237
+
238
+ case 'get_capabilities':
239
+ return this.getCapabilities();
240
+
241
+ default:
242
+ return {
243
+ success: false,
244
+ error: `不支持的命令: ${command}`,
245
+ timestamp: new Date().toISOString()
246
+ };
247
+ }
248
+ } catch (error) {
249
+ this.logger.error('处理请求时出错:', error);
250
+ return {
251
+ success: false,
252
+ error: error.message,
253
+ timestamp: new Date().toISOString()
254
+ };
255
+ }
256
+ }
257
+
258
+ /**
259
+ * 处理自然语言输入
260
+ */
261
+ async processNaturalLanguage(text, context) {
262
+ // 解析自然语言命令
263
+ const parsedCommand = this.nlpProcessor.parseCommand(text);
264
+ this.logger.info('解析结果:', parsedCommand);
265
+
266
+ // 根据解析结果执行相应操作
267
+ const handler = this.actionHandlers[parsedCommand.command];
268
+ if (handler) {
269
+ return await handler(parsedCommand, context);
270
+ }
271
+
272
+ return {
273
+ success: false,
274
+ error: `无法识别的命令: ${parsedCommand.command}`,
275
+ parsed: parsedCommand,
276
+ timestamp: new Date().toISOString()
277
+ };
278
+ }
279
+
280
+ /**
281
+ * 处理提交操作
282
+ */
283
+ async handleCommit(parsedCommand, context) {
284
+ const { message, commitType } = parsedCommand;
285
+ const { autoStage = true, autoPush = false, conventionalCommits = true } = context;
286
+
287
+ try {
288
+ // 获取当前状态
289
+ const statusResult = await this.gitOperator.getStatus();
290
+ if (!statusResult.success) {
291
+ return statusResult;
292
+ }
293
+
294
+ const status = statusResult.data;
295
+
296
+ // 检查是否有更改需要提交
297
+ if (status.isClean) {
298
+ return {
299
+ success: false,
300
+ error: '没有需要提交的更改',
301
+ suggestion: '请先修改一些文件再提交',
302
+ action: 'status_check',
303
+ timestamp: new Date().toISOString()
304
+ };
305
+ }
306
+
307
+ // 自动暂存文件(如果启用)
308
+ if (autoStage && ((status.not_added && status.not_added.length > 0) ||
309
+ (status.modified && status.modified.length > 0))) {
310
+ const addResult = await this.gitOperator.addFiles('.');
311
+ if (!addResult.success) {
312
+ return addResult;
313
+ }
314
+ }
315
+
316
+ // 格式化提交消息
317
+ const formattedMessage = conventionalCommits
318
+ ? this.nlpProcessor.formatCommitMessage(parsedCommand, true)
319
+ : message;
320
+
321
+ // 执行提交
322
+ const commitResult = await this.gitOperator.commit(formattedMessage);
323
+ if (!commitResult.success) {
324
+ return commitResult;
325
+ }
326
+
327
+ // 自动推送(如果启用)
328
+ let pushResult = null;
329
+ if (autoPush) {
330
+ pushResult = await this.gitOperator.push();
331
+ if (!pushResult.success) {
332
+ return {
333
+ ...pushResult,
334
+ warning: '提交成功但推送失败,请手动推送'
335
+ };
336
+ }
337
+ }
338
+
339
+ return {
340
+ success: true,
341
+ action: 'commit',
342
+ message: formattedMessage,
343
+ details: commitResult.data,
344
+ changes: {
345
+ filesChanged: (status.modified ? status.modified.length : 0) +
346
+ (status.created ? status.created.length : 0) +
347
+ (status.deleted ? status.deleted.length : 0),
348
+ filesStaged: status.staged ? status.staged.length : 0
349
+ },
350
+ pushed: autoPush && pushResult?.success,
351
+ timestamp: new Date().toISOString()
352
+ };
353
+
354
+ } catch (error) {
355
+ this.logger.error('提交过程中出错:', error);
356
+ return {
357
+ success: false,
358
+ error: error.message,
359
+ action: 'commit',
360
+ timestamp: new Date().toISOString()
361
+ };
362
+ }
363
+ }
364
+
365
+ /**
366
+ * 处理添加文件操作
367
+ */
368
+ async handleAdd(parsedCommand, context) {
369
+ try {
370
+ const { message } = parsedCommand;
371
+ const files = message || '.';
372
+
373
+ const result = await this.gitOperator.addFiles(files);
374
+
375
+ if (result.success) {
376
+ return {
377
+ success: true,
378
+ action: 'add',
379
+ message: result.message,
380
+ files: files,
381
+ timestamp: new Date().toISOString()
382
+ };
383
+ }
384
+
385
+ return result;
386
+ } catch (error) {
387
+ return {
388
+ success: false,
389
+ error: error.message,
390
+ action: 'add',
391
+ timestamp: new Date().toISOString()
392
+ };
393
+ }
394
+ }
395
+
396
+ /**
397
+ * 处理状态查询操作
398
+ */
399
+ async handleStatus(parsedCommand, context) {
400
+ try {
401
+ const result = await this.gitOperator.getStatus();
402
+
403
+ if (result.success) {
404
+ const status = result.data;
405
+
406
+ return {
407
+ success: true,
408
+ action: 'status',
409
+ message: status.isClean ? '工作区干净,没有待提交的更改' : '发现待提交的更改',
410
+ details: {
411
+ isClean: status.isClean,
412
+ currentBranch: status.current,
413
+ tracking: status.tracking,
414
+ changes: {
415
+ modified: status.modified.length,
416
+ created: status.created.length,
417
+ deleted: status.deleted.length,
418
+ staged: status.staged.length,
419
+ untracked: status.not_added.length
420
+ }
421
+ },
422
+ files: {
423
+ modified: status.modified,
424
+ created: status.created,
425
+ deleted: status.deleted,
426
+ staged: status.staged,
427
+ untracked: status.not_added
428
+ },
429
+ timestamp: new Date().toISOString()
430
+ };
431
+ }
432
+
433
+ return result;
434
+ } catch (error) {
435
+ return {
436
+ success: false,
437
+ error: error.message,
438
+ action: 'status',
439
+ timestamp: new Date().toISOString()
440
+ };
441
+ }
442
+ }
443
+
444
+ /**
445
+ * 处理日志查询操作
446
+ */
447
+ async handleLog(parsedCommand, context) {
448
+ try {
449
+ const { limit = 10 } = context;
450
+ const result = await this.gitOperator.getLog(limit);
451
+
452
+ if (result.success) {
453
+ return {
454
+ success: true,
455
+ action: 'log',
456
+ commits: result.data,
457
+ count: result.data.length,
458
+ timestamp: new Date().toISOString()
459
+ };
460
+ }
461
+
462
+ return result;
463
+ } catch (error) {
464
+ return {
465
+ success: false,
466
+ error: error.message,
467
+ action: 'log',
468
+ timestamp: new Date().toISOString()
469
+ };
470
+ }
471
+ }
472
+
473
+ /**
474
+ * 处理差异查询操作
475
+ */
476
+ async handleDiff(parsedCommand, context) {
477
+ try {
478
+ const result = await this.gitOperator.getDiff();
479
+
480
+ if (result.success) {
481
+ return {
482
+ success: true,
483
+ action: 'diff',
484
+ diff: result.data,
485
+ timestamp: new Date().toISOString()
486
+ };
487
+ }
488
+
489
+ return result;
490
+ } catch (error) {
491
+ return {
492
+ success: false,
493
+ error: error.message,
494
+ action: 'diff',
495
+ timestamp: new Date().toISOString()
496
+ };
497
+ }
498
+ }
499
+
500
+ /**
501
+ * 处理分支操作
502
+ */
503
+ async handleBranch(parsedCommand, context) {
504
+ try {
505
+ const { message } = parsedCommand;
506
+ const { action = 'list' } = context;
507
+
508
+ switch (action) {
509
+ case 'create':
510
+ if (!message) {
511
+ return {
512
+ success: false,
513
+ error: '请指定分支名称',
514
+ timestamp: new Date().toISOString()
515
+ };
516
+ }
517
+ return await this.gitOperator.createBranch(message);
518
+
519
+ case 'checkout':
520
+ if (!message) {
521
+ return {
522
+ success: false,
523
+ error: '请指定要切换的分支名称',
524
+ timestamp: new Date().toISOString()
525
+ };
526
+ }
527
+ return await this.gitOperator.checkoutBranch(message);
528
+
529
+ case 'list':
530
+ default:
531
+ const result = await this.gitOperator.getBranches();
532
+ if (result.success) {
533
+ return {
534
+ success: true,
535
+ action: 'branch_list',
536
+ branches: result.data,
537
+ timestamp: new Date().toISOString()
538
+ };
539
+ }
540
+ return result;
541
+ }
542
+ } catch (error) {
543
+ return {
544
+ success: false,
545
+ error: error.message,
546
+ action: 'branch',
547
+ timestamp: new Date().toISOString()
548
+ };
549
+ }
550
+ }
551
+
552
+ /**
553
+ * 直接执行特定操作
554
+ */
555
+ async executeAction(action, params = {}) {
556
+ const handler = this.actionHandlers[action];
557
+ if (!handler) {
558
+ return {
559
+ success: false,
560
+ error: `不支持的操作: ${action}`,
561
+ timestamp: new Date().toISOString()
562
+ };
563
+ }
564
+
565
+ // 构造伪解析命令对象
566
+ const pseudoCommand = {
567
+ command: action,
568
+ message: params.message || '',
569
+ commitType: params.commitType || null
570
+ };
571
+
572
+ return await handler(pseudoCommand, params.context || {});
573
+ }
574
+
575
+ /**
576
+ * 获取工具能力列表
577
+ */
578
+ getCapabilities() {
579
+ return {
580
+ success: true,
581
+ capabilities: {
582
+ naturalLanguage: true,
583
+ gitOperations: [
584
+ 'commit',
585
+ 'add',
586
+ 'status',
587
+ 'log',
588
+ 'diff',
589
+ 'branch'
590
+ ],
591
+ features: [
592
+ '约定式提交',
593
+ '自动暂存',
594
+ '自动推送',
595
+ '智能解析'
596
+ ]
597
+ },
598
+ timestamp: new Date().toISOString()
599
+ };
600
+ }
601
+ }
602
+
603
+ module.exports = { MCPHandler };