@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.
Files changed (100) hide show
  1. package/.clang-tidy +28 -0
  2. package/.dockerignore +56 -0
  3. package/.env.example +29 -0
  4. package/.github/CODEOWNERS +2 -0
  5. package/.github/ISSUE_TEMPLATE/blank.md +27 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  8. package/.github/SECURITY.md +24 -0
  9. package/.github/codeql/codeql-config.yml +8 -0
  10. package/.github/dependabot.yml +14 -0
  11. package/.github/labeler.yml +50 -0
  12. package/.github/packaging/brand-cursor.png +0 -0
  13. package/.github/packaging/database/init.sql +48 -0
  14. package/.github/packaging/docker/Dockerfile +111 -0
  15. package/.github/packaging/docker/docker-compose.yml +56 -0
  16. package/.github/packaging/scripts/preflight.sh +413 -0
  17. package/.github/packaging/scripts/prepare-release.sh +141 -0
  18. package/.github/packaging/scripts/release.sh +22 -0
  19. package/.github/packaging/scripts/setup-git-hooks.sh +73 -0
  20. package/.github/pull_request_template.md +31 -0
  21. package/.github/signed.json +9 -0
  22. package/.github/workflows/README.md +23 -0
  23. package/.github/workflows/ci.yml +181 -0
  24. package/.github/workflows/cla.yml +33 -0
  25. package/.github/workflows/formula-sha.yml +63 -0
  26. package/.github/workflows/issue-response.yml +44 -0
  27. package/.github/workflows/labeler.yml +42 -0
  28. package/.github/workflows/pr-body.yml +49 -0
  29. package/.github/workflows/release.yml +176 -0
  30. package/.github/workflows/security.yml +94 -0
  31. package/.github/workflows/stale.yml +38 -0
  32. package/AGENTS.md +49 -0
  33. package/CHANGELOG.md +3 -0
  34. package/CMakeLists.txt +646 -0
  35. package/Formula/cursor.rb +46 -0
  36. package/LICENSE +201 -0
  37. package/Makefile +28 -0
  38. package/README.md +46 -0
  39. package/cli.js +16 -0
  40. package/include/agent.h +86 -0
  41. package/include/agent_mode.h +17 -0
  42. package/include/memory_manager.h +102 -0
  43. package/include/services/ai_service.h +31 -0
  44. package/include/services/auth_service.h +87 -0
  45. package/include/services/checkpoint_service.h +69 -0
  46. package/include/services/codebase_service.h +38 -0
  47. package/include/services/command_service.h +23 -0
  48. package/include/services/context_service.h +74 -0
  49. package/include/services/database_service.h +56 -0
  50. package/include/services/error_service.h +106 -0
  51. package/include/services/file_service.h +51 -0
  52. package/include/services/git_service.h +29 -0
  53. package/include/services/github_service.h +85 -0
  54. package/include/services/mcp_service.h +85 -0
  55. package/include/services/multi_file_service.h +93 -0
  56. package/include/services/sandbox_service.h +96 -0
  57. package/include/services/theme_service.h +67 -0
  58. package/include/services/web_service.h +52 -0
  59. package/include/utils/config.h +68 -0
  60. package/include/utils/memory_utils.h +79 -0
  61. package/include/utils/platform.h +56 -0
  62. package/include/utils/ui.h +43 -0
  63. package/include/utils/validation.h +63 -0
  64. package/include/utils/version.h.in +17 -0
  65. package/install.js +49 -0
  66. package/package.json +16 -0
  67. package/release/checksums.txt +3 -0
  68. package/release/cursor-linux/cursor_v0.1.7_linux_amd64.tar.gz +0 -0
  69. package/release/cursor-macos/cursor_v0.1.7_darwin_arm64.tar.gz +0 -0
  70. package/release/cursor-windows/cursor__windows_amd64.zip +0 -0
  71. package/src/agent.cpp +2026 -0
  72. package/src/main.cpp +97 -0
  73. package/src/memory_manager.cpp +814 -0
  74. package/src/services/ai_service.cpp +366 -0
  75. package/src/services/auth_service.cpp +779 -0
  76. package/src/services/checkpoint_service.cpp +465 -0
  77. package/src/services/codebase_service.cpp +233 -0
  78. package/src/services/command_service.cpp +82 -0
  79. package/src/services/context_service.cpp +348 -0
  80. package/src/services/database_service.cpp +148 -0
  81. package/src/services/error_service.cpp +438 -0
  82. package/src/services/file_service.cpp +349 -0
  83. package/src/services/git_service.cpp +148 -0
  84. package/src/services/github_service.cpp +435 -0
  85. package/src/services/mcp_service.cpp +481 -0
  86. package/src/services/multi_file_service.cpp +591 -0
  87. package/src/services/sandbox_service.cpp +678 -0
  88. package/src/services/theme_service.cpp +429 -0
  89. package/src/services/web_service.cpp +532 -0
  90. package/src/utils/config.cpp +77 -0
  91. package/src/utils/memory_utils.cpp +93 -0
  92. package/src/utils/ui.cpp +307 -0
  93. package/src/utils/validation.cpp +306 -0
  94. package/src/utils/version.cpp +175 -0
  95. package/tests/e2e/docker-compose.yml +195 -0
  96. package/tests/e2e/run_e2e_tests.sh +70 -0
  97. package/tests/e2e/run_tests_in_docker.sh +115 -0
  98. package/tests/main_test.cpp +16 -0
  99. package/tests/mocks/mock_ollama.py +98 -0
  100. 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