@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.
- package/EXEMPLOS.md +861 -0
- package/INSTRUCOES.md +444 -0
- package/README.md +63 -283
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/base-provider.js +3 -26
- package/dist/providers/base-provider.js.map +1 -1
- package/dist/providers/gitea-provider.d.ts +0 -2
- package/dist/providers/gitea-provider.d.ts.map +1 -1
- package/dist/providers/gitea-provider.js +0 -62
- package/dist/providers/gitea-provider.js.map +1 -1
- package/dist/providers/github-provider.d.ts +0 -2
- package/dist/providers/github-provider.d.ts.map +1 -1
- package/dist/providers/github-provider.js +48 -105
- package/dist/providers/github-provider.js.map +1 -1
- package/dist/server.d.ts +0 -27
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +130 -1215
- package/dist/server.js.map +1 -1
- package/dist/tools/{git-commits.d.ts → git-analytics.d.ts} +4 -10
- package/dist/tools/git-analytics.d.ts.map +1 -0
- package/dist/tools/git-analytics.js +18 -0
- package/dist/tools/git-analytics.js.map +1 -0
- package/dist/tools/git-archive.d.ts +3 -0
- package/dist/tools/git-archive.d.ts.map +1 -1
- package/dist/tools/git-archive.js +2 -2
- package/dist/tools/git-archive.js.map +1 -1
- package/dist/tools/git-backup.d.ts +216 -0
- package/dist/tools/git-backup.d.ts.map +1 -0
- package/dist/tools/git-backup.js +813 -0
- package/dist/tools/git-backup.js.map +1 -0
- package/dist/tools/git-branches.d.ts +159 -8
- package/dist/tools/git-branches.d.ts.map +1 -1
- package/dist/tools/git-branches.js +554 -2
- package/dist/tools/git-branches.js.map +1 -1
- package/dist/tools/git-config.d.ts +3 -0
- package/dist/tools/git-config.d.ts.map +1 -1
- package/dist/tools/git-config.js +2 -2
- package/dist/tools/git-config.js.map +1 -1
- package/dist/tools/git-files.d.ts +130 -8
- package/dist/tools/git-files.d.ts.map +1 -1
- package/dist/tools/git-files.js +426 -2
- package/dist/tools/git-files.js.map +1 -1
- package/dist/tools/git-issues.d.ts +137 -471
- package/dist/tools/git-issues.d.ts.map +1 -1
- package/dist/tools/git-issues.js +605 -613
- package/dist/tools/git-issues.js.map +1 -1
- package/dist/tools/git-monitor.d.ts +161 -0
- package/dist/tools/git-monitor.d.ts.map +1 -0
- package/dist/tools/git-monitor.js +746 -0
- package/dist/tools/git-monitor.js.map +1 -0
- package/dist/tools/git-packages.d.ts +5 -2
- package/dist/tools/git-packages.d.ts.map +1 -1
- package/dist/tools/git-packages.js +3 -3
- package/dist/tools/git-packages.js.map +1 -1
- package/dist/tools/git-pulls.d.ts +38 -646
- package/dist/tools/git-pulls.d.ts.map +1 -1
- package/dist/tools/git-pulls.js +64 -716
- package/dist/tools/git-pulls.js.map +1 -1
- package/dist/tools/git-release.d.ts +187 -0
- package/dist/tools/git-release.d.ts.map +1 -0
- package/dist/tools/git-release.js +619 -0
- package/dist/tools/git-release.js.map +1 -0
- package/dist/tools/git-remote.d.ts +112 -77
- package/dist/tools/git-remote.d.ts.map +1 -1
- package/dist/tools/git-remote.js +481 -183
- package/dist/tools/git-remote.js.map +1 -1
- package/dist/tools/git-repos.d.ts +19 -0
- package/dist/tools/git-repos.d.ts.map +1 -0
- package/dist/tools/git-repos.js +18 -0
- package/dist/tools/git-repos.js.map +1 -0
- package/dist/tools/git-reset.d.ts +121 -74
- package/dist/tools/git-reset.d.ts.map +1 -1
- package/dist/tools/git-reset.js +540 -159
- package/dist/tools/git-reset.js.map +1 -1
- package/dist/tools/git-stash.d.ts +119 -78
- package/dist/tools/git-stash.d.ts.map +1 -1
- package/dist/tools/git-stash.js +560 -209
- package/dist/tools/git-stash.js.map +1 -1
- package/dist/tools/git-sync.d.ts +3 -163
- package/dist/tools/git-sync.d.ts.map +1 -1
- package/dist/tools/git-sync.js +9 -326
- package/dist/tools/git-sync.js.map +1 -1
- package/dist/tools/git-tags.d.ts +105 -331
- package/dist/tools/git-tags.d.ts.map +1 -1
- package/dist/tools/git-tags.js +545 -416
- package/dist/tools/git-tags.js.map +1 -1
- package/dist/tools/git-workflow.d.ts +127 -0
- package/dist/tools/git-workflow.d.ts.map +1 -0
- package/dist/tools/git-workflow.js +359 -0
- package/dist/tools/git-workflow.js.map +1 -0
- package/dist/utils/auto-detection.d.ts +113 -0
- package/dist/utils/auto-detection.d.ts.map +1 -0
- package/dist/utils/auto-detection.js +235 -0
- package/dist/utils/auto-detection.js.map +1 -0
- package/dist/utils/error-handler.d.ts +107 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +331 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/git-operations.d.ts.map +1 -1
- package/dist/utils/git-operations.js +6 -51
- package/dist/utils/git-operations.js.map +1 -1
- package/dist/utils/user-detection.d.ts +1 -13
- package/dist/utils/user-detection.d.ts.map +1 -1
- package/dist/utils/user-detection.js +1 -26
- package/dist/utils/user-detection.js.map +1 -1
- package/package.json +62 -60
- package/dist/client.d.ts +0 -307
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -299
- package/dist/client.js.map +0 -1
- package/dist/tools/git-branch-protection.d.ts +0 -97
- package/dist/tools/git-branch-protection.d.ts.map +0 -1
- package/dist/tools/git-branch-protection.js +0 -182
- package/dist/tools/git-branch-protection.js.map +0 -1
- package/dist/tools/git-commits.d.ts.map +0 -1
- package/dist/tools/git-commits.js +0 -5
- package/dist/tools/git-commits.js.map +0 -1
- package/dist/tools/git-initialize.d.ts +0 -208
- package/dist/tools/git-initialize.d.ts.map +0 -1
- package/dist/tools/git-initialize.js +0 -470
- package/dist/tools/git-initialize.js.map +0 -1
- package/dist/tools/git-projects.d.ts +0 -112
- package/dist/tools/git-projects.d.ts.map +0 -1
- package/dist/tools/git-projects.js +0 -319
- package/dist/tools/git-projects.js.map +0 -1
- package/dist/tools/git-releases.d.ts +0 -486
- package/dist/tools/git-releases.d.ts.map +0 -1
- package/dist/tools/git-releases.js +0 -561
- package/dist/tools/git-releases.js.map +0 -1
- package/dist/tools/git-repositories.d.ts +0 -469
- package/dist/tools/git-repositories.d.ts.map +0 -1
- package/dist/tools/git-repositories.js +0 -637
- package/dist/tools/git-repositories.js.map +0 -1
- package/dist/tools/git-revert.d.ts +0 -147
- package/dist/tools/git-revert.d.ts.map +0 -1
- package/dist/tools/git-revert.js +0 -199
- package/dist/tools/git-revert.js.map +0 -1
- package/dist/tools/git-update-project.d.ts +0 -309
- package/dist/tools/git-update-project.d.ts.map +0 -1
- package/dist/tools/git-update-project.js +0 -878
- package/dist/tools/git-update-project.js.map +0 -1
package/dist/tools/git-issues.js
CHANGED
|
@@ -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.
|
|
36
|
+
exports.gitIssuesTool = void 0;
|
|
4
37
|
const zod_1 = require("zod");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
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
|
-
*
|
|
14
|
-
*
|
|
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
|
-
*
|
|
23
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
265
|
+
async executeCreate(detection, input) {
|
|
323
266
|
try {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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 '${
|
|
333
|
-
data:
|
|
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
|
-
|
|
303
|
+
return this.errorHandler.toUniversalResponse();
|
|
338
304
|
}
|
|
339
|
-
}
|
|
305
|
+
}
|
|
340
306
|
/**
|
|
341
|
-
*
|
|
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
|
|
309
|
+
async executeList(detection, input) {
|
|
370
310
|
try {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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:
|
|
348
|
+
message: `Found ${limitedIssues.length} issues`,
|
|
379
349
|
data: {
|
|
380
|
-
issues,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
367
|
+
return this.errorHandler.toUniversalResponse();
|
|
389
368
|
}
|
|
390
|
-
}
|
|
369
|
+
}
|
|
391
370
|
/**
|
|
392
|
-
*
|
|
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
|
|
373
|
+
async executeGet(detection, input) {
|
|
416
374
|
try {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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
|
-
|
|
422
|
-
return {
|
|
395
|
+
return (0, auto_detection_js_1.createUniversalResponse)({
|
|
423
396
|
success: true,
|
|
424
397
|
action: 'get',
|
|
425
|
-
message: `Issue
|
|
426
|
-
data:
|
|
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
|
-
|
|
411
|
+
return this.errorHandler.toUniversalResponse();
|
|
431
412
|
}
|
|
432
|
-
}
|
|
413
|
+
}
|
|
433
414
|
/**
|
|
434
|
-
*
|
|
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
|
|
417
|
+
async executeUpdate(detection, input) {
|
|
466
418
|
try {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
|
492
|
-
data:
|
|
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
|
-
|
|
448
|
+
return this.errorHandler.toUniversalResponse();
|
|
497
449
|
}
|
|
498
|
-
}
|
|
450
|
+
}
|
|
499
451
|
/**
|
|
500
|
-
*
|
|
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
|
|
454
|
+
async executeClose(detection, input) {
|
|
524
455
|
try {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
|
|
530
|
-
|
|
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
|
|
534
|
-
data:
|
|
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
|
-
|
|
493
|
+
return this.errorHandler.toUniversalResponse();
|
|
539
494
|
}
|
|
540
|
-
}
|
|
495
|
+
}
|
|
541
496
|
/**
|
|
542
|
-
*
|
|
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
|
|
499
|
+
async executeScan(detection, input) {
|
|
567
500
|
try {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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
|
-
|
|
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: '
|
|
587
|
-
message: `
|
|
521
|
+
action: 'scan',
|
|
522
|
+
message: `Found ${todos.length} TODOs/FIXMEs in code`,
|
|
588
523
|
data: {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
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
|
-
|
|
681
|
+
executor.errorHandler.addError(error);
|
|
682
|
+
return executor.errorHandler.toUniversalResponse();
|
|
691
683
|
}
|
|
692
684
|
}
|
|
693
685
|
};
|