@bniladridas/cursor 0.1.7
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/.clang-tidy +28 -0
- package/.dockerignore +56 -0
- package/.env.example +29 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/ISSUE_TEMPLATE/blank.md +27 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- package/.github/SECURITY.md +24 -0
- package/.github/codeql/codeql-config.yml +8 -0
- package/.github/dependabot.yml +14 -0
- package/.github/labeler.yml +50 -0
- package/.github/packaging/brand-cursor.png +0 -0
- package/.github/packaging/database/init.sql +48 -0
- package/.github/packaging/docker/Dockerfile +111 -0
- package/.github/packaging/docker/docker-compose.yml +56 -0
- package/.github/packaging/scripts/preflight.sh +413 -0
- package/.github/packaging/scripts/prepare-release.sh +141 -0
- package/.github/packaging/scripts/release.sh +22 -0
- package/.github/packaging/scripts/setup-git-hooks.sh +73 -0
- package/.github/pull_request_template.md +31 -0
- package/.github/signed.json +9 -0
- package/.github/workflows/README.md +23 -0
- package/.github/workflows/ci.yml +181 -0
- package/.github/workflows/cla.yml +33 -0
- package/.github/workflows/formula-sha.yml +63 -0
- package/.github/workflows/issue-response.yml +44 -0
- package/.github/workflows/labeler.yml +42 -0
- package/.github/workflows/pr-body.yml +49 -0
- package/.github/workflows/release.yml +176 -0
- package/.github/workflows/security.yml +94 -0
- package/.github/workflows/stale.yml +38 -0
- package/AGENTS.md +49 -0
- package/CHANGELOG.md +3 -0
- package/CMakeLists.txt +646 -0
- package/Formula/cursor.rb +46 -0
- package/LICENSE +201 -0
- package/Makefile +28 -0
- package/README.md +46 -0
- package/cli.js +16 -0
- package/include/agent.h +86 -0
- package/include/agent_mode.h +17 -0
- package/include/memory_manager.h +102 -0
- package/include/services/ai_service.h +31 -0
- package/include/services/auth_service.h +87 -0
- package/include/services/checkpoint_service.h +69 -0
- package/include/services/codebase_service.h +38 -0
- package/include/services/command_service.h +23 -0
- package/include/services/context_service.h +74 -0
- package/include/services/database_service.h +56 -0
- package/include/services/error_service.h +106 -0
- package/include/services/file_service.h +51 -0
- package/include/services/git_service.h +29 -0
- package/include/services/github_service.h +85 -0
- package/include/services/mcp_service.h +85 -0
- package/include/services/multi_file_service.h +93 -0
- package/include/services/sandbox_service.h +96 -0
- package/include/services/theme_service.h +67 -0
- package/include/services/web_service.h +52 -0
- package/include/utils/config.h +68 -0
- package/include/utils/memory_utils.h +79 -0
- package/include/utils/platform.h +56 -0
- package/include/utils/ui.h +43 -0
- package/include/utils/validation.h +63 -0
- package/include/utils/version.h.in +17 -0
- package/install.js +49 -0
- package/package.json +16 -0
- package/release/checksums.txt +3 -0
- package/release/cursor-linux/cursor_v0.1.7_linux_amd64.tar.gz +0 -0
- package/release/cursor-macos/cursor_v0.1.7_darwin_arm64.tar.gz +0 -0
- package/release/cursor-windows/cursor__windows_amd64.zip +0 -0
- package/src/agent.cpp +2026 -0
- package/src/main.cpp +97 -0
- package/src/memory_manager.cpp +814 -0
- package/src/services/ai_service.cpp +366 -0
- package/src/services/auth_service.cpp +779 -0
- package/src/services/checkpoint_service.cpp +465 -0
- package/src/services/codebase_service.cpp +233 -0
- package/src/services/command_service.cpp +82 -0
- package/src/services/context_service.cpp +348 -0
- package/src/services/database_service.cpp +148 -0
- package/src/services/error_service.cpp +438 -0
- package/src/services/file_service.cpp +349 -0
- package/src/services/git_service.cpp +148 -0
- package/src/services/github_service.cpp +435 -0
- package/src/services/mcp_service.cpp +481 -0
- package/src/services/multi_file_service.cpp +591 -0
- package/src/services/sandbox_service.cpp +678 -0
- package/src/services/theme_service.cpp +429 -0
- package/src/services/web_service.cpp +532 -0
- package/src/utils/config.cpp +77 -0
- package/src/utils/memory_utils.cpp +93 -0
- package/src/utils/ui.cpp +307 -0
- package/src/utils/validation.cpp +306 -0
- package/src/utils/version.cpp +175 -0
- package/tests/e2e/docker-compose.yml +195 -0
- package/tests/e2e/run_e2e_tests.sh +70 -0
- package/tests/e2e/run_tests_in_docker.sh +115 -0
- package/tests/main_test.cpp +16 -0
- package/tests/mocks/mock_ollama.py +98 -0
- package/tests/mocks/start_nginx.sh +64 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
#include "services/github_service.h"
|
|
2
|
+
#include "services/web_service.h"
|
|
3
|
+
#include <iostream>
|
|
4
|
+
#include <map>
|
|
5
|
+
#include <nlohmann/json.hpp>
|
|
6
|
+
#include <regex>
|
|
7
|
+
#include <sstream>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
namespace Services {
|
|
12
|
+
|
|
13
|
+
std::string GitHubService::get_github_token() {
|
|
14
|
+
const char *token = std::getenv("GITHUB_TOKEN");
|
|
15
|
+
if (token != nullptr) {
|
|
16
|
+
return std::string(token);
|
|
17
|
+
}
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
std::string GitHubService::get_api_base_url() {
|
|
22
|
+
return "https://api.github.com";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
WebResponse GitHubService::make_github_request(const std::string &endpoint,
|
|
26
|
+
const std::string &method,
|
|
27
|
+
const std::string &body) {
|
|
28
|
+
std::string url = get_api_base_url() + endpoint;
|
|
29
|
+
HeaderMap headers;
|
|
30
|
+
|
|
31
|
+
std::string token = get_github_token();
|
|
32
|
+
if (!token.empty()) {
|
|
33
|
+
headers["Authorization"] = "Bearer " + token;
|
|
34
|
+
}
|
|
35
|
+
headers["Accept"] = "application/vnd.github.v3+json";
|
|
36
|
+
headers["User-Agent"] = "cursor-agent/1.0";
|
|
37
|
+
|
|
38
|
+
if (!body.empty() || method == "POST" || method == "PATCH" ||
|
|
39
|
+
method == "PUT") {
|
|
40
|
+
headers["Content-Type"] = "application/json";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (method == "POST") {
|
|
44
|
+
return WebService::post_json(url, body, headers);
|
|
45
|
+
}
|
|
46
|
+
return WebService::fetch_with_headers(url, headers);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
std::string GitHubService::get_repo_info(const std::string &owner,
|
|
50
|
+
const std::string &repo) {
|
|
51
|
+
std::string endpoint = "/repos/" + owner + "/" + repo;
|
|
52
|
+
WebResponse response = make_github_request(endpoint);
|
|
53
|
+
|
|
54
|
+
if (response.success) {
|
|
55
|
+
try {
|
|
56
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
57
|
+
std::stringstream ss;
|
|
58
|
+
ss << "Repository: " << json["full_name"] << "\n";
|
|
59
|
+
ss << "Description: " << json.value("description", "No description")
|
|
60
|
+
<< "\n";
|
|
61
|
+
ss << "Stars: " << json.value("stargazers_count", 0) << "\n";
|
|
62
|
+
ss << "Forks: " << json.value("forks_count", 0) << "\n";
|
|
63
|
+
ss << "Language: " << json.value("language", "Unknown") << "\n";
|
|
64
|
+
return ss.str();
|
|
65
|
+
} catch (const std::exception &e) {
|
|
66
|
+
return "Error parsing repository info: " + std::string(e.what());
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
return "Failed to fetch repository info: " + response.error_message;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
std::vector<GitHubIssue> GitHubService::get_issues(const std::string &owner,
|
|
74
|
+
const std::string &repo,
|
|
75
|
+
const std::string &state) {
|
|
76
|
+
std::vector<GitHubIssue> issues;
|
|
77
|
+
std::string endpoint =
|
|
78
|
+
"/repos/" + owner + "/" + repo + "/issues?state=" + state;
|
|
79
|
+
|
|
80
|
+
WebResponse response = make_github_request(endpoint, "GET", "");
|
|
81
|
+
|
|
82
|
+
if (!response.success) {
|
|
83
|
+
throw std::runtime_error("Failed to fetch issues: " +
|
|
84
|
+
response.error_message);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
89
|
+
for (const auto &item : json) {
|
|
90
|
+
GitHubIssue issue;
|
|
91
|
+
issue.number = item["number"];
|
|
92
|
+
issue.title = item["title"];
|
|
93
|
+
issue.body = item.value("body", "");
|
|
94
|
+
issue.state = item["state"];
|
|
95
|
+
|
|
96
|
+
for (const auto &label : item["labels"]) {
|
|
97
|
+
issue.labels.push_back(label["name"]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!item["assignee"].is_null()) {
|
|
101
|
+
issue.assignees.push_back(item["assignee"]["login"]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!item["milestone"].is_null()) {
|
|
105
|
+
issue.milestone = item["milestone"]["number"];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
issues.push_back(issue);
|
|
109
|
+
}
|
|
110
|
+
} catch (const std::exception &e) {
|
|
111
|
+
throw std::runtime_error("Error parsing issues: " + std::string(e.what()));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return issues;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
GitHubIssue
|
|
118
|
+
GitHubService::create_issue(const std::string &owner, const std::string &repo,
|
|
119
|
+
const std::string &title, const std::string &body,
|
|
120
|
+
const std::vector<std::string> &labels) {
|
|
121
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/issues";
|
|
122
|
+
nlohmann::json payload = {
|
|
123
|
+
{"title", title}, {"body", body}, {"labels", labels}};
|
|
124
|
+
std::string json_body = payload.dump();
|
|
125
|
+
|
|
126
|
+
WebResponse response = make_github_request(endpoint, "POST", json_body);
|
|
127
|
+
|
|
128
|
+
if (!response.success) {
|
|
129
|
+
throw std::runtime_error("Failed to create issue: " +
|
|
130
|
+
response.error_message);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
135
|
+
GitHubIssue issue;
|
|
136
|
+
issue.number = json["number"];
|
|
137
|
+
issue.title = json["title"];
|
|
138
|
+
issue.body = json.value("body", "");
|
|
139
|
+
issue.state = json["state"];
|
|
140
|
+
for (const auto &label : json["labels"]) {
|
|
141
|
+
issue.labels.push_back(label["name"]);
|
|
142
|
+
}
|
|
143
|
+
return issue;
|
|
144
|
+
} catch (const std::exception &e) {
|
|
145
|
+
throw std::runtime_error("Error parsing created issue: " +
|
|
146
|
+
std::string(e.what()));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
bool GitHubService::update_issue(
|
|
151
|
+
const std::string &owner, const std::string &repo, int issue_number,
|
|
152
|
+
const std::map<std::string, std::string> &updates) {
|
|
153
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/issues/" +
|
|
154
|
+
std::to_string(issue_number);
|
|
155
|
+
nlohmann::json payload;
|
|
156
|
+
for (const auto &update : updates) {
|
|
157
|
+
payload[update.first] = update.second;
|
|
158
|
+
}
|
|
159
|
+
std::string json_body = payload.dump();
|
|
160
|
+
|
|
161
|
+
WebResponse response = make_github_request(endpoint, "PATCH", json_body);
|
|
162
|
+
|
|
163
|
+
return response.success;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
bool GitHubService::add_comment(const std::string &owner,
|
|
167
|
+
const std::string &repo, int issue_number,
|
|
168
|
+
const std::string &comment) {
|
|
169
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/issues/" +
|
|
170
|
+
std::to_string(issue_number) + "/comments";
|
|
171
|
+
nlohmann::json payload = {{"body", comment}};
|
|
172
|
+
std::string json_body = payload.dump();
|
|
173
|
+
|
|
174
|
+
WebResponse response = make_github_request(endpoint, "POST", json_body);
|
|
175
|
+
|
|
176
|
+
return response.success;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
std::vector<GitHubPR>
|
|
180
|
+
GitHubService::get_pull_requests(const std::string &owner,
|
|
181
|
+
const std::string &repo,
|
|
182
|
+
const std::string &state) {
|
|
183
|
+
std::vector<GitHubPR> prs;
|
|
184
|
+
std::string endpoint =
|
|
185
|
+
"/repos/" + owner + "/" + repo + "/pulls?state=" + state;
|
|
186
|
+
|
|
187
|
+
WebResponse response = make_github_request(endpoint, "GET", "");
|
|
188
|
+
|
|
189
|
+
if (!response.success) {
|
|
190
|
+
throw std::runtime_error("Failed to fetch PRs: " + response.error_message);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
195
|
+
for (const auto &item : json) {
|
|
196
|
+
GitHubPR pr;
|
|
197
|
+
pr.number = item["number"];
|
|
198
|
+
pr.title = item["title"];
|
|
199
|
+
pr.body = item.value("body", "");
|
|
200
|
+
pr.state = item["state"];
|
|
201
|
+
pr.head_branch = item["head"]["ref"];
|
|
202
|
+
pr.base_branch = item["base"]["ref"];
|
|
203
|
+
pr.mergeable = item.value("mergeable", false);
|
|
204
|
+
prs.push_back(pr);
|
|
205
|
+
}
|
|
206
|
+
} catch (const std::exception &e) {
|
|
207
|
+
throw std::runtime_error("Error parsing PRs: " + std::string(e.what()));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return prs;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
GitHubPR GitHubService::get_pull_request(const std::string &owner,
|
|
214
|
+
const std::string &repo,
|
|
215
|
+
int pr_number) {
|
|
216
|
+
GitHubPR pr;
|
|
217
|
+
std::string endpoint =
|
|
218
|
+
"/repos/" + owner + "/" + repo + "/pulls/" + std::to_string(pr_number);
|
|
219
|
+
|
|
220
|
+
WebResponse response = make_github_request(endpoint, "GET", "");
|
|
221
|
+
|
|
222
|
+
if (!response.success) {
|
|
223
|
+
throw std::runtime_error("Failed to fetch PR: " + response.error_message);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
228
|
+
pr.number = json["number"];
|
|
229
|
+
pr.title = json["title"];
|
|
230
|
+
pr.body = json.value("body", "");
|
|
231
|
+
pr.state = json["state"];
|
|
232
|
+
pr.head_branch = json["head"]["ref"];
|
|
233
|
+
pr.base_branch = json["base"]["ref"];
|
|
234
|
+
pr.mergeable = json.value("mergeable", false);
|
|
235
|
+
} catch (const std::exception &e) {
|
|
236
|
+
throw std::runtime_error("Error parsing PR: " + std::string(e.what()));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return pr;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
bool GitHubService::create_pr_comment(const std::string &owner,
|
|
243
|
+
const std::string &repo, int pr_number,
|
|
244
|
+
const std::string &comment) {
|
|
245
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/issues/" +
|
|
246
|
+
std::to_string(pr_number) + "/comments";
|
|
247
|
+
nlohmann::json payload = {{"body", comment}};
|
|
248
|
+
std::string json_body = payload.dump();
|
|
249
|
+
|
|
250
|
+
WebResponse response = make_github_request(endpoint, "POST", json_body);
|
|
251
|
+
|
|
252
|
+
return response.success;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
std::vector<std::string>
|
|
256
|
+
GitHubService::get_milestones(const std::string &owner,
|
|
257
|
+
const std::string &repo) {
|
|
258
|
+
std::vector<std::string> milestones;
|
|
259
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/milestones";
|
|
260
|
+
|
|
261
|
+
WebResponse response = make_github_request(endpoint, "GET", "");
|
|
262
|
+
|
|
263
|
+
if (!response.success) {
|
|
264
|
+
throw std::runtime_error("Failed to fetch milestones: " +
|
|
265
|
+
response.error_message);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
270
|
+
for (const auto &item : json) {
|
|
271
|
+
milestones.push_back(item["title"]);
|
|
272
|
+
}
|
|
273
|
+
} catch (const std::exception &e) {
|
|
274
|
+
throw std::runtime_error("Error parsing milestones: " +
|
|
275
|
+
std::string(e.what()));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return milestones;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
int GitHubService::create_milestone(const std::string &owner,
|
|
282
|
+
const std::string &repo,
|
|
283
|
+
const std::string &title,
|
|
284
|
+
const std::string &description) {
|
|
285
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/milestones";
|
|
286
|
+
nlohmann::json payload = {{"title", title}, {"description", description}};
|
|
287
|
+
std::string json_body = payload.dump();
|
|
288
|
+
|
|
289
|
+
WebResponse response = make_github_request(endpoint, "POST", json_body);
|
|
290
|
+
|
|
291
|
+
if (!response.success) {
|
|
292
|
+
return -1;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
297
|
+
return json["number"];
|
|
298
|
+
} catch (const std::exception &) {
|
|
299
|
+
return -1;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
std::vector<std::string> GitHubService::get_labels(const std::string &owner,
|
|
304
|
+
const std::string &repo) {
|
|
305
|
+
std::vector<std::string> labels;
|
|
306
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/labels";
|
|
307
|
+
|
|
308
|
+
WebResponse response = make_github_request(endpoint, "GET", "");
|
|
309
|
+
|
|
310
|
+
if (!response.success) {
|
|
311
|
+
throw std::runtime_error("Failed to fetch labels: " +
|
|
312
|
+
response.error_message);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
nlohmann::json json = nlohmann::json::parse(response.content);
|
|
317
|
+
for (const auto &item : json) {
|
|
318
|
+
labels.push_back(item["name"]);
|
|
319
|
+
}
|
|
320
|
+
} catch (const std::exception &e) {
|
|
321
|
+
throw std::runtime_error("Error parsing labels: " + std::string(e.what()));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return labels;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
bool GitHubService::create_label(const std::string &owner,
|
|
328
|
+
const std::string &repo,
|
|
329
|
+
const std::string &name,
|
|
330
|
+
const std::string &color,
|
|
331
|
+
const std::string &description) {
|
|
332
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/labels";
|
|
333
|
+
nlohmann::json payload = {
|
|
334
|
+
{"name", name}, {"color", color}, {"description", description}};
|
|
335
|
+
std::string json_body = payload.dump();
|
|
336
|
+
|
|
337
|
+
WebResponse response = make_github_request(endpoint, "POST", json_body);
|
|
338
|
+
|
|
339
|
+
return response.success;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
bool GitHubService::create_webhook(const std::string &owner,
|
|
343
|
+
const std::string &repo,
|
|
344
|
+
const std::string &url,
|
|
345
|
+
const std::vector<std::string> &events) {
|
|
346
|
+
std::string endpoint = "/repos/" + owner + "/" + repo + "/hooks";
|
|
347
|
+
nlohmann::json payload = {
|
|
348
|
+
{"name", "web"},
|
|
349
|
+
{"active", true},
|
|
350
|
+
{"events", events},
|
|
351
|
+
{"config", {{"url", url}, {"content_type", "json"}}}};
|
|
352
|
+
std::string json_body = payload.dump();
|
|
353
|
+
|
|
354
|
+
WebResponse response = make_github_request(endpoint, "POST", json_body);
|
|
355
|
+
|
|
356
|
+
return response.success;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
std::string GitHubService::run_health_check(const std::string &owner,
|
|
360
|
+
const std::string &repo) {
|
|
361
|
+
std::stringstream ss;
|
|
362
|
+
ss << "# Health Check Report for " << owner << "/" << repo << "\n\n";
|
|
363
|
+
|
|
364
|
+
ss << "## Repository Information\n";
|
|
365
|
+
ss << get_repo_info(owner, repo) << "\n";
|
|
366
|
+
|
|
367
|
+
auto issues = get_issues(owner, repo, "open");
|
|
368
|
+
ss << "## Issues\n";
|
|
369
|
+
ss << "Open issues: " << issues.size() << "\n\n";
|
|
370
|
+
|
|
371
|
+
auto prs = get_pull_requests(owner, repo, "open");
|
|
372
|
+
ss << "## Pull Requests\n";
|
|
373
|
+
ss << "Open PRs: " << prs.size() << "\n\n";
|
|
374
|
+
|
|
375
|
+
auto milestones = get_milestones(owner, repo);
|
|
376
|
+
ss << "## Milestones\n";
|
|
377
|
+
ss << "Active milestones: " << milestones.size() << "\n";
|
|
378
|
+
for (const auto &milestone : milestones) {
|
|
379
|
+
ss << "- " << milestone << "\n";
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return ss.str();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
std::string GitHubService::find_related_issues(const std::string &owner,
|
|
386
|
+
const std::string &repo,
|
|
387
|
+
const std::string &text) {
|
|
388
|
+
auto issues = get_issues(owner, repo, "all");
|
|
389
|
+
std::stringstream ss;
|
|
390
|
+
ss << "Related issues found:\n";
|
|
391
|
+
|
|
392
|
+
std::regex word_regex("\\b\\w+\\b");
|
|
393
|
+
std::vector<std::string> keywords;
|
|
394
|
+
auto words_begin = std::sregex_iterator(text.begin(), text.end(), word_regex);
|
|
395
|
+
auto words_end = std::sregex_iterator();
|
|
396
|
+
|
|
397
|
+
for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
|
|
398
|
+
std::string word = (*i).str();
|
|
399
|
+
if (word.length() > 3) {
|
|
400
|
+
keywords.push_back(word);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
int found_count = 0;
|
|
405
|
+
for (const auto &issue : issues) {
|
|
406
|
+
bool related = false;
|
|
407
|
+
for (const auto &keyword : keywords) {
|
|
408
|
+
if (issue.title.find(keyword) != std::string::npos ||
|
|
409
|
+
issue.body.find(keyword) != std::string::npos) {
|
|
410
|
+
related = true;
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (related) {
|
|
416
|
+
ss << "- #" << issue.number << ": " << issue.title << "\n";
|
|
417
|
+
found_count++;
|
|
418
|
+
if (found_count >= 5)
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (found_count == 0) {
|
|
424
|
+
ss << "No related issues found.";
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return ss.str();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
bool GitHubService::is_available() {
|
|
431
|
+
std::string token = get_github_token();
|
|
432
|
+
return !token.empty() && WebService::is_available();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
} // namespace Services
|