@andrebuzeli/git-mcp 3.4.0 → 4.0.3

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 (141) hide show
  1. package/EXEMPLOS.md +861 -0
  2. package/INSTRUCOES.md +444 -0
  3. package/README.md +63 -283
  4. package/dist/providers/base-provider.d.ts.map +1 -1
  5. package/dist/providers/base-provider.js +3 -26
  6. package/dist/providers/base-provider.js.map +1 -1
  7. package/dist/providers/gitea-provider.d.ts +0 -2
  8. package/dist/providers/gitea-provider.d.ts.map +1 -1
  9. package/dist/providers/gitea-provider.js +0 -62
  10. package/dist/providers/gitea-provider.js.map +1 -1
  11. package/dist/providers/github-provider.d.ts +0 -2
  12. package/dist/providers/github-provider.d.ts.map +1 -1
  13. package/dist/providers/github-provider.js +48 -105
  14. package/dist/providers/github-provider.js.map +1 -1
  15. package/dist/server.d.ts +0 -27
  16. package/dist/server.d.ts.map +1 -1
  17. package/dist/server.js +130 -1215
  18. package/dist/server.js.map +1 -1
  19. package/dist/tools/{git-commits.d.ts → git-analytics.d.ts} +4 -10
  20. package/dist/tools/git-analytics.d.ts.map +1 -0
  21. package/dist/tools/git-analytics.js +18 -0
  22. package/dist/tools/git-analytics.js.map +1 -0
  23. package/dist/tools/git-archive.d.ts +3 -0
  24. package/dist/tools/git-archive.d.ts.map +1 -1
  25. package/dist/tools/git-archive.js +2 -2
  26. package/dist/tools/git-archive.js.map +1 -1
  27. package/dist/tools/git-backup.d.ts +216 -0
  28. package/dist/tools/git-backup.d.ts.map +1 -0
  29. package/dist/tools/git-backup.js +813 -0
  30. package/dist/tools/git-backup.js.map +1 -0
  31. package/dist/tools/git-branches.d.ts +159 -8
  32. package/dist/tools/git-branches.d.ts.map +1 -1
  33. package/dist/tools/git-branches.js +554 -2
  34. package/dist/tools/git-branches.js.map +1 -1
  35. package/dist/tools/git-config.d.ts +3 -0
  36. package/dist/tools/git-config.d.ts.map +1 -1
  37. package/dist/tools/git-config.js +2 -2
  38. package/dist/tools/git-config.js.map +1 -1
  39. package/dist/tools/git-files.d.ts +130 -8
  40. package/dist/tools/git-files.d.ts.map +1 -1
  41. package/dist/tools/git-files.js +426 -2
  42. package/dist/tools/git-files.js.map +1 -1
  43. package/dist/tools/git-issues.d.ts +137 -471
  44. package/dist/tools/git-issues.d.ts.map +1 -1
  45. package/dist/tools/git-issues.js +605 -613
  46. package/dist/tools/git-issues.js.map +1 -1
  47. package/dist/tools/git-monitor.d.ts +161 -0
  48. package/dist/tools/git-monitor.d.ts.map +1 -0
  49. package/dist/tools/git-monitor.js +746 -0
  50. package/dist/tools/git-monitor.js.map +1 -0
  51. package/dist/tools/git-packages.d.ts +5 -2
  52. package/dist/tools/git-packages.d.ts.map +1 -1
  53. package/dist/tools/git-packages.js +3 -3
  54. package/dist/tools/git-packages.js.map +1 -1
  55. package/dist/tools/git-pulls.d.ts +38 -646
  56. package/dist/tools/git-pulls.d.ts.map +1 -1
  57. package/dist/tools/git-pulls.js +64 -716
  58. package/dist/tools/git-pulls.js.map +1 -1
  59. package/dist/tools/git-release.d.ts +187 -0
  60. package/dist/tools/git-release.d.ts.map +1 -0
  61. package/dist/tools/git-release.js +619 -0
  62. package/dist/tools/git-release.js.map +1 -0
  63. package/dist/tools/git-remote.d.ts +112 -77
  64. package/dist/tools/git-remote.d.ts.map +1 -1
  65. package/dist/tools/git-remote.js +481 -183
  66. package/dist/tools/git-remote.js.map +1 -1
  67. package/dist/tools/git-repos.d.ts +19 -0
  68. package/dist/tools/git-repos.d.ts.map +1 -0
  69. package/dist/tools/git-repos.js +18 -0
  70. package/dist/tools/git-repos.js.map +1 -0
  71. package/dist/tools/git-reset.d.ts +121 -74
  72. package/dist/tools/git-reset.d.ts.map +1 -1
  73. package/dist/tools/git-reset.js +540 -159
  74. package/dist/tools/git-reset.js.map +1 -1
  75. package/dist/tools/git-stash.d.ts +119 -78
  76. package/dist/tools/git-stash.d.ts.map +1 -1
  77. package/dist/tools/git-stash.js +560 -209
  78. package/dist/tools/git-stash.js.map +1 -1
  79. package/dist/tools/git-sync.d.ts +3 -163
  80. package/dist/tools/git-sync.d.ts.map +1 -1
  81. package/dist/tools/git-sync.js +9 -326
  82. package/dist/tools/git-sync.js.map +1 -1
  83. package/dist/tools/git-tags.d.ts +105 -331
  84. package/dist/tools/git-tags.d.ts.map +1 -1
  85. package/dist/tools/git-tags.js +545 -416
  86. package/dist/tools/git-tags.js.map +1 -1
  87. package/dist/tools/git-workflow.d.ts +127 -0
  88. package/dist/tools/git-workflow.d.ts.map +1 -0
  89. package/dist/tools/git-workflow.js +359 -0
  90. package/dist/tools/git-workflow.js.map +1 -0
  91. package/dist/utils/auto-detection.d.ts +113 -0
  92. package/dist/utils/auto-detection.d.ts.map +1 -0
  93. package/dist/utils/auto-detection.js +235 -0
  94. package/dist/utils/auto-detection.js.map +1 -0
  95. package/dist/utils/error-handler.d.ts +107 -0
  96. package/dist/utils/error-handler.d.ts.map +1 -0
  97. package/dist/utils/error-handler.js +331 -0
  98. package/dist/utils/error-handler.js.map +1 -0
  99. package/dist/utils/git-operations.d.ts.map +1 -1
  100. package/dist/utils/git-operations.js +6 -51
  101. package/dist/utils/git-operations.js.map +1 -1
  102. package/dist/utils/user-detection.d.ts +1 -13
  103. package/dist/utils/user-detection.d.ts.map +1 -1
  104. package/dist/utils/user-detection.js +1 -26
  105. package/dist/utils/user-detection.js.map +1 -1
  106. package/package.json +62 -60
  107. package/dist/client.d.ts +0 -307
  108. package/dist/client.d.ts.map +0 -1
  109. package/dist/client.js +0 -299
  110. package/dist/client.js.map +0 -1
  111. package/dist/tools/git-branch-protection.d.ts +0 -97
  112. package/dist/tools/git-branch-protection.d.ts.map +0 -1
  113. package/dist/tools/git-branch-protection.js +0 -182
  114. package/dist/tools/git-branch-protection.js.map +0 -1
  115. package/dist/tools/git-commits.d.ts.map +0 -1
  116. package/dist/tools/git-commits.js +0 -5
  117. package/dist/tools/git-commits.js.map +0 -1
  118. package/dist/tools/git-initialize.d.ts +0 -208
  119. package/dist/tools/git-initialize.d.ts.map +0 -1
  120. package/dist/tools/git-initialize.js +0 -470
  121. package/dist/tools/git-initialize.js.map +0 -1
  122. package/dist/tools/git-projects.d.ts +0 -112
  123. package/dist/tools/git-projects.d.ts.map +0 -1
  124. package/dist/tools/git-projects.js +0 -319
  125. package/dist/tools/git-projects.js.map +0 -1
  126. package/dist/tools/git-releases.d.ts +0 -486
  127. package/dist/tools/git-releases.d.ts.map +0 -1
  128. package/dist/tools/git-releases.js +0 -561
  129. package/dist/tools/git-releases.js.map +0 -1
  130. package/dist/tools/git-repositories.d.ts +0 -469
  131. package/dist/tools/git-repositories.d.ts.map +0 -1
  132. package/dist/tools/git-repositories.js +0 -637
  133. package/dist/tools/git-repositories.js.map +0 -1
  134. package/dist/tools/git-revert.d.ts +0 -147
  135. package/dist/tools/git-revert.d.ts.map +0 -1
  136. package/dist/tools/git-revert.js +0 -199
  137. package/dist/tools/git-revert.js.map +0 -1
  138. package/dist/tools/git-update-project.d.ts +0 -309
  139. package/dist/tools/git-update-project.d.ts.map +0 -1
  140. package/dist/tools/git-update-project.js +0 -878
  141. package/dist/tools/git-update-project.js.map +0 -1
@@ -1,693 +1,685 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.issuesTool = void 0;
36
+ exports.gitIssuesTool = void 0;
4
37
  const zod_1 = require("zod");
5
- const index_js_1 = require("../providers/index.js");
6
- const user_detection_js_1 = require("../utils/user-detection.js");
38
+ const auto_detection_js_1 = require("../utils/auto-detection.js");
39
+ const error_handler_js_1 = require("../utils/error-handler.js");
7
40
  /**
8
- * Tool: issues
9
- *
10
- * DESCRIÇÃO:
11
- * Gerenciamento completo de issues com suporte multi-provider (GitHub e Gitea)
41
+ * Tool: git-issues
12
42
  *
13
- * FUNCIONALIDADES:
14
- * - Criação de novas issues
15
- * - Listagem e busca de issues
16
- * - Obtenção de detalhes específicos
17
- * - Atualização de issues existentes
18
- * - Fechamento de issues
19
- * - Adição de comentários
20
- * - Busca por conteúdo e status
43
+ * SISTEMA DE ISSUES PARA DESENVOLVEDOR INDIVIDUAL
44
+ * Issues locais inteligentes para tracking de tarefas e TODOs
21
45
  *
22
- * USO:
23
- * - Para gerenciar bugs e features
24
- * - Para acompanhar progresso de desenvolvimento
25
- * - Para comunicação entre equipe
26
- * - Para controle de qualidade
27
- *
28
- * RECOMENDAÇÕES:
29
- * - Use títulos descritivos
30
- * - Documente detalhes completos
31
- * - Atualize status regularmente
32
- * - Use labels adequadamente
46
+ * DESIGNED FOR: Programador individual autônomo
47
+ * PHILOSOPHY: Issues simples e locais para produtividade pessoal
33
48
  */
49
+ const GitIssuesInputSchema = zod_1.z.discriminatedUnion('action', [
50
+ // CREATE ISSUE - Criação inteligente
51
+ zod_1.z.object({
52
+ action: zod_1.z.literal('create'),
53
+ projectPath: zod_1.z.string(),
54
+ title: zod_1.z.string(),
55
+ description: zod_1.z.string().optional(),
56
+ labels: zod_1.z.array(zod_1.z.string()).optional(), // priority, bug, feature, todo, etc.
57
+ priority: zod_1.z.enum(['low', 'medium', 'high', 'urgent']).default('medium'),
58
+ assignee: zod_1.z.string().optional(), // Auto-detect user
59
+ dueDate: zod_1.z.string().optional() // ISO date string
60
+ }),
61
+ // LIST ISSUES - Listagem com filtros
62
+ zod_1.z.object({
63
+ action: zod_1.z.literal('list'),
64
+ projectPath: zod_1.z.string(),
65
+ state: zod_1.z.enum(['open', 'closed', 'all']).default('all'),
66
+ labels: zod_1.z.array(zod_1.z.string()).optional(),
67
+ priority: zod_1.z.enum(['low', 'medium', 'high', 'urgent']).optional(),
68
+ limit: zod_1.z.number().default(20),
69
+ sort: zod_1.z.enum(['created', 'updated', 'priority', 'due_date']).default('created')
70
+ }),
71
+ // GET ISSUE - Detalhes específicos
72
+ zod_1.z.object({
73
+ action: zod_1.z.literal('get'),
74
+ projectPath: zod_1.z.string(),
75
+ id: zod_1.z.string(), // Issue ID
76
+ detailed: zod_1.z.boolean().default(false)
77
+ }),
78
+ // UPDATE ISSUE - Atualização
79
+ zod_1.z.object({
80
+ action: zod_1.z.literal('update'),
81
+ projectPath: zod_1.z.string(),
82
+ id: zod_1.z.string(),
83
+ title: zod_1.z.string().optional(),
84
+ description: zod_1.z.string().optional(),
85
+ state: zod_1.z.enum(['open', 'closed']).optional(),
86
+ labels: zod_1.z.array(zod_1.z.string()).optional(),
87
+ priority: zod_1.z.enum(['low', 'medium', 'high', 'urgent']).optional(),
88
+ assignee: zod_1.z.string().optional(),
89
+ dueDate: zod_1.z.string().optional()
90
+ }),
91
+ // CLOSE ISSUE - Fechamento
92
+ zod_1.z.object({
93
+ action: zod_1.z.literal('close'),
94
+ projectPath: zod_1.z.string(),
95
+ id: zod_1.z.string(),
96
+ comment: zod_1.z.string().optional()
97
+ }),
98
+ // SCAN CODE - Auto-detect TODOs/FIXMEs
99
+ zod_1.z.object({
100
+ action: zod_1.z.literal('scan'),
101
+ projectPath: zod_1.z.string(),
102
+ createIssues: zod_1.z.boolean().default(false), // Auto-create issues from TODOs
103
+ patterns: zod_1.z.array(zod_1.z.string()).optional() // Custom patterns to scan
104
+ })
105
+ ]);
34
106
  /**
35
- * Schema de validação para entrada da tool issues
36
- *
37
- * VALIDAÇÕES:
38
- * - action: Ação obrigatória (create, list, get, update, close, comment, search)
39
- * - Parâmetros específicos por ação
40
- * - Validação de tipos e formatos
41
- *
42
- * RECOMENDAÇÕES:
43
- * - Sempre valide entrada antes de usar
44
- * - Use parâmetros opcionais adequadamente
45
- * - Documente parâmetros obrigatórios
107
+ * Local Issue Manager
108
+ * Gerencia issues locais em arquivos JSON
46
109
  */
47
- const IssuesInputSchema = zod_1.z.object({
48
- action: zod_1.z.enum(['create', 'list', 'get', 'update', 'close', 'comment', 'search']),
49
- // Parâmetros comuns
50
- provider: zod_1.z.enum(['gitea', 'github']).describe('Provider to use (gitea or github)'),
51
- projectPath: zod_1.z.string().describe('Local project path for git operations'),
52
- repo: zod_1.z.string().optional().describe('Repository name (extracted from projectPath)'),
53
- // Para create
54
- title: zod_1.z.string().optional(),
55
- body: zod_1.z.string().optional(),
56
- labels: zod_1.z.array(zod_1.z.string()).optional(),
57
- assignees: zod_1.z.array(zod_1.z.string()).optional(),
58
- milestone: zod_1.z.number().optional(),
59
- // Para get/update/close/comment
60
- issue_number: zod_1.z.number().optional(),
61
- // Para list
62
- state: zod_1.z.enum(['open', 'closed', 'all']).optional(),
63
- page: zod_1.z.number().min(1).optional(),
64
- // Para update
65
- new_title: zod_1.z.string().optional(),
66
- new_body: zod_1.z.string().optional(),
67
- new_state: zod_1.z.enum(['open', 'closed']).optional(),
68
- new_labels: zod_1.z.array(zod_1.z.string()).optional(),
69
- new_assignees: zod_1.z.array(zod_1.z.string()).optional(),
70
- new_milestone: zod_1.z.number().optional(),
71
- // Para comment
72
- comment_body: zod_1.z.string().optional(),
73
- // Para search
74
- query: zod_1.z.string().optional(),
75
- author: zod_1.z.string().optional(),
76
- assignee: zod_1.z.string().optional(),
77
- label: zod_1.z.string().optional(),
78
- });
79
- /**
80
- * Schema de saída padronizado
81
- *
82
- * ESTRUTURA:
83
- * - success: Status da operação
84
- * - action: Ação executada
85
- * - message: Mensagem descritiva
86
- * - data: Dados retornados (opcional)
87
- * - error: Detalhes do erro (opcional)
88
- */
89
- const IssuesResultSchema = zod_1.z.object({
90
- success: zod_1.z.boolean(),
91
- action: zod_1.z.string(),
92
- message: zod_1.z.string(),
93
- data: zod_1.z.any().optional(),
94
- error: zod_1.z.string().optional()
95
- });
110
+ class LocalIssueManager {
111
+ static ISSUES_DIR = '.git/issues';
112
+ static ISSUES_FILE = 'issues.json';
113
+ static async ensureIssuesDirectory(projectPath) {
114
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
115
+ try {
116
+ await fs.access(`${projectPath}/${this.ISSUES_DIR}`);
117
+ }
118
+ catch (e) {
119
+ await fs.mkdir(`${projectPath}/${this.ISSUES_DIR}`, { recursive: true });
120
+ }
121
+ }
122
+ static async loadIssues(projectPath) {
123
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
124
+ try {
125
+ await this.ensureIssuesDirectory(projectPath);
126
+ const content = await fs.readFile(`${projectPath}/${this.ISSUES_DIR}/${this.ISSUES_FILE}`, 'utf-8');
127
+ const data = JSON.parse(content);
128
+ return Array.isArray(data.issues) ? data.issues : [];
129
+ }
130
+ catch (e) {
131
+ return [];
132
+ }
133
+ }
134
+ static async saveIssues(projectPath, issues) {
135
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
136
+ await this.ensureIssuesDirectory(projectPath);
137
+ const data = {
138
+ version: '1.0',
139
+ lastUpdated: new Date().toISOString(),
140
+ issues: issues
141
+ };
142
+ await fs.writeFile(`${projectPath}/${this.ISSUES_DIR}/${this.ISSUES_FILE}`, JSON.stringify(data, null, 2), 'utf-8');
143
+ }
144
+ static generateIssueId() {
145
+ return `I-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
146
+ }
147
+ static parseTodoComment(line, filePath, lineNumber) {
148
+ // Parse TODO/FIXME comments
149
+ const todoMatch = line.match(/(?:\/\/|#|--|\/\*)\s*(TODO|FIXME|BUG|HACK|NOTE):\s*(.+)/i);
150
+ if (!todoMatch)
151
+ return null;
152
+ const [, type, description] = todoMatch;
153
+ return {
154
+ type: type.toLowerCase(),
155
+ description: description.trim(),
156
+ file: filePath,
157
+ line: lineNumber,
158
+ raw: line.trim()
159
+ };
160
+ }
161
+ static createIssueFromTodo(todo, projectPath) {
162
+ const labels = [todo.type];
163
+ let priority = 'medium';
164
+ let title = todo.description;
165
+ // Determine priority based on type
166
+ if (todo.type === 'bug') {
167
+ priority = 'high';
168
+ labels.push('bug');
169
+ }
170
+ else if (todo.type === 'hack') {
171
+ priority = 'low';
172
+ labels.push('technical-debt');
173
+ }
174
+ // Create meaningful title
175
+ if (title.length > 80) {
176
+ title = title.substring(0, 77) + '...';
177
+ }
178
+ const description = `**Arquivo:** \`${todo.file}:${todo.line}\`\n\n**Comentário original:**\n\`\`\`\n${todo.raw}\n\`\`\`\n\n*Issue criada automaticamente a partir de comentário no código.*`;
179
+ return {
180
+ id: this.generateIssueId(),
181
+ title,
182
+ description,
183
+ state: 'open',
184
+ labels,
185
+ priority,
186
+ assignee: null,
187
+ createdAt: new Date().toISOString(),
188
+ updatedAt: new Date().toISOString(),
189
+ dueDate: null,
190
+ comments: [],
191
+ source: {
192
+ type: 'code-scan',
193
+ file: todo.file,
194
+ line: todo.line,
195
+ originalComment: todo.raw
196
+ }
197
+ };
198
+ }
199
+ }
96
200
  /**
97
- * Tool: issues
98
- *
99
- * DESCRIÇÃO:
100
- * Gerenciamento completo de issues Gitea com múltiplas ações
101
- *
102
- * ACTIONS DISPONÍVEIS:
103
- *
104
- * 1. create - Criar nova issue
105
- * Parâmetros:
106
- * - owner (obrigatório): Proprietário do repositório
107
- * - repo (obrigatório): Nome do repositório
108
- * - title (obrigatório): Título da issue
109
- * - body (opcional): Descrição detalhada
110
- * - labels (opcional): Array de labels
111
- * - assignees (opcional): Array de usuários responsáveis
112
- * - milestone (opcional): ID do milestone
113
- *
114
- * 2. list - Listar issues
115
- * Parâmetros:
116
- * - owner (obrigatório): Proprietário do repositório
117
- * - repo (obrigatório): Nome do repositório
118
- * - state (opcional): Estado das issues (open, closed, all) - padrão: open
119
- * - page (opcional): Página da listagem (padrão: 1)
120
- * - limit (opcional): Itens por página (padrão: 30, máximo: 100)
121
- *
122
- * 3. get - Obter detalhes da issue
123
- * Parâmetros:
124
- * - owner (obrigatório): Proprietário do repositório
125
- * - repo (obrigatório): Nome do repositório
126
- * - issue_number (obrigatório): Número da issue
127
- *
128
- * 4. update - Atualizar issue existente
129
- * Parâmetros:
130
- * - owner (obrigatório): Proprietário do repositório
131
- * - repo (obrigatório): Nome do repositório
132
- * - issue_number (obrigatório): Número da issue
133
- * - new_title (opcional): Novo título
134
- * - new_body (opcional): Nova descrição
135
- * - new_state (opcional): Novo estado
136
- * - new_labels (opcional): Novos labels
137
- * - new_assignees (opcional): Novos responsáveis
138
- * - new_milestone (opcional): Novo milestone
139
- *
140
- * 5. close - Fechar issue
141
- * Parâmetros:
142
- * - owner (obrigatório): Proprietário do repositório
143
- * - repo (obrigatório): Nome do repositório
144
- * - issue_number (obrigatório): Número da issue
145
- *
146
- * 6. comment - Adicionar comentário
147
- * Parâmetros:
148
- * - owner (obrigatório): Proprietário do repositório
149
- * - repo (obrigatório): Nome do repositório
150
- * - issue_number (obrigatório): Número da issue
151
- * - comment_body (obrigatório): Conteúdo do comentário
152
- *
153
- * 7. search - Buscar issues
154
- * Parâmetros:
155
- * - owner (obrigatório): Proprietário do repositório
156
- * - repo (obrigatório): Nome do repositório
157
- * - query (obrigatório): Termo de busca
158
- * - author (opcional): Autor das issues
159
- * - assignee (opcional): Responsável pelas issues
160
- * - label (opcional): Label específico
161
- *
162
- * RECOMENDAÇÕES DE USO:
163
- * - Use títulos descritivos e claros
164
- * - Documente detalhes completos na descrição
165
- * - Atualize status regularmente
166
- * - Use labels para categorização
167
- * - Atribua responsáveis adequadamente
168
- * - Mantenha issues organizadas
201
+ * Code Scanner
202
+ * Escaneia código em busca de TODOs/FIXMEs
169
203
  */
170
- exports.issuesTool = {
171
- name: 'git-issues',
172
- description: 'tool: Gerencia issues Git, bugs, features e tarefas\n──────────────\naction create: cria nova issue\naction create requires: title, body, labels, assignees, milestone, provider\n───────────────\naction list: lista issues do repositório\naction list requires: state, page, provider\n───────────────\naction get: obtém detalhes de issue\naction get requires: issue_number, provider\n───────────────\naction update: atualiza issue existente\naction update requires: issue_number, new_title, new_body, new_state, new_labels, new_assignees, new_milestone, provider\n───────────────\naction close: fecha issue\naction close requires: issue_number, provider\n───────────────\naction comment: adiciona comentário\naction comment requires: issue_number, comment_body, provider\n───────────────\naction search: busca issues por critérios\naction search requires: query, author, assignee, label, provider',
173
- inputSchema: {
174
- type: 'object',
175
- properties: {
176
- action: {
177
- type: 'string',
178
- enum: ['create', 'list', 'get', 'update', 'close', 'comment', 'search'],
179
- description: 'Action to perform on issues'
180
- },
181
- projectPath: { type: 'string', description: 'Local project path for git operations' },
182
- provider: { type: 'string', description: 'Provider to use (github, gitea, or omit for default)' },
183
- title: { type: 'string', description: 'Issue title' },
184
- body: { type: 'string', description: 'Issue body/description' },
185
- labels: { type: 'array', items: { type: 'string' }, description: 'Issue labels' },
186
- assignees: { type: 'array', items: { type: 'string' }, description: 'Issue assignees' },
187
- milestone: { type: 'number', description: 'Milestone ID' },
188
- issue_number: { type: 'number', description: 'Issue number' },
189
- state: { type: 'string', enum: ['open', 'closed', 'all'], description: 'Issue state' },
190
- page: { type: 'number', description: 'Page number', minimum: 1 },
191
- new_title: { type: 'string', description: 'New issue title' },
192
- new_body: { type: 'string', description: 'New issue body' },
193
- new_state: { type: 'string', enum: ['open', 'closed'], description: 'New issue state' },
194
- new_labels: { type: 'array', items: { type: 'string' }, description: 'New issue labels' },
195
- new_assignees: { type: 'array', items: { type: 'string' }, description: 'New issue assignees' },
196
- new_milestone: { type: 'number', description: 'New milestone ID' },
197
- comment_body: { type: 'string', description: 'Comment content' },
198
- query: { type: 'string', description: 'Search query' },
199
- author: { type: 'string', description: 'Issue author filter' },
200
- assignee: { type: 'string', description: 'Issue assignee filter' },
201
- label: { type: 'string', description: 'Issue label filter' }
202
- },
203
- required: ['action', 'repo', 'provider', 'projectPath']
204
- },
205
- /**
206
- * Handler principal da tool issues
207
- *
208
- * FUNCIONALIDADE:
209
- * - Valida entrada usando Zod schema
210
- * - Roteia para método específico baseado na ação
211
- * - Trata erros de forma uniforme
212
- * - Retorna resultado padronizado
213
- *
214
- * FLUXO:
215
- * 1. Validação de entrada
216
- * 2. Seleção do provider
217
- * 3. Roteamento por ação
218
- * 4. Execução do método específico
219
- * 5. Tratamento de erros
220
- * 6. Retorno de resultado
221
- *
222
- * TRATAMENTO DE ERROS:
223
- * - Validação: erro de schema
224
- * - Execução: erro da operação
225
- * - Roteamento: ação não suportada
226
- *
227
- * RECOMENDAÇÕES:
228
- * - Sempre valide entrada antes de processar
229
- * - Trate erros específicos adequadamente
230
- * - Log detalhes de erro para debug
231
- * - Retorne mensagens de erro úteis
232
- */
233
- async handler(input) {
204
+ class CodeScanner {
205
+ static async scanForTodos(projectPath, customPatterns) {
206
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
207
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
208
+ const todos = [];
209
+ // Default patterns
210
+ const patterns = customPatterns || [
211
+ '**/*.js', '**/*.ts', '**/*.py', '**/*.java', '**/*.cpp', '**/*.c',
212
+ '**/*.php', '**/*.rb', '**/*.go', '**/*.rs', '**/*.swift',
213
+ '**/*.kt', '**/*.scala', '**/*.clj', '**/*.hs', '**/*.ml'
214
+ ];
215
+ // Simple file scanning (could be enhanced with glob patterns)
234
216
  try {
235
- const validatedInput = IssuesInputSchema.parse(input);
236
- // Aplicar extração automática do nome do repositório
237
- const processedInput = (0, user_detection_js_1.applyAutoRepoExtraction)(validatedInput);
238
- // Aplicar auto-detecção de usuário/owner
239
- const finalInput = await (0, user_detection_js_1.applyAutoUserDetection)(processedInput, processedInput.provider);
240
- // Obter o provider correto (sem fallback quando informado)
241
- let provider;
242
- try {
243
- if (finalInput.provider) {
244
- const requestedProvider = index_js_1.globalProviderFactory.getProvider(finalInput.provider);
245
- if (!requestedProvider) {
246
- throw new Error(`Provider '${finalInput.provider}' não encontrado`);
217
+ const scanDir = async (dir) => {
218
+ const entries = await fs.readdir(dir, { withFileTypes: true });
219
+ for (const entry of entries) {
220
+ const fullPath = path.join(dir, entry.name);
221
+ const relativePath = path.relative(projectPath, fullPath);
222
+ if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
223
+ await scanDir(fullPath);
224
+ }
225
+ else if (entry.isFile()) {
226
+ // Check if file matches patterns
227
+ const shouldScan = patterns.some(pattern => {
228
+ const regex = new RegExp(pattern.replace(/\*/g, '.*').replace(/\//g, '\\/'));
229
+ return regex.test(relativePath);
230
+ });
231
+ if (shouldScan) {
232
+ try {
233
+ const content = await fs.readFile(fullPath, 'utf-8');
234
+ const lines = content.split('\n');
235
+ lines.forEach((line, index) => {
236
+ const todo = LocalIssueManager.parseTodoComment(line, relativePath, index + 1);
237
+ if (todo) {
238
+ todos.push(todo);
239
+ }
240
+ });
241
+ }
242
+ catch (e) {
243
+ // Skip files that can't be read
244
+ }
245
+ }
247
246
  }
248
- provider = requestedProvider;
249
- }
250
- else {
251
- throw new Error("Parâmetro 'provider' é obrigatório e não pode ser omitido");
252
- }
253
- if (!provider) {
254
- throw new Error('Nenhum provider disponível');
255
247
  }
256
- }
257
- catch (providerError) {
258
- console.error('[ISSUES] Erro ao obter provider:', providerError);
259
- throw new Error(`Erro de configuração do provider: ${providerError instanceof Error ? providerError.message : 'Provider não disponível'}`);
260
- }
261
- // Obter o owner do provider
262
- const owner = (await provider.getCurrentUser()).login;
263
- switch (finalInput.action) {
264
- case 'create':
265
- return await this.createIssue(finalInput, provider, owner);
266
- case 'list':
267
- return await this.listIssues(finalInput, provider, owner);
268
- case 'get':
269
- return await this.getIssue(finalInput, provider, owner);
270
- case 'update':
271
- return await this.updateIssue(finalInput, provider, owner);
272
- case 'close':
273
- return await this.closeIssue(finalInput, provider, owner);
274
- case 'comment':
275
- return await this.addComment(finalInput, provider, owner);
276
- case 'search':
277
- return await this.searchIssues(finalInput, provider, owner);
278
- default:
279
- throw new Error(`Ação não suportada: ${finalInput.action}`);
280
- }
248
+ };
249
+ await scanDir(projectPath);
281
250
  }
282
251
  catch (error) {
283
- return {
284
- success: false,
285
- action: input.action,
286
- message: 'Erro na operação de issues',
287
- error: error instanceof Error ? error.message : String(error)
288
- };
252
+ console.warn('Error scanning code:', error);
289
253
  }
290
- },
254
+ return todos;
255
+ }
256
+ }
257
+ /**
258
+ * Classe principal para executar operações Git issues
259
+ */
260
+ class GitIssuesExecutor {
261
+ errorHandler = new error_handler_js_1.UniversalErrorHandler();
291
262
  /**
292
- * Cria uma nova issue no repositório
293
- *
294
- * FUNCIONALIDADE:
295
- * - Cria issue com título e descrição
296
- * - Suporta labels, assignees e milestone
297
- * - Retorna detalhes da issue criada
298
- *
299
- * PARÂMETROS OBRIGATÓRIOS:
300
- * - owner: Proprietário do repositório
301
- * - repo: Nome do repositório
302
- * - title: Título da issue
303
- *
304
- * PARÂMETROS OPCIONAIS:
305
- * - body: Descrição detalhada
306
- * - labels: Array de labels para categorização
307
- * - assignees: Array de usuários responsáveis
308
- * - milestone: ID do milestone associado
309
- *
310
- * VALIDAÇÕES:
311
- * - Todos os parâmetros obrigatórios
312
- * - Título deve ser único no repositório
313
- * - Labels devem existir no repositório
314
- * - Assignees devem ser usuários válidos
315
- *
316
- * RECOMENDAÇÕES:
317
- * - Use títulos descritivos e claros
318
- * - Documente detalhes completos
319
- * - Use labels para categorização
320
- * - Atribua responsáveis adequadamente
263
+ * Executa operação create
321
264
  */
322
- async createIssue(params, provider, owner) {
265
+ async executeCreate(detection, input) {
323
266
  try {
324
- // Repo é extraído automaticamente do projectPath
325
- if (!params.title || typeof params.title !== 'string' || params.title.trim().length === 0) {
326
- throw new Error('Title é obrigatório e deve conter texto');
327
- }
328
- const issue = await provider.createIssue(owner, params.repo, params.title, params.body, params.assignees, params.labels);
329
- return {
267
+ const issues = await LocalIssueManager.loadIssues(detection.projectPath);
268
+ const newIssue = {
269
+ id: LocalIssueManager.generateIssueId(),
270
+ title: input.title,
271
+ description: input.description || '',
272
+ state: 'open',
273
+ labels: input.labels || [],
274
+ priority: input.priority,
275
+ assignee: input.assignee || detection.owner,
276
+ createdAt: new Date().toISOString(),
277
+ updatedAt: new Date().toISOString(),
278
+ dueDate: input.dueDate || null,
279
+ comments: [],
280
+ source: {
281
+ type: 'manual',
282
+ createdBy: detection.owner
283
+ }
284
+ };
285
+ issues.push(newIssue);
286
+ await LocalIssueManager.saveIssues(detection.projectPath, issues);
287
+ return (0, auto_detection_js_1.createUniversalResponse)({
330
288
  success: true,
331
289
  action: 'create',
332
- message: `Issue '${params.title}' criada com sucesso`,
333
- data: issue
334
- };
290
+ message: `Issue '${input.title}' created successfully`,
291
+ data: {
292
+ issue: newIssue,
293
+ issueId: newIssue.id
294
+ },
295
+ autoDetected: {
296
+ repo: detection.repoName,
297
+ owner: detection.owner,
298
+ providers: detection.providers
299
+ }
300
+ });
335
301
  }
336
302
  catch (error) {
337
- throw new Error(`Falha ao criar issue: ${error instanceof Error ? error.message : String(error)}`);
303
+ return this.errorHandler.toUniversalResponse();
338
304
  }
339
- },
305
+ }
340
306
  /**
341
- * Lista issues do repositório
342
- *
343
- * FUNCIONALIDADE:
344
- * - Lista issues com filtros de estado
345
- * - Suporta paginação
346
- * - Retorna informações básicas de cada issue
347
- *
348
- * PARÂMETROS OBRIGATÓRIOS:
349
- * - owner: Proprietário do repositório
350
- * - repo: Nome do repositório
351
- *
352
- * PARÂMETROS OPCIONAIS:
353
- * - state: Estado das issues (open, closed, all) - padrão: open
354
- * - page: Página da listagem (padrão: 1)
355
- * - limit: Itens por página (padrão: 30, máximo: 100)
356
- *
357
- * VALIDAÇÕES:
358
- * - e repo obrigatórios
359
- * - State deve ser um dos valores válidos
360
- * - Page deve ser >= 1
361
- * - Limit deve ser entre 1 e 100
362
- *
363
- * RECOMENDAÇÕES:
364
- * - Use paginação para repositórios com muitas issues
365
- * - Monitore número total de issues
366
- * - Filtre por estado para organização
367
- * - Mantenha issues organizadas
307
+ * Executa operação list
368
308
  */
369
- async listIssues(params, provider, owner) {
309
+ async executeList(detection, input) {
370
310
  try {
371
- // Repo é extraído automaticamente do projectPath
372
- const state = params.state || 'open';
373
- const page = params.page || 1;
374
- const issues = await provider.listIssues((await provider.getCurrentUser()).login, params.repo, state, page);
375
- return {
311
+ const allIssues = await LocalIssueManager.loadIssues(detection.projectPath);
312
+ // Filter issues
313
+ let filteredIssues = allIssues;
314
+ if (input.state !== 'all') {
315
+ filteredIssues = filteredIssues.filter(issue => issue.state === input.state);
316
+ }
317
+ if (input.labels && input.labels.length > 0) {
318
+ filteredIssues = filteredIssues.filter(issue => input.labels.some((label) => issue.labels.includes(label)));
319
+ }
320
+ if (input.priority) {
321
+ filteredIssues = filteredIssues.filter(issue => issue.priority === input.priority);
322
+ }
323
+ // Sort issues
324
+ filteredIssues.sort((a, b) => {
325
+ switch (input.sort) {
326
+ case 'updated':
327
+ return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
328
+ case 'priority':
329
+ const priorityOrder = { urgent: 4, high: 3, medium: 2, low: 1 };
330
+ return priorityOrder[b.priority] - priorityOrder[a.priority];
331
+ case 'due_date':
332
+ if (!a.dueDate && !b.dueDate)
333
+ return 0;
334
+ if (!a.dueDate)
335
+ return 1;
336
+ if (!b.dueDate)
337
+ return -1;
338
+ return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
339
+ case 'created':
340
+ default:
341
+ return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
342
+ }
343
+ });
344
+ const limitedIssues = filteredIssues.slice(0, input.limit);
345
+ return (0, auto_detection_js_1.createUniversalResponse)({
376
346
  success: true,
377
347
  action: 'list',
378
- message: `${issues.length} issues ${state} encontradas`,
348
+ message: `Found ${limitedIssues.length} issues`,
379
349
  data: {
380
- issues,
381
- state,
382
- page,
383
- total: issues.length
350
+ issues: limitedIssues,
351
+ total: allIssues.length,
352
+ filtered: filteredIssues.length,
353
+ state: input.state,
354
+ labels: input.labels,
355
+ priority: input.priority,
356
+ sort: input.sort,
357
+ limit: input.limit
358
+ },
359
+ autoDetected: {
360
+ repo: detection.repoName,
361
+ owner: detection.owner,
362
+ providers: detection.providers
384
363
  }
385
- };
364
+ });
386
365
  }
387
366
  catch (error) {
388
- throw new Error(`Falha ao listar issues: ${error instanceof Error ? error.message : String(error)}`);
367
+ return this.errorHandler.toUniversalResponse();
389
368
  }
390
- },
369
+ }
391
370
  /**
392
- * Obtém detalhes de uma issue específica
393
- *
394
- * FUNCIONALIDADE:
395
- * - Retorna informações completas da issue
396
- * - Inclui título, descrição, labels, assignees
397
- * - Mostra histórico de comentários
398
- *
399
- * PARÂMETROS OBRIGATÓRIOS:
400
- * - owner: Proprietário do repositório
401
- * - repo: Nome do repositório
402
- * - issue_number: Número da issue
403
- *
404
- * VALIDAÇÕES:
405
- * - Todos os parâmetros obrigatórios
406
- * - Issue deve existir no repositório
407
- * - Número deve ser válido
408
- *
409
- * RECOMENDAÇÕES:
410
- * - Use para obter detalhes completos
411
- * - Verifique status e labels
412
- * - Analise comentários e histórico
413
- * - Monitore mudanças importantes
371
+ * Executa operação get
414
372
  */
415
- async getIssue(params, provider, owner) {
373
+ async executeGet(detection, input) {
416
374
  try {
417
- // Repo é extraído automaticamente do projectPath
418
- if (!params.issue_number || typeof params.issue_number !== 'number') {
419
- throw new Error('Issue_number é obrigatório e deve ser um número válido');
375
+ const issues = await LocalIssueManager.loadIssues(detection.projectPath);
376
+ const issue = issues.find(i => i.id === input.id);
377
+ if (!issue) {
378
+ return (0, auto_detection_js_1.createUniversalResponse)({
379
+ success: false,
380
+ action: 'get',
381
+ message: `Issue '${input.id}' not found`,
382
+ error: {
383
+ code: 'ISSUE_NOT_FOUND',
384
+ message: `Issue with ID '${input.id}' does not exist`,
385
+ cause: 'Issue not found in local storage',
386
+ suggestion: 'Check the issue ID or list all issues to see available IDs'
387
+ },
388
+ autoDetected: {
389
+ repo: detection.repoName,
390
+ owner: detection.owner,
391
+ providers: detection.providers
392
+ }
393
+ });
420
394
  }
421
- const issue = await provider.getIssue((await provider.getCurrentUser()).login, params.repo, params.issue_number);
422
- return {
395
+ return (0, auto_detection_js_1.createUniversalResponse)({
423
396
  success: true,
424
397
  action: 'get',
425
- message: `Issue #${params.issue_number} obtida com sucesso`,
426
- data: issue
427
- };
398
+ message: `Issue '${issue.title}' details`,
399
+ data: {
400
+ issue: issue,
401
+ detailed: input.detailed
402
+ },
403
+ autoDetected: {
404
+ repo: detection.repoName,
405
+ owner: detection.owner,
406
+ providers: detection.providers
407
+ }
408
+ });
428
409
  }
429
410
  catch (error) {
430
- throw new Error(`Falha ao obter issue: ${error instanceof Error ? error.message : String(error)}`);
411
+ return this.errorHandler.toUniversalResponse();
431
412
  }
432
- },
413
+ }
433
414
  /**
434
- * Atualiza uma issue existente
435
- *
436
- * FUNCIONALIDADE:
437
- * - Atualiza campos da issue
438
- * - Suporta mudança de estado
439
- * - Permite alteração de labels e assignees
440
- *
441
- * PARÂMETROS OBRIGATÓRIOS:
442
- * - owner: Proprietário do repositório
443
- * - repo: Nome do repositório
444
- * - issue_number: Número da issue
445
- *
446
- * PARÂMETROS OPCIONAIS:
447
- * - new_title: Novo título
448
- * - new_body: Nova descrição
449
- * - new_state: Novo estado
450
- * - new_labels: Novos labels
451
- * - new_assignees: Novos responsáveis
452
- * - new_milestone: Novo milestone
453
- *
454
- * VALIDAÇÕES:
455
- * - Todos os parâmetros obrigatórios
456
- * - Issue deve existir
457
- * - Pelo menos um campo deve ser atualizado
458
- *
459
- * RECOMENDAÇÕES:
460
- * - Atualize apenas campos necessários
461
- * - Use mensagens de commit descritivas
462
- * - Documente mudanças importantes
463
- * - Notifique responsáveis sobre mudanças
415
+ * Executa operação update
464
416
  */
465
- async updateIssue(params, provider, owner) {
417
+ async executeUpdate(detection, input) {
466
418
  try {
467
- // Validação de parâmetros obrigatórios
468
- if (!params.issue_number || typeof params.issue_number !== 'number') {
469
- throw new Error('Issue_number é obrigatório e deve ser um número válido');
419
+ const issues = await LocalIssueManager.loadIssues(detection.projectPath);
420
+ const issueIndex = issues.findIndex(i => i.id === input.id);
421
+ if (issueIndex === -1) {
422
+ throw new Error(`Issue '${input.id}' not found`);
470
423
  }
471
- const updateData = {};
472
- if (params.new_title)
473
- updateData.title = params.new_title;
474
- if (params.new_body !== undefined)
475
- updateData.body = params.new_body;
476
- if (params.new_state)
477
- updateData.state = params.new_state;
478
- if (params.new_labels)
479
- updateData.labels = params.new_labels;
480
- if (params.new_assignees)
481
- updateData.assignees = params.new_assignees;
482
- if (params.new_milestone !== undefined)
483
- updateData.milestone = params.new_milestone;
484
- if (Object.keys(updateData).length === 0) {
485
- throw new Error('Nenhum campo para atualizar foi fornecido');
486
- }
487
- const issue = await provider.updateIssue((await provider.getCurrentUser()).login, params.repo, params.issue_number, updateData);
488
- return {
424
+ const issue = issues[issueIndex];
425
+ const updatedIssue = {
426
+ ...issue,
427
+ ...Object.fromEntries(Object.entries(input).filter(([key, value]) => key !== 'id' && key !== 'projectPath' && key !== 'action' && value !== undefined)),
428
+ updatedAt: new Date().toISOString()
429
+ };
430
+ issues[issueIndex] = updatedIssue;
431
+ await LocalIssueManager.saveIssues(detection.projectPath, issues);
432
+ return (0, auto_detection_js_1.createUniversalResponse)({
489
433
  success: true,
490
434
  action: 'update',
491
- message: `Issue #${params.issue_number} atualizada com sucesso`,
492
- data: issue
493
- };
435
+ message: `Issue '${updatedIssue.title}' updated successfully`,
436
+ data: {
437
+ issue: updatedIssue,
438
+ changes: Object.keys(input).filter(key => key !== 'id' && key !== 'projectPath' && key !== 'action')
439
+ },
440
+ autoDetected: {
441
+ repo: detection.repoName,
442
+ owner: detection.owner,
443
+ providers: detection.providers
444
+ }
445
+ });
494
446
  }
495
447
  catch (error) {
496
- throw new Error(`Falha ao atualizar issue: ${error instanceof Error ? error.message : String(error)}`);
448
+ return this.errorHandler.toUniversalResponse();
497
449
  }
498
- },
450
+ }
499
451
  /**
500
- * Fecha uma issue
501
- *
502
- * FUNCIONALIDADE:
503
- * - Altera estado da issue para closed
504
- * - Mantém histórico e comentários
505
- * - Permite reabertura posterior
506
- *
507
- * PARÂMETROS OBRIGATÓRIOS:
508
- * - owner: Proprietário do repositório
509
- * - repo: Nome do repositório
510
- * - issue_number: Número da issue
511
- *
512
- * VALIDAÇÕES:
513
- * - Todos os parâmetros obrigatórios
514
- * - Issue deve existir
515
- * - Issue deve estar aberta
516
- *
517
- * RECOMENDAÇÕES:
518
- * - Confirme que issue foi resolvida
519
- * - Documente solução aplicada
520
- * - Use comentário explicativo
521
- * - Verifique se não há dependências
452
+ * Executa operação close
522
453
  */
523
- async closeIssue(params, provider, owner) {
454
+ async executeClose(detection, input) {
524
455
  try {
525
- // Validação de parâmetros obrigatórios
526
- if (!params.issue_number || typeof params.issue_number !== 'number') {
527
- throw new Error('Issue_number é obrigatório e deve ser um número válido');
456
+ const issues = await LocalIssueManager.loadIssues(detection.projectPath);
457
+ const issueIndex = issues.findIndex(i => i.id === input.id);
458
+ if (issueIndex === -1) {
459
+ throw new Error(`Issue '${input.id}' not found`);
460
+ }
461
+ const issue = issues[issueIndex];
462
+ // Add closing comment if provided
463
+ if (input.comment) {
464
+ issue.comments = issue.comments || [];
465
+ issue.comments.push({
466
+ id: `C-${Date.now()}`,
467
+ author: detection.owner,
468
+ content: input.comment,
469
+ createdAt: new Date().toISOString(),
470
+ type: 'closing'
471
+ });
528
472
  }
529
- const issue = await provider.updateIssue((await provider.getCurrentUser()).login, params.repo, params.issue_number, { state: 'closed' });
530
- return {
473
+ issue.state = 'closed';
474
+ issue.updatedAt = new Date().toISOString();
475
+ issue.closedAt = new Date().toISOString();
476
+ await LocalIssueManager.saveIssues(detection.projectPath, issues);
477
+ return (0, auto_detection_js_1.createUniversalResponse)({
531
478
  success: true,
532
479
  action: 'close',
533
- message: `Issue #${params.issue_number} fechada com sucesso`,
534
- data: issue
535
- };
480
+ message: `Issue '${issue.title}' closed successfully`,
481
+ data: {
482
+ issue: issue,
483
+ comment: input.comment
484
+ },
485
+ autoDetected: {
486
+ repo: detection.repoName,
487
+ owner: detection.owner,
488
+ providers: detection.providers
489
+ }
490
+ });
536
491
  }
537
492
  catch (error) {
538
- throw new Error(`Falha ao fechar issue: ${error instanceof Error ? error.message : String(error)}`);
493
+ return this.errorHandler.toUniversalResponse();
539
494
  }
540
- },
495
+ }
541
496
  /**
542
- * Adiciona comentário a uma issue
543
- *
544
- * FUNCIONALIDADE:
545
- * - Cria novo comentário na issue
546
- * - Mantém histórico de discussão
547
- * - Suporta formatação Markdown
548
- *
549
- * PARÂMETROS OBRIGATÓRIOS:
550
- * - owner: Proprietário do repositório
551
- * - repo: Nome do repositório
552
- * - issue_number: Número da issue
553
- * - comment_body: Conteúdo do comentário
554
- *
555
- * VALIDAÇÕES:
556
- * - Todos os parâmetros obrigatórios
557
- * - Issue deve existir
558
- * - Comentário não pode estar vazio
559
- *
560
- * RECOMENDAÇÕES:
561
- * - Use comentários para atualizações
562
- * - Documente progresso e decisões
563
- * - Use formatação Markdown adequadamente
564
- * - Mantenha comentários relevantes
497
+ * Executa operação scan
565
498
  */
566
- async addComment(params, provider, owner) {
499
+ async executeScan(detection, input) {
567
500
  try {
568
- // Validação de parâmetros obrigatórios
569
- if (!params.issue_number || typeof params.issue_number !== 'number') {
570
- throw new Error('Issue_number é obrigatório e deve ser um número válido');
571
- }
572
- if (!params.comment_body || typeof params.comment_body !== 'string' || params.comment_body.trim().length === 0) {
573
- throw new Error('Comment_body é obrigatório e deve conter texto');
574
- }
575
- // Verificar se a issue existe
576
- try {
577
- await provider.getIssue(owner, params.repo, params.issue_number);
578
- }
579
- catch (error) {
580
- throw new Error(`Issue #${params.issue_number} não encontrada no repositório ${owner}/${params.repo}`);
501
+ const todos = await CodeScanner.scanForTodos(detection.projectPath, input.patterns);
502
+ let createdIssues = [];
503
+ if (input.createIssues && todos.length > 0) {
504
+ const existingIssues = await LocalIssueManager.loadIssues(detection.projectPath);
505
+ // Create issues for new TODOs (avoid duplicates)
506
+ for (const todo of todos) {
507
+ const alreadyExists = existingIssues.some(issue => issue.source?.type === 'code-scan' &&
508
+ issue.source.file === todo.file &&
509
+ issue.source.line === todo.line &&
510
+ issue.source.originalComment === todo.raw);
511
+ if (!alreadyExists) {
512
+ const newIssue = LocalIssueManager.createIssueFromTodo(todo, detection.projectPath);
513
+ existingIssues.push(newIssue);
514
+ createdIssues.push(newIssue);
515
+ }
516
+ }
517
+ await LocalIssueManager.saveIssues(detection.projectPath, existingIssues);
581
518
  }
582
- // Adicionar comentário usando o provider
583
- const comment = await provider.addComment(owner, params.repo, params.issue_number, params.comment_body.trim());
584
- return {
519
+ return (0, auto_detection_js_1.createUniversalResponse)({
585
520
  success: true,
586
- action: 'comment',
587
- message: `Comentário adicionado à issue #${params.issue_number} com sucesso`,
521
+ action: 'scan',
522
+ message: `Found ${todos.length} TODOs/FIXMEs in code`,
588
523
  data: {
589
- issue_number: params.issue_number,
590
- comment: comment,
591
- body: params.comment_body,
592
- created_at: comment.created_at,
593
- updated_at: comment.updated_at,
594
- user: comment.user,
595
- html_url: comment.html_url
524
+ todos: todos,
525
+ totalFound: todos.length,
526
+ createdIssues: createdIssues.length,
527
+ issuesCreated: createdIssues,
528
+ createIssues: input.createIssues,
529
+ patterns: input.patterns
530
+ },
531
+ autoDetected: {
532
+ repo: detection.repoName,
533
+ owner: detection.owner,
534
+ providers: detection.providers
596
535
  }
597
- };
536
+ });
598
537
  }
599
538
  catch (error) {
600
- throw new Error(`Falha ao adicionar comentário: ${error instanceof Error ? error.message : String(error)}`);
539
+ return this.errorHandler.toUniversalResponse();
601
540
  }
541
+ }
542
+ }
543
+ /**
544
+ * Tool principal git-issues
545
+ */
546
+ exports.gitIssuesTool = {
547
+ name: 'git-issues',
548
+ description: `📋 SISTEMA DE ISSUES PARA DESENVOLVEDOR INDIVIDUAL
549
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
550
+ 🎯 ISSUES LOCAIS INTELIGENTES:
551
+ • create: Criação de issues com prioridade e labels
552
+ • list: Listagem com filtros avançados
553
+ • get: Detalhes completos de issues
554
+ • update: Atualização de status e informações
555
+ • close: Fechamento com comentários
556
+ • scan: Auto-detecção de TODOs/FIXMEs no código
557
+
558
+ 🔍 GERENCIAMENTO DE TAREFAS:
559
+ • Sistema local (sem dependência de GitHub/Gitea)
560
+ • Priorização automática baseada em tipo
561
+ • Labels inteligentes (bug, feature, todo, etc.)
562
+ • Auto-detecção de TODOs no código
563
+ • Rastreamento de progresso
564
+
565
+ ⚡ PRODUTIVIDADE PESSOAL:
566
+ • Issues criadas automaticamente de comentários
567
+ • Sistema de prioridades (urgent, high, medium, low)
568
+ • Datas de vencimento e responsáveis
569
+ • Histórico completo de mudanças
570
+ • Integração com workflow pessoal
571
+
572
+ 🤖 COMPATÍVEL COM AI AGENTS:
573
+ • Interface universal para qualquer IDE
574
+ • Auto-detecção completa de contexto
575
+ • Respostas estruturadas consistentes
576
+ • Error handling inteligente
577
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
578
+ inputSchema: {
579
+ type: 'object',
580
+ properties: {
581
+ action: {
582
+ type: 'string',
583
+ enum: ['create', 'list', 'get', 'update', 'close', 'scan'],
584
+ description: 'Ação do sistema de issues'
585
+ },
586
+ projectPath: {
587
+ type: 'string',
588
+ description: 'Caminho absoluto do projeto'
589
+ },
590
+ title: {
591
+ type: 'string',
592
+ description: 'Título da issue'
593
+ },
594
+ description: {
595
+ type: 'string',
596
+ description: 'Descrição da issue'
597
+ },
598
+ labels: {
599
+ type: 'array',
600
+ items: { type: 'string' },
601
+ description: 'Labels da issue'
602
+ },
603
+ priority: {
604
+ type: 'string',
605
+ enum: ['low', 'medium', 'high', 'urgent'],
606
+ description: 'Prioridade da issue'
607
+ },
608
+ assignee: {
609
+ type: 'string',
610
+ description: 'Responsável pela issue'
611
+ },
612
+ dueDate: {
613
+ type: 'string',
614
+ description: 'Data de vencimento (ISO string)'
615
+ },
616
+ state: {
617
+ type: 'string',
618
+ enum: ['open', 'closed', 'all'],
619
+ description: 'Estado da issue'
620
+ },
621
+ id: {
622
+ type: 'string',
623
+ description: 'ID da issue'
624
+ },
625
+ detailed: {
626
+ type: 'boolean',
627
+ description: 'Informações detalhadas'
628
+ },
629
+ comment: {
630
+ type: 'string',
631
+ description: 'Comentário para fechamento'
632
+ },
633
+ createIssues: {
634
+ type: 'boolean',
635
+ description: 'Criar issues automaticamente dos TODOs'
636
+ },
637
+ patterns: {
638
+ type: 'array',
639
+ items: { type: 'string' },
640
+ description: 'Padrões customizados para scan'
641
+ },
642
+ limit: {
643
+ type: 'number',
644
+ description: 'Limite de resultados'
645
+ },
646
+ sort: {
647
+ type: 'string',
648
+ enum: ['created', 'updated', 'priority', 'due_date'],
649
+ description: 'Critério de ordenação'
650
+ }
651
+ },
652
+ required: ['action', 'projectPath']
602
653
  },
603
- /**
604
- * Busca issues por critérios específicos
605
- *
606
- * FUNCIONALIDADE:
607
- * - Busca issues por conteúdo
608
- * - Filtra por autor, assignee e label
609
- * - Retorna resultados relevantes
610
- *
611
- * PARÂMETROS OBRIGATÓRIOS:
612
- * - owner: Proprietário do repositório
613
- * - repo: Nome do repositório
614
- * - query: Termo de busca
615
- *
616
- * PARÂMETROS OPCIONAIS:
617
- * - author: Autor das issues
618
- * - assignee: Responsável pelas issues
619
- * - label: Label específico
620
- *
621
- * VALIDAÇÕES:
622
- * - Todos os parâmetros obrigatórios
623
- * - Query deve ter pelo menos 3 caracteres
624
- * - Repositório deve existir
625
- *
626
- * RECOMENDAÇÕES:
627
- * - Use termos de busca específicos
628
- * - Combine filtros para resultados precisos
629
- * - Analise relevância dos resultados
630
- * - Use para encontrar issues relacionadas
631
- */
632
- async searchIssues(params, provider, owner) {
654
+ async handler(input) {
655
+ const executor = new GitIssuesExecutor();
633
656
  try {
634
- // Validação de parâmetros obrigatórios
635
- if (!params.query || typeof params.query !== 'string') {
636
- throw new Error('Query é obrigatório e deve ser uma string válida');
637
- }
638
- if (params.query.trim().length < 3) {
639
- throw new Error('Query deve ter pelo menos 3 caracteres');
640
- }
641
- const page = params.page || 1;
642
- // Buscar issues usando o provider
643
- let searchResults = [];
644
- if (provider.searchIssues) {
645
- searchResults = await provider.searchIssues(owner, params.repo, params.query, params.author || undefined, params.assignee || undefined, params.label || undefined);
646
- }
647
- else {
648
- // Fallback: buscar todas as issues e filtrar localmente
649
- const allIssues = await provider.listIssues((await provider.getCurrentUser()).login, params.repo, 'all', 1);
650
- searchResults = allIssues.filter((issue) => issue.title?.toLowerCase().includes(params.query?.toLowerCase() || '') ||
651
- issue.body?.toLowerCase().includes(params.query?.toLowerCase() || ''));
652
- }
653
- // Aplicar filtros adicionais se especificados
654
- let filteredResults = searchResults;
655
- if (params.author) {
656
- filteredResults = filteredResults.filter((issue) => issue.user?.login?.toLowerCase().includes(params.author.toLowerCase()));
657
- }
658
- if (params.assignee) {
659
- filteredResults = filteredResults.filter((issue) => issue.assignees?.some((assignee) => assignee.login?.toLowerCase().includes(params.assignee.toLowerCase())));
660
- }
661
- if (params.label) {
662
- filteredResults = filteredResults.filter((issue) => issue.labels?.some((label) => label.name?.toLowerCase().includes(params.label.toLowerCase())));
657
+ // Validate input
658
+ const validatedInput = GitIssuesInputSchema.parse(input);
659
+ // Auto-detect context
660
+ const detection = await (0, auto_detection_js_1.autoDetect)(validatedInput.projectPath);
661
+ await (0, auto_detection_js_1.validateAutoDetection)(detection);
662
+ // Execute specific action
663
+ switch (validatedInput.action) {
664
+ case 'create':
665
+ return await executor['executeCreate'](detection, validatedInput);
666
+ case 'list':
667
+ return await executor['executeList'](detection, validatedInput);
668
+ case 'get':
669
+ return await executor['executeGet'](detection, validatedInput);
670
+ case 'update':
671
+ return await executor['executeUpdate'](detection, validatedInput);
672
+ case 'close':
673
+ return await executor['executeClose'](detection, validatedInput);
674
+ case 'scan':
675
+ return await executor['executeScan'](detection, validatedInput);
676
+ default:
677
+ throw new Error(`Ação '${validatedInput.action}' não suportada`);
663
678
  }
664
- return {
665
- success: true,
666
- action: 'search',
667
- message: `${filteredResults.length} issues encontradas para '${params.query}'`,
668
- data: {
669
- query: params.query,
670
- author: params.author || 'todos',
671
- assignee: params.assignee || 'todos',
672
- label: params.label || 'todos',
673
- page,
674
- total_found: searchResults.length,
675
- results: filteredResults,
676
- summary: {
677
- total_issues: searchResults.length,
678
- filtered_issues: filteredResults.length,
679
- states: {
680
- open: filteredResults.filter((i) => i.state === 'open').length,
681
- closed: filteredResults.filter((i) => i.state === 'closed').length
682
- },
683
- labels: [...new Set(filteredResults.flatMap((i) => i.labels?.map((l) => l.name) || []).filter(Boolean))],
684
- assignees: [...new Set(filteredResults.flatMap((i) => i.assignees?.map((a) => a.login) || []).filter(Boolean))]
685
- }
686
- }
687
- };
688
679
  }
689
680
  catch (error) {
690
- throw new Error(`Falha ao buscar issues: ${error instanceof Error ? error.message : String(error)}`);
681
+ executor.errorHandler.addError(error);
682
+ return executor.errorHandler.toUniversalResponse();
691
683
  }
692
684
  }
693
685
  };