@andrebuzeli/git-mcp 2.39.0 → 2.41.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.
@@ -5,15 +5,82 @@ const zod_1 = require("zod");
5
5
  const index_js_1 = require("../providers/index.js");
6
6
  const user_detection_js_1 = require("../utils/user-detection.js");
7
7
  const git_operations_js_1 = require("../utils/git-operations.js");
8
- const GitUpdateProjectInputSchema = zod_1.z.object({
9
- action: zod_1.z.literal('update'),
10
- repo: zod_1.z.string(),
11
- projectPath: zod_1.z.string(),
12
- provider: zod_1.z.enum(['gitea', 'github']),
13
- message: zod_1.z.string().min(1, 'Commit message is required'),
14
- branch: zod_1.z.string().optional(),
15
- forcePush: zod_1.z.boolean().optional()
16
- });
8
+ const GitUpdateProjectInputSchema = zod_1.z.discriminatedUnion('action', [
9
+ // Action: update - commit incremental
10
+ zod_1.z.object({
11
+ action: zod_1.z.literal('update'),
12
+ repo: zod_1.z.string(),
13
+ projectPath: zod_1.z.string(),
14
+ provider: zod_1.z.enum(['gitea', 'github']),
15
+ message: zod_1.z.string().min(1, 'Commit message is required'),
16
+ branch: zod_1.z.string().optional(),
17
+ forcePush: zod_1.z.boolean().optional()
18
+ }),
19
+ // Action: status - verificar status do repositório
20
+ zod_1.z.object({
21
+ action: zod_1.z.literal('status'),
22
+ projectPath: zod_1.z.string(),
23
+ detailed: zod_1.z.boolean().optional()
24
+ }),
25
+ // Action: diff - mostrar diferenças
26
+ zod_1.z.object({
27
+ action: zod_1.z.literal('diff'),
28
+ projectPath: zod_1.z.string(),
29
+ staged: zod_1.z.boolean().optional(),
30
+ nameOnly: zod_1.z.boolean().optional(),
31
+ commit: zod_1.z.string().optional()
32
+ }),
33
+ // Action: log - histórico de commits
34
+ zod_1.z.object({
35
+ action: zod_1.z.literal('log'),
36
+ projectPath: zod_1.z.string(),
37
+ maxCount: zod_1.z.number().optional(),
38
+ oneline: zod_1.z.boolean().optional(),
39
+ branch: zod_1.z.string().optional()
40
+ }),
41
+ // Action: reset - desfazer mudanças
42
+ zod_1.z.object({
43
+ action: zod_1.z.literal('reset'),
44
+ projectPath: zod_1.z.string(),
45
+ mode: zod_1.z.enum(['soft', 'mixed', 'hard']).optional(),
46
+ commit: zod_1.z.string().optional()
47
+ }),
48
+ // Action: stash - gerenciar mudanças temporárias
49
+ zod_1.z.object({
50
+ action: zod_1.z.literal('stash'),
51
+ projectPath: zod_1.z.string(),
52
+ operation: zod_1.z.enum(['save', 'pop', 'apply', 'list', 'drop', 'clear']).optional(),
53
+ message: zod_1.z.string().optional()
54
+ }),
55
+ // Action: pull - atualizar do remoto
56
+ zod_1.z.object({
57
+ action: zod_1.z.literal('pull'),
58
+ projectPath: zod_1.z.string(),
59
+ branch: zod_1.z.string().optional()
60
+ }),
61
+ // Action: sync - sincronização completa (pull + commit + push)
62
+ zod_1.z.object({
63
+ action: zod_1.z.literal('sync'),
64
+ repo: zod_1.z.string(),
65
+ projectPath: zod_1.z.string(),
66
+ provider: zod_1.z.enum(['gitea', 'github']),
67
+ message: zod_1.z.string().min(1, 'Commit message is required'),
68
+ branch: zod_1.z.string().optional(),
69
+ forcePush: zod_1.z.boolean().optional()
70
+ }),
71
+ // Action: init - upload inicial completo (substitui upload-project)
72
+ zod_1.z.object({
73
+ action: zod_1.z.literal('init'),
74
+ repo: zod_1.z.string(),
75
+ projectPath: zod_1.z.string(),
76
+ provider: zod_1.z.enum(['gitea', 'github']),
77
+ message: zod_1.z.string().min(1, 'Commit message is required'),
78
+ branch: zod_1.z.string().optional(),
79
+ createRepo: zod_1.z.boolean().optional(),
80
+ forcePush: zod_1.z.boolean().optional(),
81
+ granular: zod_1.z.boolean().optional() // commits granulares por tipo de arquivo
82
+ })
83
+ ]);
17
84
  const GitUpdateProjectResultSchema = zod_1.z.object({
18
85
  success: zod_1.z.boolean(),
19
86
  action: zod_1.z.string(),
@@ -23,33 +90,68 @@ const GitUpdateProjectResultSchema = zod_1.z.object({
23
90
  });
24
91
  exports.gitUpdateProjectTool = {
25
92
  name: 'git-update-project',
26
- description: 'tool: Atualiza projeto incrementalmente no repositório\\n──────────────\\naction update: detecta mudanças, faz commit e push automático\\naction update requires: repo, provider, projectPath, message\\n───────────────\\nCOMMITS REAIS: Detecta mudanças no diretório local, faz git add, commit e push\\nFunciona apenas em repositórios Git locais com mudanças pendentes\\nPush automático para remote configurado (origin)',
93
+ description: 'tool: Gerenciamento COMPLETO de projetos Git (local + remoto)\\n──────────────\\n9 ACTIONS DISPONÍVEIS:\\n• init: UPLOAD INICIAL completo (substitui upload-project)\\n• update: Commit incremental automático\\n• status: Verificar status do repositório\\n• diff: Mostrar diferenças entre versões\\n log: Histórico de commits\\n• reset: Desfazer mudanças\\n• stash: Gerenciar mudanças temporárias\\n• pull: Atualizar do repositório remoto\\n• sync: Sincronização completa (pull+commit+push)\\n───────────────\\nCOMMITS REAIS + RASTREABILIDADE TOTAL\\nFunciona com GitHub, Gitea e qualquer repositório Git',
27
94
  inputSchema: {
28
95
  type: 'object',
29
96
  properties: {
30
- action: { type: 'string', enum: ['update'], description: 'Action to perform' },
31
- repo: { type: 'string', description: 'Repository name' },
32
- projectPath: { type: 'string', description: 'Local project path' },
33
- provider: { type: 'string', enum: ['gitea', 'github'], description: 'Provider to use' },
34
- message: { type: 'string', description: 'Commit message (required)' },
35
- branch: { type: 'string', description: 'Target branch', default: 'main' },
36
- forcePush: { type: 'boolean', description: 'Force push to remote', default: false }
97
+ action: {
98
+ type: 'string',
99
+ enum: ['init', 'update', 'status', 'diff', 'log', 'reset', 'stash', 'pull', 'sync'],
100
+ description: 'Action to perform'
101
+ },
102
+ // Parâmetros comuns
103
+ repo: { type: 'string', description: 'Repository name (required for init/update/sync)' },
104
+ projectPath: { type: 'string', description: 'Local project path (required for all)' },
105
+ provider: { type: 'string', enum: ['gitea', 'github'], description: 'Provider (required for init/update/sync)' },
106
+ // Parâmetros específicos
107
+ message: { type: 'string', description: 'Commit message (required for init/update/sync)' },
108
+ branch: { type: 'string', description: 'Branch name', default: 'main' },
109
+ forcePush: { type: 'boolean', description: 'Force push', default: false },
110
+ createRepo: { type: 'boolean', description: 'Create remote repository if not exists', default: false },
111
+ granular: { type: 'boolean', description: 'Create granular commits by file type for init', default: false },
112
+ detailed: { type: 'boolean', description: 'Detailed output for status', default: false },
113
+ staged: { type: 'boolean', description: 'Show staged changes for diff', default: false },
114
+ nameOnly: { type: 'boolean', description: 'Show only filenames for diff', default: false },
115
+ commit: { type: 'string', description: 'Target commit for reset/diff' },
116
+ maxCount: { type: 'number', description: 'Max commits for log', default: 10 },
117
+ oneline: { type: 'boolean', description: 'One line format for log', default: true },
118
+ mode: { type: 'string', enum: ['soft', 'mixed', 'hard'], description: 'Reset mode', default: 'mixed' },
119
+ operation: { type: 'string', enum: ['save', 'pop', 'apply', 'list', 'drop', 'clear'], description: 'Stash operation', default: 'save' }
37
120
  },
38
- required: ['action', 'repo', 'projectPath', 'provider', 'message']
121
+ required: ['action', 'projectPath']
39
122
  },
40
123
  async handler(input) {
41
124
  try {
42
125
  const validatedInput = GitUpdateProjectInputSchema.parse(input);
43
- const processedInput = await (0, user_detection_js_1.applyAutoUserDetection)(validatedInput, validatedInput.provider);
44
- const provider = index_js_1.globalProviderFactory.getProvider(processedInput.provider);
45
- const result = await this.handleUpdate(validatedInput);
46
- return GitUpdateProjectResultSchema.parse(result);
126
+ // Roteamento baseado na action
127
+ switch (validatedInput.action) {
128
+ case 'init':
129
+ return await this.handleInit(validatedInput);
130
+ case 'update':
131
+ return await this.handleUpdate(validatedInput);
132
+ case 'status':
133
+ return await this.handleStatus(validatedInput);
134
+ case 'diff':
135
+ return await this.handleDiff(validatedInput);
136
+ case 'log':
137
+ return await this.handleLog(validatedInput);
138
+ case 'reset':
139
+ return await this.handleReset(validatedInput);
140
+ case 'stash':
141
+ return await this.handleStash(validatedInput);
142
+ case 'pull':
143
+ return await this.handlePull(validatedInput);
144
+ case 'sync':
145
+ return await this.handleSync(validatedInput);
146
+ default:
147
+ throw new Error(`Action '${validatedInput.action}' não suportada`);
148
+ }
47
149
  }
48
150
  catch (error) {
49
151
  return {
50
152
  success: false,
51
153
  action: input.action,
52
- message: 'Erro na atualização incremental do projeto',
154
+ message: `Erro na operação ${input.action}`,
53
155
  error: error instanceof Error ? error.message : String(error)
54
156
  };
55
157
  }
@@ -183,6 +285,554 @@ exports.gitUpdateProjectTool = {
183
285
  error: error instanceof Error ? error.message : String(error)
184
286
  };
185
287
  }
288
+ },
289
+ // Action: status - verificar status do repositório
290
+ async handleStatus(params) {
291
+ try {
292
+ const { projectPath, detailed = false } = params;
293
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
294
+ // Verificar se é um repositório Git
295
+ const isGitRepo = await gitOps.isGitRepository();
296
+ if (!isGitRepo) {
297
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
298
+ }
299
+ // Obter status detalhado
300
+ const statusResult = await gitOps.status({ porcelain: false });
301
+ if (!statusResult.success) {
302
+ throw new Error(`Falha ao obter status: ${statusResult.error}`);
303
+ }
304
+ // Obter branch atual
305
+ const branchResult = await gitOps.getCurrentBranch();
306
+ const currentBranch = branchResult.success ? branchResult.output.trim() : 'unknown';
307
+ // Contar mudanças
308
+ const porcelainResult = await gitOps.status({ porcelain: true });
309
+ const changes = porcelainResult.success ? porcelainResult.output.trim() : '';
310
+ const filesChanged = changes ? changes.split('\n').filter(line => line.trim().length > 0).length : 0;
311
+ return {
312
+ success: true,
313
+ action: 'status',
314
+ message: `Status do repositório obtido com sucesso`,
315
+ data: {
316
+ currentBranch,
317
+ filesChanged,
318
+ hasChanges: filesChanged > 0,
319
+ statusOutput: detailed ? statusResult.output : statusResult.output.split('\n').slice(0, 10).join('\n'),
320
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0',
321
+ detailed
322
+ }
323
+ };
324
+ }
325
+ catch (error) {
326
+ return {
327
+ success: false,
328
+ action: 'status',
329
+ message: 'Erro ao verificar status do repositório',
330
+ error: error instanceof Error ? error.message : String(error)
331
+ };
332
+ }
333
+ },
334
+ // Action: diff - mostrar diferenças
335
+ async handleDiff(params) {
336
+ try {
337
+ const { projectPath, staged = false, nameOnly = false, commit } = params;
338
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
339
+ // Verificar se é um repositório Git
340
+ const isGitRepo = await gitOps.isGitRepository();
341
+ if (!isGitRepo) {
342
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
343
+ }
344
+ // Obter diferenças
345
+ const diffOptions = {};
346
+ if (staged)
347
+ diffOptions.cached = true;
348
+ if (nameOnly)
349
+ diffOptions.nameOnly = true;
350
+ if (commit)
351
+ diffOptions.commit = commit;
352
+ const diffResult = await gitOps.diff(diffOptions);
353
+ if (!diffResult.success && diffResult.error) {
354
+ throw new Error(`Falha ao obter diferenças: ${diffResult.error}`);
355
+ }
356
+ const hasDifferences = diffResult.output.trim().length > 0;
357
+ return {
358
+ success: true,
359
+ action: 'diff',
360
+ message: hasDifferences ? 'Diferenças encontradas' : 'Nenhuma diferença encontrada',
361
+ data: {
362
+ hasDifferences,
363
+ diffOutput: diffResult.output,
364
+ staged,
365
+ nameOnly,
366
+ commit: commit || 'HEAD',
367
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0'
368
+ }
369
+ };
370
+ }
371
+ catch (error) {
372
+ return {
373
+ success: false,
374
+ action: 'diff',
375
+ message: 'Erro ao obter diferenças',
376
+ error: error instanceof Error ? error.message : String(error)
377
+ };
378
+ }
379
+ },
380
+ // Action: log - histórico de commits
381
+ async handleLog(params) {
382
+ try {
383
+ const { projectPath, maxCount = 10, oneline = true, branch } = params;
384
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
385
+ // Verificar se é um repositório Git
386
+ const isGitRepo = await gitOps.isGitRepository();
387
+ if (!isGitRepo) {
388
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
389
+ }
390
+ // Obter histórico de commits
391
+ const logOptions = {};
392
+ if (maxCount)
393
+ logOptions.maxCount = maxCount;
394
+ if (oneline)
395
+ logOptions.oneline = true;
396
+ if (branch)
397
+ logOptions.branches = [branch];
398
+ const logResult = await gitOps.log(logOptions);
399
+ if (!logResult.success) {
400
+ throw new Error(`Falha ao obter histórico: ${logResult.error}`);
401
+ }
402
+ const commits = logResult.output.trim();
403
+ const commitCount = commits ? commits.split('\n').filter(line => line.trim().length > 0).length : 0;
404
+ return {
405
+ success: true,
406
+ action: 'log',
407
+ message: `${commitCount} commits encontrados no histórico`,
408
+ data: {
409
+ commits: commits || 'Nenhum commit encontrado',
410
+ commitCount,
411
+ maxCount,
412
+ oneline,
413
+ branch: branch || 'all',
414
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0'
415
+ }
416
+ };
417
+ }
418
+ catch (error) {
419
+ return {
420
+ success: false,
421
+ action: 'log',
422
+ message: 'Erro ao obter histórico de commits',
423
+ error: error instanceof Error ? error.message : String(error)
424
+ };
425
+ }
426
+ },
427
+ // Action: reset - desfazer mudanças
428
+ async handleReset(params) {
429
+ try {
430
+ const { projectPath, mode = 'mixed', commit } = params;
431
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
432
+ // Verificar se é um repositório Git
433
+ const isGitRepo = await gitOps.isGitRepository();
434
+ if (!isGitRepo) {
435
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
436
+ }
437
+ // Executar reset
438
+ const resetOptions = {};
439
+ if (commit) {
440
+ resetOptions.target = commit;
441
+ }
442
+ const resetResult = await gitOps.reset(mode, resetOptions);
443
+ if (!resetResult.success) {
444
+ throw new Error(`Falha no reset: ${resetResult.error}`);
445
+ }
446
+ return {
447
+ success: true,
448
+ action: 'reset',
449
+ message: `Reset ${mode} executado com sucesso`,
450
+ data: {
451
+ mode,
452
+ targetCommit: commit || 'HEAD',
453
+ resetOutput: resetResult.output,
454
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0'
455
+ }
456
+ };
457
+ }
458
+ catch (error) {
459
+ return {
460
+ success: false,
461
+ action: 'reset',
462
+ message: 'Erro ao executar reset',
463
+ error: error instanceof Error ? error.message : String(error)
464
+ };
465
+ }
466
+ },
467
+ // Action: stash - gerenciar mudanças temporárias
468
+ async handleStash(params) {
469
+ try {
470
+ const { projectPath, operation = 'save', message } = params;
471
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
472
+ // Verificar se é um repositório Git
473
+ const isGitRepo = await gitOps.isGitRepository();
474
+ if (!isGitRepo) {
475
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
476
+ }
477
+ let stashResult;
478
+ switch (operation) {
479
+ case 'save':
480
+ stashResult = await gitOps.stash('push', { message });
481
+ break;
482
+ case 'pop':
483
+ stashResult = await gitOps.stash('pop');
484
+ break;
485
+ case 'apply':
486
+ stashResult = await gitOps.stash('apply');
487
+ break;
488
+ case 'list':
489
+ stashResult = await gitOps.stash('list');
490
+ break;
491
+ case 'drop':
492
+ stashResult = await gitOps.stash('drop');
493
+ break;
494
+ case 'clear':
495
+ stashResult = await gitOps.stash('clear');
496
+ break;
497
+ default:
498
+ throw new Error(`Operação de stash '${operation}' não suportada`);
499
+ }
500
+ if (!stashResult.success) {
501
+ throw new Error(`Falha na operação stash ${operation}: ${stashResult.error}`);
502
+ }
503
+ return {
504
+ success: true,
505
+ action: 'stash',
506
+ message: `Operação stash '${operation}' executada com sucesso`,
507
+ data: {
508
+ operation,
509
+ message: message || undefined,
510
+ stashOutput: stashResult.output,
511
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0'
512
+ }
513
+ };
514
+ }
515
+ catch (error) {
516
+ return {
517
+ success: false,
518
+ action: 'stash',
519
+ message: 'Erro na operação de stash',
520
+ error: error instanceof Error ? error.message : String(error)
521
+ };
522
+ }
523
+ },
524
+ // Action: pull - atualizar do remoto
525
+ async handlePull(params) {
526
+ try {
527
+ const { projectPath, branch } = params;
528
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
529
+ // Verificar se é um repositório Git
530
+ const isGitRepo = await gitOps.isGitRepository();
531
+ if (!isGitRepo) {
532
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
533
+ }
534
+ // Executar pull
535
+ const pullResult = await gitOps.pull('origin', branch);
536
+ if (!pullResult.success) {
537
+ throw new Error(`Falha no pull: ${pullResult.error}`);
538
+ }
539
+ return {
540
+ success: true,
541
+ action: 'pull',
542
+ message: `Pull do remoto executado com sucesso`,
543
+ data: {
544
+ remote: 'origin',
545
+ branch: branch || 'current',
546
+ pullOutput: pullResult.output,
547
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0'
548
+ }
549
+ };
550
+ }
551
+ catch (error) {
552
+ return {
553
+ success: false,
554
+ action: 'pull',
555
+ message: 'Erro ao executar pull',
556
+ error: error instanceof Error ? error.message : String(error)
557
+ };
558
+ }
559
+ },
560
+ // Action: sync - sincronização completa (pull + commit + push)
561
+ async handleSync(params) {
562
+ try {
563
+ const { repo, projectPath, message, branch = 'main', forcePush = false, provider: providerName } = params;
564
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
565
+ // Verificar se é um repositório Git
566
+ const isGitRepo = await gitOps.isGitRepository();
567
+ if (!isGitRepo) {
568
+ throw new Error(`Diretório '${projectPath}' não é um repositório Git válido`);
569
+ }
570
+ const syncResults = {
571
+ pull: { success: false, output: '', error: '' },
572
+ commit: { success: false, output: '', error: '', created: false },
573
+ push: { success: false, output: '', error: '' }
574
+ };
575
+ // 1. Pull do remoto
576
+ try {
577
+ const pullResult = await gitOps.pull('origin', branch);
578
+ syncResults.pull = {
579
+ success: pullResult.success,
580
+ output: pullResult.output,
581
+ error: pullResult.error || ''
582
+ };
583
+ }
584
+ catch (pullErr) {
585
+ syncResults.pull.error = pullErr instanceof Error ? pullErr.message : String(pullErr);
586
+ }
587
+ // 2. Verificar se há mudanças após pull
588
+ const statusResult = await gitOps.status({ porcelain: true });
589
+ const hasChanges = statusResult.success && statusResult.output.trim().length > 0;
590
+ if (hasChanges) {
591
+ // Fazer commit das mudanças
592
+ const addResult = await gitOps.addFiles(['.']);
593
+ if (addResult.success) {
594
+ const commitResult = await gitOps.commit(message);
595
+ syncResults.commit = {
596
+ success: commitResult.success,
597
+ output: commitResult.output,
598
+ error: commitResult.error || '',
599
+ created: commitResult.success
600
+ };
601
+ }
602
+ else {
603
+ syncResults.commit.error = `Falha ao adicionar arquivos: ${addResult.error}`;
604
+ }
605
+ }
606
+ // 3. Push se commit foi criado
607
+ if (syncResults.commit.created) {
608
+ try {
609
+ const pushOptions = {};
610
+ if (forcePush)
611
+ pushOptions.force = true;
612
+ const pushResult = await gitOps.push('origin', branch, pushOptions);
613
+ syncResults.push = {
614
+ success: pushResult.success,
615
+ output: pushResult.output,
616
+ error: pushResult.error || ''
617
+ };
618
+ }
619
+ catch (pushErr) {
620
+ syncResults.push.error = pushErr instanceof Error ? pushErr.message : String(pushErr);
621
+ }
622
+ }
623
+ const overallSuccess = syncResults.pull.success && (!hasChanges || syncResults.commit.success);
624
+ return {
625
+ success: overallSuccess,
626
+ action: 'sync',
627
+ message: `Sincronização ${overallSuccess ? 'concluída' : 'com problemas'}`,
628
+ data: {
629
+ repo,
630
+ branch,
631
+ provider: providerName,
632
+ syncResults,
633
+ hasChanges,
634
+ implementation: 'REAL_GIT_OPERATIONS_v2.38.0',
635
+ summary: {
636
+ pullSuccessful: syncResults.pull.success,
637
+ commitCreated: syncResults.commit.created,
638
+ pushSuccessful: syncResults.push.success
639
+ }
640
+ }
641
+ };
642
+ }
643
+ catch (error) {
644
+ return {
645
+ success: false,
646
+ action: 'sync',
647
+ message: 'Erro na sincronização completa',
648
+ error: error instanceof Error ? error.message : String(error)
649
+ };
650
+ }
651
+ },
652
+ // Action: init - upload inicial completo (substitui upload-project)
653
+ async handleInit(params) {
654
+ try {
655
+ const { repo, projectPath, message, branch = 'main', forcePush = false, createRepo = false, granular = false, provider: providerName } = params;
656
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
657
+ // Aplicar auto-detecção de usuário
658
+ const processedInput = await (0, user_detection_js_1.applyAutoUserDetection)(params, providerName);
659
+ const provider = index_js_1.globalProviderFactory.getProvider(processedInput.provider);
660
+ if (!provider) {
661
+ throw new Error(`Provider '${providerName}' não encontrado`);
662
+ }
663
+ const currentUser = await provider.getCurrentUser();
664
+ const owner = currentUser.login;
665
+ // 1. Inicializar repositório Git local se necessário
666
+ const isGitRepo = await gitOps.isGitRepository();
667
+ if (!isGitRepo) {
668
+ const initResult = await gitOps.initRepository();
669
+ if (!initResult.success) {
670
+ throw new Error(`Falha ao inicializar repositório Git: ${initResult.error}`);
671
+ }
672
+ }
673
+ // 2. Verificar/criar repositório remoto
674
+ let repoExists = true;
675
+ try {
676
+ await provider.getRepository(owner, repo);
677
+ }
678
+ catch (error) {
679
+ repoExists = false;
680
+ if (createRepo) {
681
+ try {
682
+ await provider.createRepository(repo, `Projeto ${repo}`, false);
683
+ repoExists = true;
684
+ }
685
+ catch (createError) {
686
+ console.warn(`Aviso: Não foi possível criar repositório: ${createError instanceof Error ? createError.message : String(createError)}`);
687
+ }
688
+ }
689
+ else {
690
+ throw new Error(`Repositório '${repo}' não existe. Use createRepo: true para criar automaticamente.`);
691
+ }
692
+ }
693
+ // 3. Preparar arquivos para commit
694
+ let filesCommitted = 0;
695
+ let commitsCreated = 0;
696
+ if (granular) {
697
+ // Commits granulares por tipo de arquivo (melhor rastreabilidade)
698
+ const fileGroups = await this.groupFilesByType(projectPath);
699
+ for (const [fileType, files] of Object.entries(fileGroups)) {
700
+ if (files.length > 0) {
701
+ // Adicionar arquivos do tipo específico
702
+ const addResult = await gitOps.addFiles(files);
703
+ if (addResult.success) {
704
+ // Verificar se há mudanças para commitar
705
+ const statusResult = await gitOps.status({ porcelain: true });
706
+ if (statusResult.success && statusResult.output.trim()) {
707
+ const commitResult = await gitOps.commit(`${message} - ${fileType} files`);
708
+ if (commitResult.success) {
709
+ commitsCreated++;
710
+ filesCommitted += files.length;
711
+ }
712
+ }
713
+ }
714
+ }
715
+ }
716
+ }
717
+ else {
718
+ // Commit único de todos os arquivos (como upload-project)
719
+ const addResult = await gitOps.addFiles(['.']);
720
+ if (addResult.success) {
721
+ const statusResult = await gitOps.status({ porcelain: true });
722
+ if (statusResult.success && statusResult.output.trim()) {
723
+ const commitResult = await gitOps.commit(message);
724
+ if (commitResult.success) {
725
+ commitsCreated++;
726
+ filesCommitted = statusResult.output.trim().split('\n').length;
727
+ }
728
+ }
729
+ }
730
+ }
731
+ // 4. Configurar e fazer push para remote
732
+ let pushSuccessful = false;
733
+ const remoteUrl = provider.getRepositoryUrl(owner, repo);
734
+ // Configurar remote origin
735
+ const remoteResult = await gitOps.remote('show', 'origin');
736
+ if (!remoteResult.success) {
737
+ const addRemoteResult = await gitOps.remote('add', 'origin', remoteUrl);
738
+ if (!addRemoteResult.success && !addRemoteResult.error?.includes('already exists')) {
739
+ console.warn(`Aviso: Falha ao adicionar remote: ${addRemoteResult.error}`);
740
+ }
741
+ }
742
+ else {
743
+ // Atualizar URL se necessário
744
+ const setUrlResult = await gitOps.remote('set-url', 'origin', remoteUrl);
745
+ if (!setUrlResult.success) {
746
+ console.warn(`Aviso: Falha ao atualizar remote URL: ${setUrlResult.error}`);
747
+ }
748
+ }
749
+ // Fazer push
750
+ if (commitsCreated > 0) {
751
+ try {
752
+ const pushOptions = { setUpstream: true };
753
+ if (forcePush)
754
+ pushOptions.force = true;
755
+ const pushResult = await gitOps.push('origin', branch, pushOptions);
756
+ pushSuccessful = pushResult.success;
757
+ if (!pushSuccessful) {
758
+ console.warn(`Aviso: Push falhou: ${pushResult.error}`);
759
+ }
760
+ }
761
+ catch (pushErr) {
762
+ console.warn(`Aviso: Erro no push: ${pushErr instanceof Error ? pushErr.message : String(pushErr)}`);
763
+ }
764
+ }
765
+ return {
766
+ success: true,
767
+ action: 'init',
768
+ message: `Upload inicial concluído com ${commitsCreated} commit(s) e ${filesCommitted} arquivo(s)`,
769
+ data: {
770
+ repo,
771
+ branch,
772
+ provider: providerName,
773
+ owner,
774
+ remoteUrl,
775
+ repositoryCreated: !repoExists && createRepo,
776
+ gitInit: !isGitRepo,
777
+ commitsCreated,
778
+ filesCommitted,
779
+ pushSuccessful,
780
+ granular,
781
+ implementation: 'REAL_GIT_OPERATIONS_v2.40.0',
782
+ note: granular ?
783
+ 'Commits granulares criados por tipo de arquivo para melhor rastreabilidade' :
784
+ 'Commit único criado (como upload-project original)'
785
+ }
786
+ };
787
+ }
788
+ catch (error) {
789
+ return {
790
+ success: false,
791
+ action: 'init',
792
+ message: 'Erro no upload inicial do projeto',
793
+ error: error instanceof Error ? error.message : String(error)
794
+ };
795
+ }
796
+ },
797
+ // Helper method para agrupar arquivos por tipo
798
+ async groupFilesByType(projectPath) {
799
+ const gitOps = new git_operations_js_1.GitOperations(projectPath);
800
+ const statusResult = await gitOps.status({ porcelain: true });
801
+ if (!statusResult.success) {
802
+ return {};
803
+ }
804
+ const lines = statusResult.output.trim().split('\n').filter(line => line.trim());
805
+ const fileGroups = {
806
+ 'config': [],
807
+ 'source': [],
808
+ 'documentation': [],
809
+ 'assets': [],
810
+ 'other': []
811
+ };
812
+ for (const line of lines) {
813
+ // Extrair nome do arquivo (remover status indicators)
814
+ const fileName = line.substring(3).trim();
815
+ if (fileName.includes('package.json') || fileName.includes('.config.') ||
816
+ fileName.includes('tsconfig') || fileName.includes('.env')) {
817
+ fileGroups.config.push(fileName);
818
+ }
819
+ else if (fileName.endsWith('.ts') || fileName.endsWith('.js') ||
820
+ fileName.endsWith('.py') || fileName.endsWith('.java')) {
821
+ fileGroups.source.push(fileName);
822
+ }
823
+ else if (fileName.endsWith('.md') || fileName.endsWith('.txt') ||
824
+ fileName.includes('README') || fileName.includes('LICENSE')) {
825
+ fileGroups.documentation.push(fileName);
826
+ }
827
+ else if (fileName.endsWith('.png') || fileName.endsWith('.jpg') ||
828
+ fileName.endsWith('.svg') || fileName.endsWith('.css')) {
829
+ fileGroups.assets.push(fileName);
830
+ }
831
+ else {
832
+ fileGroups.other.push(fileName);
833
+ }
834
+ }
835
+ return fileGroups;
186
836
  }
187
837
  };
188
838
  //# sourceMappingURL=git-update-project.js.map