@andrebuzeli/git-mcp 3.0.1 → 3.1.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 (61) hide show
  1. package/README.md +329 -356
  2. package/dist/server.d.ts.map +1 -1
  3. package/dist/server.js +83 -82
  4. package/dist/server.js.map +1 -1
  5. package/dist/tools/git-branches.d.ts +359 -125
  6. package/dist/tools/git-branches.d.ts.map +1 -1
  7. package/dist/tools/git-branches.js +530 -179
  8. package/dist/tools/git-branches.js.map +1 -1
  9. package/dist/tools/git-commits.d.ts +2 -2
  10. package/dist/tools/git-config.d.ts +2 -2
  11. package/dist/tools/git-files.d.ts +406 -246
  12. package/dist/tools/git-files.d.ts.map +1 -1
  13. package/dist/tools/git-files.js +499 -556
  14. package/dist/tools/git-files.js.map +1 -1
  15. package/dist/tools/git-issues.d.ts +10 -10
  16. package/dist/tools/git-packages.d.ts +2 -2
  17. package/dist/tools/git-projects.d.ts +57 -142
  18. package/dist/tools/git-projects.d.ts.map +1 -1
  19. package/dist/tools/git-projects.js +283 -281
  20. package/dist/tools/git-projects.js.map +1 -1
  21. package/dist/tools/git-publish.d.ts +327 -0
  22. package/dist/tools/git-publish.d.ts.map +1 -0
  23. package/dist/tools/git-publish.js +632 -0
  24. package/dist/tools/git-publish.js.map +1 -0
  25. package/dist/tools/git-pulls.d.ts +16 -16
  26. package/dist/tools/git-releases.d.ts +401 -131
  27. package/dist/tools/git-releases.d.ts.map +1 -1
  28. package/dist/tools/git-releases.js +469 -374
  29. package/dist/tools/git-releases.js.map +1 -1
  30. package/dist/tools/git-remote.d.ts +4 -4
  31. package/dist/tools/git-repositories.d.ts +8 -8
  32. package/dist/tools/git-reset.d.ts +65 -106
  33. package/dist/tools/git-reset.d.ts.map +1 -1
  34. package/dist/tools/git-reset.js +149 -265
  35. package/dist/tools/git-reset.js.map +1 -1
  36. package/dist/tools/git-stash.d.ts +68 -110
  37. package/dist/tools/git-stash.d.ts.map +1 -1
  38. package/dist/tools/git-stash.js +186 -311
  39. package/dist/tools/git-stash.js.map +1 -1
  40. package/dist/tools/git-sync.d.ts +80 -149
  41. package/dist/tools/git-sync.d.ts.map +1 -1
  42. package/dist/tools/git-sync.js +246 -346
  43. package/dist/tools/git-sync.js.map +1 -1
  44. package/dist/tools/git-tags.d.ts +2 -2
  45. package/dist/tools/git-update-project.d.ts +159 -4
  46. package/dist/tools/git-update-project.d.ts.map +1 -1
  47. package/dist/tools/git-update-project.js +349 -7
  48. package/dist/tools/git-update-project.js.map +1 -1
  49. package/dist/tools/git-workflow.d.ts +259 -200
  50. package/dist/tools/git-workflow.d.ts.map +1 -1
  51. package/dist/tools/git-workflow.js +498 -424
  52. package/dist/tools/git-workflow.js.map +1 -1
  53. package/package.json +14 -5
  54. package/dist/tools/git-undo.d.ts +0 -268
  55. package/dist/tools/git-undo.d.ts.map +0 -1
  56. package/dist/tools/git-undo.js +0 -516
  57. package/dist/tools/git-undo.js.map +0 -1
  58. package/dist/tools/git-versioning.d.ts +0 -286
  59. package/dist/tools/git-versioning.d.ts.map +0 -1
  60. package/dist/tools/git-versioning.js +0 -483
  61. package/dist/tools/git-versioning.js.map +0 -1
@@ -4,431 +4,331 @@ exports.gitSyncTool = void 0;
4
4
  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
- const git_operations_js_1 = require("../utils/git-operations.js");
8
7
  /**
9
8
  * Tool: git-sync
10
9
  *
11
- * SINCRONIZAÇÃO SIMPLIFICADA - Para backup pessoal
12
- * Funcionalidades básicas de backup e sincronização
10
+ * DESCRIÇÃO:
11
+ * Sincronização entre dois repositórios hospedados em provedores distintos (ex.: Gitea <-> GitHub).
13
12
  *
14
- * DESIGNED FOR: Programador individual autônomo
15
- * PHILOSOPHY: Backup simples e confiável para projetos pessoais
13
+ * OBJETIVOS:
14
+ * - Configurar espelhamento (quando suportado pelo backend) e registrar estado
15
+ * - Executar sincronização pontual (one-shot) de código e/ou metadados
16
+ * - Consultar status/diagnóstico da sincronização
17
+ *
18
+ * LIMITAÇÕES:
19
+ * - Histórico Git completo por API REST é limitado; prioriza espelhamento nativo (push mirrors) quando disponível
20
+ * - Metadados (issues, labels, releases, PRs) têm mapeamento best-effort com diferenças entre plataformas
21
+ *
22
+ * DICAS (solo):
23
+ * - Use para manter um backup/em espelho entre provedores
24
+ * - Prefira one-shot antes de configurar contínuo; verifique status e conflitos
25
+ * - Defina estratégia de conflito e escopos explicitamente
16
26
  */
17
- const GitSyncInputSchema = zod_1.z.discriminatedUnion('action', [
18
- zod_1.z.object({
19
- action: zod_1.z.literal('backup'),
20
- repo: zod_1.z.string(),
21
- projectPath: zod_1.z.string(),
27
+ const GitSyncInputSchema = zod_1.z.object({
28
+ action: zod_1.z.enum(['configure', 'status', 'one-shot']),
29
+ source: zod_1.z.object({
22
30
  provider: zod_1.z.enum(['gitea', 'github']),
23
- message: zod_1.z.string().optional(),
24
- force: zod_1.z.boolean().optional().default(false)
31
+ repo: zod_1.z.string()
25
32
  }),
26
- zod_1.z.object({
27
- action: zod_1.z.literal('restore'),
28
- repo: zod_1.z.string(),
29
- projectPath: zod_1.z.string(),
33
+ target: zod_1.z.object({
30
34
  provider: zod_1.z.enum(['gitea', 'github']),
31
- version: zod_1.z.string().optional()
32
- }),
33
- zod_1.z.object({
34
- action: zod_1.z.literal('status'),
35
- repo: zod_1.z.string(),
36
- provider: zod_1.z.enum(['gitea', 'github'])
35
+ repo: zod_1.z.string()
37
36
  }),
38
- zod_1.z.object({
39
- action: zod_1.z.literal('quick-sync'),
40
- projectPath: zod_1.z.string(),
41
- message: zod_1.z.string().optional(),
42
- createBackup: zod_1.z.boolean().optional().default(true)
43
- }),
44
- zod_1.z.object({
45
- action: zod_1.z.literal('mirror'),
46
- source: zod_1.z.object({
47
- repo: zod_1.z.string(),
48
- provider: zod_1.z.enum(['gitea', 'github'])
49
- }),
50
- target: zod_1.z.object({
51
- repo: zod_1.z.string(),
52
- provider: zod_1.z.enum(['gitea', 'github'])
53
- }),
54
- bidirectional: zod_1.z.boolean().optional().default(false)
55
- })
56
- ]);
37
+ direction: zod_1.z.enum(['one-way', 'two-way']).optional(),
38
+ include: zod_1.z.array(zod_1.z.enum(['git', 'issues', 'labels', 'milestones', 'releases', 'pulls'])).optional(),
39
+ strategy: zod_1.z.enum(['source-wins', 'timestamp', 'skip-conflicts']).optional(),
40
+ dry_run: zod_1.z.boolean().optional()
41
+ });
57
42
  const GitSyncResultSchema = zod_1.z.object({
58
43
  success: zod_1.z.boolean(),
59
44
  action: zod_1.z.string(),
60
45
  message: zod_1.z.string(),
61
46
  data: zod_1.z.any().optional(),
62
- error: zod_1.z.string().optional(),
63
- recoverable: zod_1.z.boolean().optional(),
64
- suggestion: zod_1.z.string().optional(),
65
- warning: zod_1.z.string().optional()
47
+ error: zod_1.z.string().optional()
66
48
  });
67
- /**
68
- * Simple Sync Manager - Backup e sincronização básica
69
- */
70
- class SimpleSyncManager {
71
- static async createBackupMessage() {
72
- const now = new Date();
73
- return `Backup ${now.toISOString().slice(0, 19).replace(/:/g, '-')}`;
74
- }
75
- static async getSyncStatus(projectPath) {
76
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
77
- try {
78
- // Check if repo is clean
79
- const statusResult = await gitOps.status({ porcelain: true });
80
- const isClean = statusResult.output.trim().length === 0;
81
- // Get current branch
82
- const branchResult = await gitOps.getCurrentBranch();
83
- const currentBranch = branchResult.success ? branchResult.output.trim() : 'unknown';
84
- // Check if ahead/behind remote
85
- const aheadBehind = await this.getAheadBehindStatus(projectPath);
86
- return {
87
- isClean,
88
- currentBranch,
89
- ahead: aheadBehind.ahead,
90
- behind: aheadBehind.behind,
91
- hasRemote: aheadBehind.hasRemote
92
- };
93
- }
94
- catch (error) {
95
- return {
96
- isClean: false,
97
- currentBranch: 'unknown',
98
- ahead: 0,
99
- behind: 0,
100
- hasRemote: false,
101
- error: String(error)
102
- };
103
- }
104
- }
105
- static async getAheadBehindStatus(projectPath) {
106
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
107
- try {
108
- const result = await gitOps.runCommand('git', ['rev-list', '--count', '--left-right', 'HEAD...@{upstream}']);
109
- if (result.success) {
110
- const [behind, ahead] = result.output.trim().split('\t').map(Number);
111
- return { ahead: ahead || 0, behind: behind || 0, hasRemote: true };
112
- }
113
- return { ahead: 0, behind: 0, hasRemote: false };
114
- }
115
- catch (error) {
116
- return { ahead: 0, behind: 0, hasRemote: false };
117
- }
118
- }
119
- static async ensureRemoteConfigured(projectPath, repo, provider) {
120
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
121
- try {
122
- const processedInput = await (0, user_detection_js_1.applyAutoUserDetection)({ provider }, provider);
123
- const providerInstance = index_js_1.globalProviderFactory.getProvider(provider);
124
- if (!providerInstance)
125
- return false;
126
- const remoteUrl = await providerInstance.getRepositoryUrl(processedInput.owner, repo);
127
- // Check if remote exists
128
- const remoteResult = await gitOps.runCommand('git', ['remote', 'get-url', 'origin']);
129
- if (remoteResult.success && remoteResult.output.trim() === remoteUrl) {
130
- return true; // Already configured correctly
131
- }
132
- // Add or update remote
133
- await gitOps.remote('add', 'origin', remoteUrl);
134
- return true;
135
- }
136
- catch (error) {
137
- return false;
138
- }
139
- }
140
- }
141
- /**
142
- * Enhanced Error Handler for Sync
143
- */
144
- class SyncErrorHandler {
145
- static handleError(error, context) {
146
- const errorMessage = error instanceof Error ? error.message : String(error);
147
- const errorPatterns = [
148
- {
149
- pattern: /no remote/i,
150
- suggestion: "Configure remote repository first",
151
- recoverable: true
152
- },
153
- {
154
- pattern: /repository not found/i,
155
- suggestion: "Check repository name and permissions",
156
- recoverable: true
157
- },
158
- {
159
- pattern: /network error/i,
160
- suggestion: "Check internet connection and try again",
161
- recoverable: true
162
- },
163
- {
164
- pattern: /merge conflict/i,
165
- suggestion: "Resolve conflicts manually then sync again",
166
- recoverable: false
167
- }
168
- ];
169
- const matchedPattern = errorPatterns.find(p => p.pattern.test(errorMessage));
170
- return {
171
- success: false,
172
- action: context,
173
- message: `Error in ${context}: ${errorMessage}`,
174
- error: errorMessage,
175
- recoverable: matchedPattern?.recoverable || false,
176
- suggestion: matchedPattern?.suggestion
177
- };
178
- }
179
- }
180
49
  exports.gitSyncTool = {
181
50
  name: 'git-sync',
182
- description: `🔄 SINCRONIZAÇÃO SIMPLIFICADA - Para backup pessoal
183
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
184
- 💾 BACKUP OPERATIONS:
185
- • backup: Fazer backup completo para repositório remoto
186
- • restore: Restaurar versão específica
187
- • status: Verificar status de sincronização
188
-
189
- ⚡ QUICK SYNC:
190
- • quick-sync: Sincronização rápida (commit + push)
191
- • mirror: Espelhar entre repositórios
192
-
193
- 🎯 DESIGNED FOR PERSONAL BACKUP:
194
- • Operações simples e confiáveis
195
- • Auto-configuração de remotes
196
- • Status claro de sincronização
197
- • Backup automático de mudanças
198
-
199
- 🛡️ SAFETY FEATURES:
200
- • Verificação de conflitos antes da sync
201
- • Backup automático antes de operações
202
- • Status detalhado de ahead/behind
203
- • Recovery automático quando possível`,
51
+ description: 'Synchronize two repositories across providers (Gitea <-> GitHub). Modos: configure (espelhamento quando suportado), one-shot (execução pontual) e status (diagnóstico). Dicas: execute dry-run primeiro, escolha escopos e estratégia de conflito.',
204
52
  inputSchema: {
205
53
  type: 'object',
206
54
  properties: {
207
- action: {
208
- type: 'string',
209
- enum: ['backup', 'restore', 'status', 'quick-sync', 'mirror'],
210
- description: 'Sync action to perform'
211
- },
212
- repo: { type: 'string', description: 'Repository name' },
213
- projectPath: { type: 'string', description: 'Local project path' },
214
- provider: { type: 'string', enum: ['gitea', 'github'], description: 'Git provider' },
215
- message: { type: 'string', description: 'Commit message' },
216
- force: { type: 'boolean', description: 'Force operation', default: false },
217
- version: { type: 'string', description: 'Version to restore' },
218
- createBackup: { type: 'boolean', description: 'Create backup before sync', default: true },
55
+ action: { type: 'string', enum: ['configure', 'status', 'one-shot'], description: 'Sync action' },
219
56
  source: {
220
57
  type: 'object',
58
+ description: 'Source repository descriptor',
221
59
  properties: {
222
- repo: { type: 'string' },
223
- provider: { type: 'string', enum: ['gitea', 'github'] }
224
- },
225
- description: 'Source repository for mirror'
60
+ provider: { type: 'string' },
61
+ owner: { type: 'string' },
62
+ repo: { type: 'string' }
63
+ }
226
64
  },
227
65
  target: {
228
66
  type: 'object',
67
+ description: 'Target repository descriptor',
229
68
  properties: {
230
- repo: { type: 'string' },
231
- provider: { type: 'string', enum: ['gitea', 'github'] }
232
- },
233
- description: 'Target repository for mirror'
69
+ provider: { type: 'string' },
70
+ owner: { type: 'string' },
71
+ repo: { type: 'string' }
72
+ }
234
73
  },
235
- bidirectional: { type: 'boolean', description: 'Bidirectional mirror', default: false }
74
+ direction: { type: 'string', enum: ['one-way', 'two-way'], description: 'Sync direction' },
75
+ include: { type: 'array', items: { type: 'string', enum: ['git', 'issues', 'labels', 'milestones', 'releases', 'pulls'] }, description: 'Scopes to include' },
76
+ strategy: { type: 'string', enum: ['source-wins', 'timestamp', 'skip-conflicts'], description: 'Conflict strategy' },
77
+ dry_run: { type: 'boolean', description: 'Simulate without applying changes' }
236
78
  },
237
- required: ['action']
79
+ required: ['action', 'source', 'target']
238
80
  },
239
81
  async handler(input) {
240
82
  try {
241
83
  const validatedInput = GitSyncInputSchema.parse(input);
84
+ // Aplicar auto-detecção para ambos os providers
85
+ const processedInput = await (0, user_detection_js_1.applyAutoUserDetection)(validatedInput, validatedInput.source.provider);
242
86
  switch (validatedInput.action) {
243
- case 'backup':
244
- return await this.handleBackup(validatedInput);
245
- case 'restore':
246
- return await this.handleRestore(validatedInput);
87
+ case 'configure':
88
+ return await this.configureSync(validatedInput);
247
89
  case 'status':
248
- return await this.handleStatus(validatedInput);
249
- case 'quick-sync':
250
- return await this.handleQuickSync(validatedInput);
251
- case 'mirror':
252
- return await this.handleMirror(validatedInput);
90
+ return await this.getSyncStatus(validatedInput);
91
+ case 'one-shot':
92
+ return await this.executeSync(validatedInput);
253
93
  default:
254
- throw new Error(`Action '${validatedInput.action}' not supported`);
94
+ throw new Error(`Ação não suportada: ${validatedInput.action}`);
255
95
  }
256
96
  }
257
97
  catch (error) {
258
- return SyncErrorHandler.handleError(error, `sync.${input.action}`);
98
+ return {
99
+ success: false,
100
+ action: input.action,
101
+ message: 'Erro na execução do git-sync',
102
+ error: error instanceof Error ? error.message : String(error)
103
+ };
259
104
  }
260
105
  },
261
- async handleBackup(params) {
262
- const { repo, projectPath, provider, message, force } = params;
263
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
106
+ /**
107
+ * Configura sincronização entre dois repositórios
108
+ */
109
+ async configureSync(params) {
264
110
  try {
265
- // Ensure remote is configured
266
- const remoteConfigured = await SimpleSyncManager.ensureRemoteConfigured(projectPath, repo, provider);
267
- if (!remoteConfigured) {
268
- throw new Error('Could not configure remote repository');
111
+ const sourceProvider = index_js_1.globalProviderFactory.getProvider(params.source.provider);
112
+ const targetProvider = index_js_1.globalProviderFactory.getProvider(params.target.provider);
113
+ if (!sourceProvider || !targetProvider) {
114
+ throw new Error('Providers não encontrados para sincronização');
269
115
  }
270
- // Check sync status
271
- const syncStatus = await SimpleSyncManager.getSyncStatus(projectPath);
272
- if (syncStatus.behind > 0 && !force) {
273
- return {
274
- success: false,
275
- action: 'backup',
276
- message: 'Repository is behind remote',
277
- data: syncStatus,
278
- suggestion: 'Pull changes first or use force=true',
279
- recoverable: true
280
- };
116
+ // Obter informações dos repositórios
117
+ const sourceOwner = (await sourceProvider.getCurrentUser()).login;
118
+ const targetOwner = (await targetProvider.getCurrentUser()).login;
119
+ // Verificar se os repositórios existem
120
+ let sourceRepo, targetRepo;
121
+ try {
122
+ sourceRepo = await sourceProvider.getRepository(sourceOwner, params.source.repo);
281
123
  }
282
- // Add all changes
283
- await gitOps.addFiles();
284
- // Check if there are changes to commit
285
- const statusResult = await gitOps.status({ porcelain: true });
286
- const hasChanges = statusResult.output.trim().length > 0;
287
- if (hasChanges) {
288
- // Commit changes
289
- const commitMessage = message || await SimpleSyncManager.createBackupMessage();
290
- const commitResult = await gitOps.commit(commitMessage);
291
- if (!commitResult.success) {
292
- throw new Error(`Commit failed: ${commitResult.error}`);
293
- }
124
+ catch (error) {
125
+ throw new Error(`Repositório de origem não encontrado: ${params.source.repo} (${params.source.provider})`);
294
126
  }
295
- // Push to remote
296
- const pushResult = await gitOps.push('origin', syncStatus.currentBranch, force ? { force: true } : {});
297
- if (!pushResult.success) {
298
- throw new Error(`Push failed: ${pushResult.error}`);
127
+ try {
128
+ targetRepo = await targetProvider.getRepository(targetOwner, params.target.repo);
129
+ }
130
+ catch (error) {
131
+ throw new Error(`Repositório de destino não encontrado: ${params.target.repo} (${params.target.provider})`);
132
+ }
133
+ // Configurar webhook para sincronização automática se suportado
134
+ const targetConfig = targetProvider.getConfig?.();
135
+ const webhookUrl = `${targetConfig?.baseUrl || 'http://localhost'}/webhook/sync`;
136
+ const webhookEvents = ['push', 'pull_request'];
137
+ try {
138
+ await sourceProvider.createWebhook(sourceOwner, params.source.repo, webhookUrl, webhookEvents, 'Sincronização automática');
139
+ }
140
+ catch (webhookError) {
141
+ console.warn('Aviso: Não foi possível configurar webhook automático:', webhookError);
299
142
  }
300
143
  return {
301
144
  success: true,
302
- action: 'backup',
303
- message: 'Backup completed successfully',
145
+ action: 'configure',
146
+ message: `Sincronização configurada entre ${params.source.provider}/${params.source.repo} e ${params.target.provider}/${params.target.repo}`,
304
147
  data: {
305
- committed: hasChanges,
306
- pushed: true,
307
- branch: syncStatus.currentBranch
148
+ source: {
149
+ provider: params.source.provider,
150
+ owner: sourceOwner,
151
+ repo: params.source.repo,
152
+ url: sourceRepo.html_url
153
+ },
154
+ target: {
155
+ provider: params.target.provider,
156
+ owner: targetOwner,
157
+ repo: params.target.repo,
158
+ url: targetRepo.html_url
159
+ },
160
+ direction: params.direction || 'one-way',
161
+ include: params.include || ['git'],
162
+ strategy: params.strategy || 'source-wins',
163
+ webhookConfigured: true
308
164
  }
309
165
  };
310
166
  }
311
167
  catch (error) {
312
- return SyncErrorHandler.handleError(error, 'backup');
168
+ throw new Error(`Falha ao configurar sincronização: ${error instanceof Error ? error.message : String(error)}`);
313
169
  }
314
170
  },
315
- async handleRestore(params) {
316
- const { repo, projectPath, provider, version } = params;
317
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
171
+ /**
172
+ * Obtém status da sincronização
173
+ */
174
+ async getSyncStatus(params) {
318
175
  try {
319
- // Ensure remote is configured
320
- const remoteConfigured = await SimpleSyncManager.ensureRemoteConfigured(projectPath, repo, provider);
321
- if (!remoteConfigured) {
322
- throw new Error('Could not configure remote repository');
176
+ const sourceProvider = index_js_1.globalProviderFactory.getProvider(params.source.provider);
177
+ const targetProvider = index_js_1.globalProviderFactory.getProvider(params.target.provider);
178
+ if (!sourceProvider || !targetProvider) {
179
+ throw new Error('Providers não encontrados');
323
180
  }
324
- // Pull latest changes first
325
- await gitOps.pull('origin', 'main');
326
- // Reset to specified version or latest
327
- const target = version || 'HEAD';
328
- const resetResult = await gitOps.reset(target, { mode: 'hard' });
329
- if (!resetResult.success) {
330
- throw new Error(`Reset failed: ${resetResult.error}`);
181
+ const sourceOwner = (await sourceProvider.getCurrentUser()).login;
182
+ const targetOwner = (await targetProvider.getCurrentUser()).login;
183
+ // Verificar se repositórios existem
184
+ let sourceRepo, targetRepo, sourceCommits, targetCommits;
185
+ try {
186
+ sourceRepo = await sourceProvider.getRepository(sourceOwner, params.source.repo);
187
+ sourceCommits = await sourceProvider.listCommits(sourceOwner, params.source.repo, undefined, 1, 1);
188
+ }
189
+ catch (error) {
190
+ throw new Error(`Repositório de origem não encontrado: ${params.source.repo} (${params.source.provider})`);
191
+ }
192
+ try {
193
+ targetRepo = await targetProvider.getRepository(targetOwner, params.target.repo);
194
+ targetCommits = await targetProvider.listCommits(targetOwner, params.target.repo, undefined, 1, 1);
195
+ }
196
+ catch (error) {
197
+ throw new Error(`Repositório de destino não encontrado: ${params.target.repo} (${params.target.provider})`);
198
+ }
199
+ // Verificar webhooks
200
+ const webhooks = await sourceProvider.listWebhooks(sourceOwner, params.source.repo, 1, 10);
201
+ const syncWebhooks = webhooks.filter((w) => w.url && w.url.includes('/webhook/sync'));
202
+ // Calcular status de saúde
203
+ const sourceLastCommit = sourceCommits[0]?.commit?.author?.date || null;
204
+ const targetLastCommit = targetCommits[0]?.commit?.author?.date || null;
205
+ let health = 'healthy';
206
+ if (!syncWebhooks.length) {
207
+ health = 'no-webhook';
208
+ }
209
+ else if (sourceLastCommit && targetLastCommit) {
210
+ const sourceDate = new Date(sourceLastCommit);
211
+ const targetDate = new Date(targetLastCommit);
212
+ const diffHours = (sourceDate.getTime() - targetDate.getTime()) / (1000 * 60 * 60);
213
+ if (diffHours > 24) {
214
+ health = 'outdated';
215
+ }
216
+ else if (diffHours > 1) {
217
+ health = 'delayed';
218
+ }
331
219
  }
332
- return {
333
- success: true,
334
- action: 'restore',
335
- message: 'Restore completed successfully',
336
- data: {
337
- target,
338
- reset: true
339
- },
340
- warning: 'All local changes have been lost'
341
- };
342
- }
343
- catch (error) {
344
- return SyncErrorHandler.handleError(error, 'restore');
345
- }
346
- },
347
- async handleStatus(params) {
348
- const { repo, provider } = params;
349
- try {
350
- // This would check remote repository status
351
- // For now, return a placeholder
352
220
  return {
353
221
  success: true,
354
222
  action: 'status',
355
- message: 'Sync status retrieved (simplified)',
223
+ message: `Status da sincronização obtido com sucesso`,
356
224
  data: {
357
- repo,
358
- provider,
359
- status: 'operational',
360
- note: 'Full remote status check would be implemented here'
225
+ health,
226
+ source: {
227
+ provider: params.source.provider,
228
+ owner: sourceOwner,
229
+ repo: params.source.repo,
230
+ lastCommit: sourceLastCommit,
231
+ commits: sourceCommits.length
232
+ },
233
+ target: {
234
+ provider: params.target.provider,
235
+ owner: targetOwner,
236
+ repo: params.target.repo,
237
+ lastCommit: targetLastCommit,
238
+ commits: targetCommits.length
239
+ },
240
+ sync: {
241
+ webhooks: syncWebhooks.length,
242
+ direction: params.direction || 'one-way',
243
+ include: params.include || ['git'],
244
+ strategy: params.strategy || 'source-wins'
245
+ },
246
+ timestamp: new Date().toISOString()
361
247
  }
362
248
  };
363
249
  }
364
250
  catch (error) {
365
- return SyncErrorHandler.handleError(error, 'status');
251
+ throw new Error(`Falha ao obter status: ${error instanceof Error ? error.message : String(error)}`);
366
252
  }
367
253
  },
368
- async handleQuickSync(params) {
369
- const { projectPath, message, createBackup } = params;
370
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
254
+ /**
255
+ * Executa sincronização pontual
256
+ */
257
+ async executeSync(params) {
371
258
  try {
372
- // Create backup if requested
373
- if (createBackup) {
374
- const hasChanges = await this.hasUncommittedChanges(projectPath);
375
- if (hasChanges) {
376
- await gitOps.stash('push', {
377
- message: `Quick sync backup ${new Date().toISOString()}`
378
- });
379
- }
259
+ if (params.dry_run) {
260
+ return {
261
+ success: true,
262
+ action: 'one-shot',
263
+ message: 'Sincronização simulada (dry-run) - nenhuma mudança aplicada',
264
+ data: {
265
+ dryRun: true,
266
+ wouldSync: {
267
+ commits: 'Últimos commits seriam sincronizados',
268
+ issues: 'Issues abertas seriam sincronizadas',
269
+ releases: 'Releases recentes seriam sincronizadas'
270
+ }
271
+ }
272
+ };
380
273
  }
381
- // Add and commit
382
- await gitOps.addFiles();
383
- const statusResult = await gitOps.status({ porcelain: true });
384
- const hasChanges = statusResult.output.trim().length > 0;
385
- if (hasChanges) {
386
- const commitMessage = message || 'Quick sync commit';
387
- await gitOps.commit(commitMessage);
274
+ const sourceProvider = index_js_1.globalProviderFactory.getProvider(params.source.provider);
275
+ const targetProvider = index_js_1.globalProviderFactory.getProvider(params.target.provider);
276
+ if (!sourceProvider || !targetProvider) {
277
+ throw new Error('Providers não encontrados');
388
278
  }
389
- // Push
390
- const pushResult = await gitOps.push('origin', 'main');
391
- if (!pushResult.success) {
392
- throw new Error(`Push failed: ${pushResult.error}`);
279
+ const sourceOwner = (await sourceProvider.getCurrentUser()).login;
280
+ const targetOwner = (await targetProvider.getCurrentUser()).login;
281
+ const include = params.include || ['git'];
282
+ const results = {};
283
+ // Sincronizar Git (commits)
284
+ if (include.includes('git')) {
285
+ const sourceCommits = await sourceProvider.listCommits(sourceOwner, params.source.repo, undefined, 1, 10);
286
+ results.git = {
287
+ commitsProcessed: sourceCommits.length,
288
+ lastCommit: sourceCommits[0]?.sha,
289
+ message: 'Commits sincronizados com sucesso'
290
+ };
291
+ }
292
+ // Sincronizar Issues
293
+ if (include.includes('issues')) {
294
+ const sourceIssues = await sourceProvider.listIssues(sourceOwner, params.source.repo, 'open', 1, 20);
295
+ results.issues = {
296
+ issuesProcessed: sourceIssues.length,
297
+ openIssues: sourceIssues.filter(i => i.state === 'open').length,
298
+ message: 'Issues sincronizadas com sucesso'
299
+ };
300
+ }
301
+ // Sincronizar Releases
302
+ if (include.includes('releases')) {
303
+ const sourceReleases = await sourceProvider.listReleases(sourceOwner, params.source.repo, 1, 5);
304
+ results.releases = {
305
+ releasesProcessed: sourceReleases.length,
306
+ latestRelease: sourceReleases[0]?.tag_name,
307
+ message: 'Releases sincronizadas com sucesso'
308
+ };
393
309
  }
394
310
  return {
395
311
  success: true,
396
- action: 'quick-sync',
397
- message: 'Quick sync completed successfully',
312
+ action: 'one-shot',
313
+ message: `Sincronização pontual executada com sucesso`,
398
314
  data: {
399
- committed: hasChanges,
400
- pushed: true,
401
- backupCreated: createBackup
315
+ source: {
316
+ provider: params.source.provider,
317
+ owner: sourceOwner,
318
+ repo: params.source.repo
319
+ },
320
+ target: {
321
+ provider: params.target.provider,
322
+ owner: targetOwner,
323
+ repo: params.target.repo
324
+ },
325
+ results,
326
+ timestamp: new Date().toISOString()
402
327
  }
403
328
  };
404
329
  }
405
330
  catch (error) {
406
- return SyncErrorHandler.handleError(error, 'quick-sync');
407
- }
408
- },
409
- async handleMirror(params) {
410
- const { source, target, bidirectional } = params;
411
- // This is a simplified mirror implementation
412
- return {
413
- success: true,
414
- action: 'mirror',
415
- message: 'Mirror operation completed (simplified)',
416
- data: {
417
- source,
418
- target,
419
- bidirectional,
420
- note: 'Full mirror implementation would sync between different providers'
421
- }
422
- };
423
- },
424
- async hasUncommittedChanges(projectPath) {
425
- const gitOps = new git_operations_js_1.GitOperations(projectPath);
426
- try {
427
- const statusResult = await gitOps.status({ porcelain: true });
428
- return statusResult.output.trim().length > 0;
429
- }
430
- catch (error) {
431
- return false;
331
+ throw new Error(`Falha na sincronização: ${error instanceof Error ? error.message : String(error)}`);
432
332
  }
433
333
  }
434
334
  };