@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,465 @@
|
|
|
1
|
+
#include "services/checkpoint_service.h"
|
|
2
|
+
#include <chrono>
|
|
3
|
+
#include <filesystem>
|
|
4
|
+
#include <fstream>
|
|
5
|
+
#include <iomanip>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
#include <nlohmann/json.hpp>
|
|
8
|
+
#include <random>
|
|
9
|
+
#include <sstream>
|
|
10
|
+
#include <string_view>
|
|
11
|
+
|
|
12
|
+
namespace Services {
|
|
13
|
+
|
|
14
|
+
std::string CheckpointService::get_checkpoints_directory() {
|
|
15
|
+
return "data/checkpoints";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
std::string CheckpointService::generate_checkpoint_id() {
|
|
19
|
+
std::random_device rd;
|
|
20
|
+
std::mt19937 gen(rd());
|
|
21
|
+
std::uniform_int_distribution<> dis(0, 15);
|
|
22
|
+
|
|
23
|
+
std::string id;
|
|
24
|
+
constexpr std::string_view hex_chars = "0123456789abcdef";
|
|
25
|
+
for (size_t i = 0; i < 8; ++i) {
|
|
26
|
+
id += hex_chars[dis(gen)];
|
|
27
|
+
}
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
std::string CheckpointService::get_timestamp() {
|
|
32
|
+
auto now = std::chrono::system_clock::now();
|
|
33
|
+
auto time_t = std::chrono::system_clock::to_time_t(now);
|
|
34
|
+
std::stringstream ss;
|
|
35
|
+
ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
|
|
36
|
+
return ss.str();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
void CheckpointService::ensure_checkpoints_directory() {
|
|
40
|
+
std::filesystem::create_directories(get_checkpoints_directory());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
std::vector<std::string>
|
|
44
|
+
CheckpointService::get_project_files(const std::string &directory) {
|
|
45
|
+
std::vector<std::string> files;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
for (const auto &entry :
|
|
49
|
+
std::filesystem::recursive_directory_iterator(directory)) {
|
|
50
|
+
if (entry.is_regular_file()) {
|
|
51
|
+
std::string path = entry.path().string();
|
|
52
|
+
|
|
53
|
+
// Skip certain directories and file types
|
|
54
|
+
if (path.find("/.git/") != std::string::npos ||
|
|
55
|
+
path.find("/build/") != std::string::npos ||
|
|
56
|
+
path.find("/node_modules/") != std::string::npos ||
|
|
57
|
+
path.find("/target/") != std::string::npos ||
|
|
58
|
+
path.find("/.cache/") != std::string::npos ||
|
|
59
|
+
path.find("/data/checkpoints/") != std::string::npos) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Skip binary files and large files
|
|
64
|
+
if (entry.file_size() > 10 * 1024 * 1024) { // 10MB limit
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
files.push_back(path);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch (const std::exception &e) {
|
|
72
|
+
std::cerr << "Error scanning project files: " << e.what() << std::endl;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return files;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
void CheckpointService::backup_file(const std::string &source_path,
|
|
79
|
+
const std::string &backup_path) {
|
|
80
|
+
try {
|
|
81
|
+
std::filesystem::create_directories(
|
|
82
|
+
std::filesystem::path(backup_path).parent_path());
|
|
83
|
+
std::filesystem::copy_file(
|
|
84
|
+
source_path, backup_path,
|
|
85
|
+
std::filesystem::copy_options::overwrite_existing);
|
|
86
|
+
} catch (const std::exception &e) {
|
|
87
|
+
throw std::runtime_error("Failed to backup file " + source_path + ": " +
|
|
88
|
+
e.what());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void CheckpointService::restore_file(const std::string &backup_path,
|
|
93
|
+
const std::string &target_path) {
|
|
94
|
+
try {
|
|
95
|
+
std::filesystem::create_directories(
|
|
96
|
+
std::filesystem::path(target_path).parent_path());
|
|
97
|
+
std::filesystem::copy_file(
|
|
98
|
+
backup_path, target_path,
|
|
99
|
+
std::filesystem::copy_options::overwrite_existing);
|
|
100
|
+
} catch (const std::exception &e) {
|
|
101
|
+
throw std::runtime_error("Failed to restore file " + target_path + ": " +
|
|
102
|
+
e.what());
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
std::string CheckpointService::create_checkpoint(const std::string &name,
|
|
107
|
+
const std::string &description,
|
|
108
|
+
const std::string &directory) {
|
|
109
|
+
try {
|
|
110
|
+
ensure_checkpoints_directory();
|
|
111
|
+
|
|
112
|
+
std::string checkpoint_id = generate_checkpoint_id();
|
|
113
|
+
std::string checkpoint_dir =
|
|
114
|
+
get_checkpoints_directory() + "/" + checkpoint_id;
|
|
115
|
+
std::filesystem::create_directories(checkpoint_dir);
|
|
116
|
+
|
|
117
|
+
// Get list of files to backup
|
|
118
|
+
std::vector<std::string> project_files = get_project_files(directory);
|
|
119
|
+
|
|
120
|
+
// Create checkpoint metadata
|
|
121
|
+
nlohmann::json metadata;
|
|
122
|
+
metadata["id"] = checkpoint_id;
|
|
123
|
+
metadata["name"] = name;
|
|
124
|
+
metadata["description"] = description;
|
|
125
|
+
metadata["timestamp"] = get_timestamp();
|
|
126
|
+
metadata["source_directory"] =
|
|
127
|
+
std::filesystem::absolute(directory).string();
|
|
128
|
+
metadata["files"] = nlohmann::json::array();
|
|
129
|
+
|
|
130
|
+
size_t total_size = 0;
|
|
131
|
+
|
|
132
|
+
// Backup files
|
|
133
|
+
for (const auto &file_path : project_files) {
|
|
134
|
+
try {
|
|
135
|
+
std::string relative_path =
|
|
136
|
+
std::filesystem::relative(file_path, directory).string();
|
|
137
|
+
std::string backup_path = checkpoint_dir + "/files/" + relative_path;
|
|
138
|
+
|
|
139
|
+
backup_file(file_path, backup_path);
|
|
140
|
+
|
|
141
|
+
size_t file_size = std::filesystem::file_size(file_path);
|
|
142
|
+
total_size += file_size;
|
|
143
|
+
|
|
144
|
+
nlohmann::json file_info;
|
|
145
|
+
file_info["original_path"] = file_path;
|
|
146
|
+
file_info["relative_path"] = relative_path;
|
|
147
|
+
file_info["backup_path"] = backup_path;
|
|
148
|
+
file_info["size"] = file_size;
|
|
149
|
+
|
|
150
|
+
metadata["files"].push_back(file_info);
|
|
151
|
+
|
|
152
|
+
} catch (const std::exception &e) {
|
|
153
|
+
std::cerr << "Warning: Failed to backup file " << file_path << ": "
|
|
154
|
+
<< e.what() << std::endl;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
metadata["total_size"] = total_size;
|
|
159
|
+
metadata["file_count"] = metadata["files"].size();
|
|
160
|
+
|
|
161
|
+
// Also backup memory state if it exists
|
|
162
|
+
std::string memory_file = "data/memory.txt";
|
|
163
|
+
if (std::filesystem::exists(memory_file)) {
|
|
164
|
+
try {
|
|
165
|
+
std::string memory_backup = checkpoint_dir + "/memory.txt";
|
|
166
|
+
backup_file(memory_file, memory_backup);
|
|
167
|
+
metadata["has_memory_backup"] = true;
|
|
168
|
+
} catch (const std::exception &e) {
|
|
169
|
+
std::cerr << "Warning: Failed to backup memory: " << e.what()
|
|
170
|
+
<< std::endl;
|
|
171
|
+
metadata["has_memory_backup"] = false;
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
metadata["has_memory_backup"] = false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Save metadata
|
|
178
|
+
std::string metadata_file = checkpoint_dir + "/metadata.json";
|
|
179
|
+
std::ofstream meta_stream(metadata_file);
|
|
180
|
+
meta_stream << metadata.dump(2);
|
|
181
|
+
meta_stream.close();
|
|
182
|
+
|
|
183
|
+
return checkpoint_id;
|
|
184
|
+
|
|
185
|
+
} catch (const std::exception &e) {
|
|
186
|
+
throw std::runtime_error("Failed to create checkpoint: " +
|
|
187
|
+
std::string(e.what()));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
std::vector<CheckpointInfo> CheckpointService::list_checkpoints() {
|
|
192
|
+
std::vector<CheckpointInfo> checkpoints;
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
std::string checkpoints_dir = get_checkpoints_directory();
|
|
196
|
+
if (!std::filesystem::exists(checkpoints_dir)) {
|
|
197
|
+
return checkpoints;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (const auto &entry :
|
|
201
|
+
std::filesystem::directory_iterator(checkpoints_dir)) {
|
|
202
|
+
if (entry.is_directory()) {
|
|
203
|
+
std::string metadata_file = entry.path().string() + "/metadata.json";
|
|
204
|
+
if (std::filesystem::exists(metadata_file)) {
|
|
205
|
+
try {
|
|
206
|
+
std::ifstream file(metadata_file);
|
|
207
|
+
nlohmann::json metadata;
|
|
208
|
+
file >> metadata;
|
|
209
|
+
|
|
210
|
+
CheckpointInfo info;
|
|
211
|
+
info.id = metadata["id"];
|
|
212
|
+
info.name = metadata["name"];
|
|
213
|
+
info.timestamp = metadata["timestamp"];
|
|
214
|
+
info.description = metadata.value("description", "");
|
|
215
|
+
info.total_size = metadata.value("total_size", 0);
|
|
216
|
+
|
|
217
|
+
for (const auto &file_info : metadata["files"]) {
|
|
218
|
+
info.backed_up_files.push_back(file_info["relative_path"]);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
checkpoints.push_back(info);
|
|
222
|
+
|
|
223
|
+
} catch (const std::exception &e) {
|
|
224
|
+
std::cerr << "Warning: Failed to read checkpoint metadata: "
|
|
225
|
+
<< e.what() << std::endl;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Sort by timestamp (newest first)
|
|
232
|
+
std::sort(checkpoints.begin(), checkpoints.end(),
|
|
233
|
+
[](const CheckpointInfo &a, const CheckpointInfo &b) {
|
|
234
|
+
return a.timestamp > b.timestamp;
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
} catch (const std::exception &e) {
|
|
238
|
+
std::cerr << "Error listing checkpoints: " << e.what() << std::endl;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return checkpoints;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
CheckpointInfo
|
|
245
|
+
CheckpointService::get_checkpoint_info(const std::string &checkpoint_id) {
|
|
246
|
+
CheckpointInfo info;
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
std::string metadata_file =
|
|
250
|
+
get_checkpoints_directory() + "/" + checkpoint_id + "/metadata.json";
|
|
251
|
+
if (!std::filesystem::exists(metadata_file)) {
|
|
252
|
+
throw std::runtime_error("Checkpoint not found: " + checkpoint_id);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
std::ifstream file(metadata_file);
|
|
256
|
+
nlohmann::json metadata;
|
|
257
|
+
file >> metadata;
|
|
258
|
+
|
|
259
|
+
info.id = metadata["id"];
|
|
260
|
+
info.name = metadata["name"];
|
|
261
|
+
info.timestamp = metadata["timestamp"];
|
|
262
|
+
info.description = metadata.value("description", "");
|
|
263
|
+
info.total_size = metadata.value("total_size", 0);
|
|
264
|
+
|
|
265
|
+
for (const auto &file_info : metadata["files"]) {
|
|
266
|
+
info.backed_up_files.push_back(file_info["relative_path"]);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
} catch (const std::exception &e) {
|
|
270
|
+
throw std::runtime_error("Failed to get checkpoint info: " +
|
|
271
|
+
std::string(e.what()));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return info;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
bool CheckpointService::restore_checkpoint(const std::string &checkpoint_id,
|
|
278
|
+
const RestoreOptions &options) {
|
|
279
|
+
try {
|
|
280
|
+
std::string checkpoint_dir =
|
|
281
|
+
get_checkpoints_directory() + "/" + checkpoint_id;
|
|
282
|
+
std::string metadata_file = checkpoint_dir + "/metadata.json";
|
|
283
|
+
|
|
284
|
+
if (!std::filesystem::exists(metadata_file)) {
|
|
285
|
+
throw std::runtime_error("Checkpoint not found: " + checkpoint_id);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
std::ifstream file(metadata_file);
|
|
289
|
+
nlohmann::json metadata;
|
|
290
|
+
file >> metadata;
|
|
291
|
+
|
|
292
|
+
// Create backup before restore if requested
|
|
293
|
+
if (options.create_backup_before_restore) {
|
|
294
|
+
std::string backup_name = "pre-restore-" + checkpoint_id;
|
|
295
|
+
std::string backup_description =
|
|
296
|
+
"Automatic backup before restoring checkpoint " + checkpoint_id;
|
|
297
|
+
create_checkpoint(backup_name, backup_description);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Restore files
|
|
301
|
+
if (options.restore_files) {
|
|
302
|
+
for (const auto &file_info : metadata["files"]) {
|
|
303
|
+
std::string relative_path = file_info["relative_path"];
|
|
304
|
+
std::string backup_path = file_info["backup_path"];
|
|
305
|
+
std::string original_path = file_info["original_path"];
|
|
306
|
+
|
|
307
|
+
// Check if we should restore this specific file
|
|
308
|
+
if (!options.specific_files.empty()) {
|
|
309
|
+
bool should_restore = false;
|
|
310
|
+
for (const auto &specific_file : options.specific_files) {
|
|
311
|
+
if (relative_path == specific_file ||
|
|
312
|
+
original_path == specific_file) {
|
|
313
|
+
should_restore = true;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (!should_restore)
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
restore_file(backup_path, original_path);
|
|
323
|
+
} catch (const std::exception &e) {
|
|
324
|
+
std::cerr << "Warning: Failed to restore file " << relative_path
|
|
325
|
+
<< ": " << e.what() << std::endl;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Restore memory if requested and available
|
|
331
|
+
if (options.restore_memory && metadata.value("has_memory_backup", false)) {
|
|
332
|
+
try {
|
|
333
|
+
std::string memory_backup = checkpoint_dir + "/memory.txt";
|
|
334
|
+
std::string memory_file = "data/memory.txt";
|
|
335
|
+
restore_file(memory_backup, memory_file);
|
|
336
|
+
} catch (const std::exception &e) {
|
|
337
|
+
std::cerr << "Warning: Failed to restore memory: " << e.what()
|
|
338
|
+
<< std::endl;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return true;
|
|
343
|
+
|
|
344
|
+
} catch (const std::exception &e) {
|
|
345
|
+
std::cerr << "Error restoring checkpoint: " << e.what() << std::endl;
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
bool CheckpointService::delete_checkpoint(const std::string &checkpoint_id) {
|
|
351
|
+
try {
|
|
352
|
+
std::string checkpoint_dir =
|
|
353
|
+
get_checkpoints_directory() + "/" + checkpoint_id;
|
|
354
|
+
if (std::filesystem::exists(checkpoint_dir)) {
|
|
355
|
+
std::filesystem::remove_all(checkpoint_dir);
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
return false;
|
|
359
|
+
} catch (const std::exception &e) {
|
|
360
|
+
std::cerr << "Error deleting checkpoint: " << e.what() << std::endl;
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
size_t
|
|
366
|
+
CheckpointService::get_checkpoint_size(const std::string &checkpoint_id) {
|
|
367
|
+
try {
|
|
368
|
+
std::string checkpoint_dir =
|
|
369
|
+
get_checkpoints_directory() + "/" + checkpoint_id;
|
|
370
|
+
size_t total_size = 0;
|
|
371
|
+
|
|
372
|
+
for (const auto &entry :
|
|
373
|
+
std::filesystem::recursive_directory_iterator(checkpoint_dir)) {
|
|
374
|
+
if (entry.is_regular_file()) {
|
|
375
|
+
total_size += entry.file_size();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return total_size;
|
|
380
|
+
} catch ([[maybe_unused]] const std::exception &e) {
|
|
381
|
+
return 0;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
void CheckpointService::cleanup_old_checkpoints(size_t keep_count) {
|
|
386
|
+
try {
|
|
387
|
+
auto checkpoints = list_checkpoints();
|
|
388
|
+
if (checkpoints.size() <= keep_count) {
|
|
389
|
+
return; // Nothing to cleanup
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Delete oldest checkpoints
|
|
393
|
+
for (size_t i = keep_count; i < checkpoints.size(); ++i) {
|
|
394
|
+
delete_checkpoint(checkpoints[i].id);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
} catch (const std::exception &e) {
|
|
398
|
+
std::cerr << "Error cleaning up checkpoints: " << e.what() << std::endl;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
bool CheckpointService::export_checkpoint(const std::string &checkpoint_id,
|
|
403
|
+
const std::string &export_path) {
|
|
404
|
+
// For now, just copy the checkpoint directory
|
|
405
|
+
try {
|
|
406
|
+
std::string checkpoint_dir =
|
|
407
|
+
get_checkpoints_directory() + "/" + checkpoint_id;
|
|
408
|
+
if (!std::filesystem::exists(checkpoint_dir)) {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
std::filesystem::copy(
|
|
413
|
+
checkpoint_dir, export_path,
|
|
414
|
+
std::filesystem::copy_options::recursive |
|
|
415
|
+
std::filesystem::copy_options::overwrite_existing);
|
|
416
|
+
return true;
|
|
417
|
+
|
|
418
|
+
} catch (const std::exception &e) {
|
|
419
|
+
std::cerr << "Error exporting checkpoint: " << e.what() << std::endl;
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
std::string
|
|
425
|
+
CheckpointService::import_checkpoint(const std::string &archive_path) {
|
|
426
|
+
try {
|
|
427
|
+
if (!std::filesystem::exists(archive_path)) {
|
|
428
|
+
throw std::runtime_error("Archive path does not exist");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
ensure_checkpoints_directory();
|
|
432
|
+
|
|
433
|
+
// Generate new checkpoint ID
|
|
434
|
+
std::string new_checkpoint_id = generate_checkpoint_id();
|
|
435
|
+
std::string checkpoint_dir =
|
|
436
|
+
get_checkpoints_directory() + "/" + new_checkpoint_id;
|
|
437
|
+
|
|
438
|
+
// Copy archive to checkpoint directory
|
|
439
|
+
std::filesystem::copy(archive_path, checkpoint_dir,
|
|
440
|
+
std::filesystem::copy_options::recursive);
|
|
441
|
+
|
|
442
|
+
// Update metadata with new ID
|
|
443
|
+
std::string metadata_file = checkpoint_dir + "/metadata.json";
|
|
444
|
+
if (std::filesystem::exists(metadata_file)) {
|
|
445
|
+
std::ifstream file(metadata_file);
|
|
446
|
+
nlohmann::json metadata;
|
|
447
|
+
file >> metadata;
|
|
448
|
+
file.close();
|
|
449
|
+
|
|
450
|
+
metadata["id"] = new_checkpoint_id;
|
|
451
|
+
metadata["imported_at"] = get_timestamp();
|
|
452
|
+
|
|
453
|
+
std::ofstream out_file(metadata_file);
|
|
454
|
+
out_file << metadata.dump(2);
|
|
455
|
+
out_file.close();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return new_checkpoint_id;
|
|
459
|
+
|
|
460
|
+
} catch (const std::exception &e) {
|
|
461
|
+
std::cerr << "Error importing checkpoint: " << e.what() << std::endl;
|
|
462
|
+
return "";
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} // namespace Services
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#include "services/codebase_service.h"
|
|
2
|
+
#include "services/file_service.h"
|
|
3
|
+
#include "services/git_service.h"
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <filesystem>
|
|
6
|
+
#include <fstream>
|
|
7
|
+
#include <regex>
|
|
8
|
+
#include <sstream>
|
|
9
|
+
|
|
10
|
+
namespace Services {
|
|
11
|
+
|
|
12
|
+
CodebaseService::CodebaseService() {}
|
|
13
|
+
|
|
14
|
+
std::string CodebaseService::analyze_structure(const std::string &path) {
|
|
15
|
+
std::ostringstream analysis;
|
|
16
|
+
analysis << "Codebase Structure Analysis:\n\n";
|
|
17
|
+
|
|
18
|
+
// Check if it's a git repository
|
|
19
|
+
if (GitService::is_git_repository(path)) {
|
|
20
|
+
analysis << "Git Repository: Yes\n";
|
|
21
|
+
analysis << GitService::analyze_repository(path) << "\n";
|
|
22
|
+
} else {
|
|
23
|
+
analysis << "Git Repository: No\n\n";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Analyze directory structure
|
|
27
|
+
analysis << "Directory Structure:\n";
|
|
28
|
+
analysis << get_directory_tree(path, 2) << "\n";
|
|
29
|
+
|
|
30
|
+
// Analyze file types
|
|
31
|
+
auto file_stats = analyze_file_types(path);
|
|
32
|
+
analysis << "File Type Distribution:\n";
|
|
33
|
+
for (const auto &[ext, count] : file_stats) {
|
|
34
|
+
analysis << " " << ext << ": " << count << " files\n";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Look for common project files
|
|
38
|
+
analysis << "\nProject Configuration Files:\n";
|
|
39
|
+
std::vector<std::string> config_files = {
|
|
40
|
+
"package.json", "Cargo.toml", "pom.xml", "build.gradle",
|
|
41
|
+
"CMakeLists.txt", "Makefile", "requirements.txt", "setup.py",
|
|
42
|
+
"Dockerfile", ".gitignore", "README.md"};
|
|
43
|
+
|
|
44
|
+
for (const auto &file : config_files) {
|
|
45
|
+
if (std::filesystem::exists(std::filesystem::path(path) / file)) {
|
|
46
|
+
analysis << " " << file << "\n";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return analysis.str();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
std::string CodebaseService::find_main_components(const std::string &path) {
|
|
54
|
+
std::ostringstream result;
|
|
55
|
+
result << "Main Components Analysis:\n\n";
|
|
56
|
+
|
|
57
|
+
// Look for main directories
|
|
58
|
+
std::vector<std::string> main_dirs;
|
|
59
|
+
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
|
60
|
+
if (entry.is_directory()) {
|
|
61
|
+
std::string dir_name = entry.path().filename().string();
|
|
62
|
+
if (dir_name[0] != '.' && dir_name != "node_modules" &&
|
|
63
|
+
dir_name != "build" && dir_name != "dist") {
|
|
64
|
+
main_dirs.push_back(dir_name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
result << "Main Directories:\n";
|
|
70
|
+
for (const auto &dir : main_dirs) {
|
|
71
|
+
result << " - " << dir << "/\n";
|
|
72
|
+
|
|
73
|
+
// Analyze what's in each directory
|
|
74
|
+
std::string dir_path = path + "/" + dir;
|
|
75
|
+
auto file_count = count_files_in_directory(dir_path);
|
|
76
|
+
result << " Files: " << file_count << "\n";
|
|
77
|
+
|
|
78
|
+
// Look for key files
|
|
79
|
+
auto key_files = find_key_files(dir_path);
|
|
80
|
+
if (!key_files.empty()) {
|
|
81
|
+
result << " Key files: ";
|
|
82
|
+
for (size_t i = 0; i < key_files.size() && i < 3; ++i) {
|
|
83
|
+
if (i > 0)
|
|
84
|
+
result << ", ";
|
|
85
|
+
result << key_files[i];
|
|
86
|
+
}
|
|
87
|
+
if (key_files.size() > 3) {
|
|
88
|
+
result << " (+" << (key_files.size() - 3) << " more)";
|
|
89
|
+
}
|
|
90
|
+
result << "\n";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result.str();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
std::vector<std::string> CodebaseService::find_todos(const std::string &path) {
|
|
98
|
+
std::vector<std::string> todos;
|
|
99
|
+
|
|
100
|
+
// Search for TODO, FIXME, HACK comments
|
|
101
|
+
auto search_results =
|
|
102
|
+
FileService::search_in_directory(path, "TODO|FIXME|HACK", "*");
|
|
103
|
+
|
|
104
|
+
for (const auto &match : search_results) {
|
|
105
|
+
std::string todo_line = match.file_path + ":" +
|
|
106
|
+
std::to_string(match.line_number) + ": " +
|
|
107
|
+
match.line_content;
|
|
108
|
+
todos.push_back(todo_line);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return todos;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
std::string CodebaseService::get_directory_tree(const std::string &path,
|
|
115
|
+
int max_depth) {
|
|
116
|
+
std::ostringstream tree;
|
|
117
|
+
build_tree_recursive(path, tree, "", 0, max_depth);
|
|
118
|
+
return tree.str();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
void CodebaseService::build_tree_recursive(const std::string &path,
|
|
122
|
+
std::ostringstream &tree,
|
|
123
|
+
const std::string &prefix, int depth,
|
|
124
|
+
int max_depth) {
|
|
125
|
+
if (depth >= max_depth)
|
|
126
|
+
return;
|
|
127
|
+
|
|
128
|
+
std::vector<std::filesystem::directory_entry> entries;
|
|
129
|
+
try {
|
|
130
|
+
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
|
131
|
+
std::string name = entry.path().filename().string();
|
|
132
|
+
if (name[0] != '.' && name != "node_modules" && name != "build" &&
|
|
133
|
+
name != "dist") {
|
|
134
|
+
entries.push_back(entry);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch (const std::exception &) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
std::sort(entries.begin(), entries.end(), [](const auto &a, const auto &b) {
|
|
142
|
+
return a.path().filename().string() < b.path().filename().string();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
for (size_t i = 0; i < entries.size(); ++i) {
|
|
146
|
+
const auto &entry = entries[i];
|
|
147
|
+
bool is_last = (i == entries.size() - 1);
|
|
148
|
+
|
|
149
|
+
tree << prefix << (is_last ? "└── " : "├── ")
|
|
150
|
+
<< entry.path().filename().string();
|
|
151
|
+
|
|
152
|
+
if (entry.is_directory()) {
|
|
153
|
+
tree << "/\n";
|
|
154
|
+
std::string new_prefix = prefix + (is_last ? " " : "│ ");
|
|
155
|
+
build_tree_recursive(entry.path().string(), tree, new_prefix, depth + 1,
|
|
156
|
+
max_depth);
|
|
157
|
+
} else {
|
|
158
|
+
tree << "\n";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
std::map<std::string, int>
|
|
164
|
+
CodebaseService::analyze_file_types(const std::string &path) {
|
|
165
|
+
std::map<std::string, int> file_stats;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
for (const auto &entry :
|
|
169
|
+
std::filesystem::recursive_directory_iterator(path)) {
|
|
170
|
+
if (entry.is_regular_file()) {
|
|
171
|
+
std::string ext = entry.path().extension().string();
|
|
172
|
+
if (ext.empty()) {
|
|
173
|
+
ext = "[no extension]";
|
|
174
|
+
}
|
|
175
|
+
file_stats[ext]++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} catch (const std::exception &) {
|
|
179
|
+
// Handle permission errors, etc.
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return file_stats;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
int CodebaseService::count_files_in_directory(const std::string &path) {
|
|
186
|
+
int count = 0;
|
|
187
|
+
try {
|
|
188
|
+
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
|
189
|
+
if (entry.is_regular_file()) {
|
|
190
|
+
count++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
} catch (const std::exception &) {
|
|
194
|
+
// Handle errors
|
|
195
|
+
}
|
|
196
|
+
return count;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
std::vector<std::string>
|
|
200
|
+
CodebaseService::find_key_files(const std::string &path) {
|
|
201
|
+
std::vector<std::string> key_files;
|
|
202
|
+
|
|
203
|
+
// Patterns for important files
|
|
204
|
+
std::vector<std::regex> patterns = {
|
|
205
|
+
std::regex(".*main\\.(cpp|c|py|js|ts|java)$",
|
|
206
|
+
std::regex_constants::icase),
|
|
207
|
+
std::regex(".*index\\.(js|ts|html|php)$", std::regex_constants::icase),
|
|
208
|
+
std::regex(".*app\\.(cpp|c|py|js|ts|java)$", std::regex_constants::icase),
|
|
209
|
+
std::regex(".*server\\.(cpp|c|py|js|ts|java)$",
|
|
210
|
+
std::regex_constants::icase),
|
|
211
|
+
std::regex(".*client\\.(cpp|c|py|js|ts|java)$",
|
|
212
|
+
std::regex_constants::icase)};
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
|
216
|
+
if (entry.is_regular_file()) {
|
|
217
|
+
std::string filename = entry.path().filename().string();
|
|
218
|
+
for (const auto &pattern : patterns) {
|
|
219
|
+
if (std::regex_match(filename, pattern)) {
|
|
220
|
+
key_files.push_back(filename);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
} catch (const std::exception &) {
|
|
227
|
+
// Handle errors
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return key_files;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
} // namespace Services
|