@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,82 @@
1
+ #include "services/command_service.h"
2
+
3
+ #include "utils/platform.h"
4
+
5
+ #include <array>
6
+ #include <chrono>
7
+ #include <cstdio>
8
+ #include <cstring>
9
+ #include <future>
10
+ #include <regex>
11
+ #include <stdexcept>
12
+
13
+ namespace Services {
14
+ const std::array<std::string, 9> CommandService::dangerous_commands = {
15
+ "rm", "sudo rm", "format", "del /", "shutdown",
16
+ "reboot", "mkfs", "fdisk", "dd"};
17
+
18
+ bool CommandService::is_dangerous_command(const std::string &command) {
19
+ // Token-based matching to avoid substring false positives
20
+ for (const auto &danger : dangerous_commands) {
21
+ std::regex pattern(
22
+ "\\b" + std::regex_replace(danger, std::regex(" "), "\\s+") + "\\b");
23
+ if (std::regex_search(command, pattern)) {
24
+ return true;
25
+ }
26
+ }
27
+ return false;
28
+ }
29
+
30
+ std::string
31
+ CommandService::execute_command([[maybe_unused]] const std::string &command,
32
+ FILE *pipe) {
33
+ if (!pipe) {
34
+ throw std::runtime_error("Failed to execute command");
35
+ }
36
+
37
+ std::string result;
38
+ char buffer[256];
39
+ size_t total_bytes = 0;
40
+ const size_t MAX_BYTES = 10 * 1024; // 10 KB limit
41
+
42
+ while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
43
+ total_bytes += strlen(buffer);
44
+ if (total_bytes > MAX_BYTES) {
45
+ result += "\n[Output truncated]";
46
+ break;
47
+ }
48
+ result += buffer;
49
+ }
50
+
51
+ int exit_code = Utils::Platform::close_process(pipe);
52
+ if (exit_code != 0) {
53
+ result += "\nExit code: " + std::to_string(exit_code);
54
+ }
55
+
56
+ return result.empty() ? "Command completed" : result;
57
+ }
58
+
59
+ std::string CommandService::execute(const std::string &command) {
60
+ if (is_dangerous_command(command)) {
61
+ return "Error: Dangerous command blocked";
62
+ }
63
+
64
+ try {
65
+ auto future = std::async(std::launch::async, [&]() -> std::string {
66
+ // Use platform-agnostic process handling
67
+ FILE *pipe = Utils::Platform::open_process(
68
+ command + Utils::Platform::get_shell_redirect_both(), "r");
69
+ return execute_command(command, pipe);
70
+ });
71
+
72
+ // Timeout: 5 seconds
73
+ if (future.wait_for(std::chrono::seconds(5)) ==
74
+ std::future_status::timeout) {
75
+ return "Error: Command timed out";
76
+ }
77
+ return future.get();
78
+ } catch (const std::exception &e) {
79
+ return std::string("Error executing command: ") + e.what();
80
+ }
81
+ }
82
+ } // namespace Services
@@ -0,0 +1,348 @@
1
+ #include "services/context_service.h"
2
+ #include <algorithm>
3
+ #include <cstdlib>
4
+ #include <filesystem>
5
+ #include <fstream>
6
+ #include <iostream>
7
+ #include <sstream>
8
+
9
+ namespace Services {
10
+
11
+ // Static member definitions
12
+ std::map<std::string, std::string> ContextService::context_cache;
13
+ std::string ContextService::cached_working_directory;
14
+
15
+ std::string ContextService::load_hierarchical_context(
16
+ const std::string &working_directory) {
17
+ // Check cache first
18
+ if (cached_working_directory == working_directory &&
19
+ context_cache.find("hierarchical") != context_cache.end()) {
20
+ return context_cache["hierarchical"];
21
+ }
22
+
23
+ std::vector<ContextFile> all_files = find_context_files(working_directory);
24
+ std::string merged_context = merge_context_files(all_files);
25
+
26
+ // Update cache
27
+ cached_working_directory = working_directory;
28
+ context_cache["hierarchical"] = merged_context;
29
+
30
+ return merged_context;
31
+ }
32
+
33
+ std::vector<ContextFile>
34
+ ContextService::find_context_files(const std::string &working_directory) {
35
+ std::vector<ContextFile> files;
36
+
37
+ // 1. Load global context (highest priority)
38
+ ContextFile global_context = load_global_context();
39
+ if (!global_context.content.empty()) {
40
+ files.push_back(global_context);
41
+ }
42
+
43
+ // 2. Load project context files (from root to current)
44
+ auto project_files = load_project_context(working_directory);
45
+ files.insert(files.end(), project_files.begin(), project_files.end());
46
+
47
+ // 3. Load local context files (current directory and subdirectories)
48
+ auto local_files = load_local_context(working_directory);
49
+ files.insert(files.end(), local_files.begin(), local_files.end());
50
+
51
+ // Sort by priority (higher priority first)
52
+ std::sort(files.begin(), files.end(),
53
+ [](const ContextFile &a, const ContextFile &b) {
54
+ return a.priority > b.priority;
55
+ });
56
+
57
+ return files;
58
+ }
59
+
60
+ ContextFile ContextService::load_global_context() {
61
+ ContextFile context;
62
+ context.source = "global";
63
+ context.priority = 100; // Highest priority
64
+
65
+ std::string home_dir = get_home_directory();
66
+ if (home_dir.empty()) {
67
+ return context;
68
+ }
69
+
70
+ std::string global_path = home_dir + "/.cursor/CURSOR.md";
71
+
72
+ if (is_readable_file(global_path)) {
73
+ context.file_path = global_path;
74
+ context.content = load_file_content(global_path);
75
+ }
76
+
77
+ return context;
78
+ }
79
+
80
+ std::vector<ContextFile>
81
+ ContextService::load_project_context(const std::string &working_directory) {
82
+ std::vector<ContextFile> files;
83
+
84
+ // Find project root
85
+ std::string project_root = find_project_root(working_directory);
86
+ if (project_root.empty()) {
87
+ return files;
88
+ }
89
+
90
+ // Walk from project root to current directory
91
+ std::filesystem::path current_path =
92
+ std::filesystem::absolute(working_directory);
93
+ std::filesystem::path root_path = std::filesystem::absolute(project_root);
94
+
95
+ std::vector<std::filesystem::path> path_hierarchy;
96
+
97
+ // Build path hierarchy from root to current
98
+ std::filesystem::path temp_path = current_path;
99
+ while (temp_path != root_path && temp_path.has_parent_path()) {
100
+ path_hierarchy.push_back(temp_path);
101
+ temp_path = temp_path.parent_path();
102
+ }
103
+ path_hierarchy.push_back(root_path);
104
+
105
+ // Reverse to go from root to current
106
+ std::reverse(path_hierarchy.begin(), path_hierarchy.end());
107
+
108
+ // Load CURSOR.md files in hierarchy order
109
+ int priority = 90; // Start below global priority
110
+ for (const auto &path : path_hierarchy) {
111
+ std::string context_file = path.string() + "/CURSOR.md";
112
+
113
+ if (is_readable_file(context_file)) {
114
+ ContextFile context;
115
+ context.file_path = context_file;
116
+ context.content = load_file_content(context_file);
117
+ context.priority = priority;
118
+ context.source = "project";
119
+
120
+ files.push_back(context);
121
+ }
122
+
123
+ priority -= 10; // Decrease priority as we go deeper
124
+ }
125
+
126
+ return files;
127
+ }
128
+
129
+ std::vector<ContextFile>
130
+ ContextService::load_local_context(const std::string &working_directory) {
131
+ std::vector<ContextFile> files;
132
+
133
+ try {
134
+ // Look for CURSOR.md files in subdirectories
135
+ for (const auto &entry :
136
+ std::filesystem::recursive_directory_iterator(working_directory)) {
137
+ if (entry.is_regular_file() &&
138
+ entry.path().filename() == "CURSOR.md") {
139
+
140
+ std::string entry_path = entry.path().string();
141
+
142
+ // Simple check - if it's in a parent directory, skip
143
+ std::filesystem::path rel_path =
144
+ std::filesystem::relative(entry.path(), working_directory);
145
+ if (rel_path.string().find("..") == 0) {
146
+ continue;
147
+ }
148
+
149
+ ContextFile context;
150
+ context.file_path = entry_path;
151
+ context.content = load_file_content(entry_path);
152
+ context.priority = 10; // Lower priority than project files
153
+ context.source = "local";
154
+
155
+ files.push_back(context);
156
+ }
157
+ }
158
+ } catch (const std::exception &e) {
159
+ std::cerr << "Error loading local context: " << e.what() << std::endl;
160
+ }
161
+
162
+ return files;
163
+ }
164
+
165
+ std::string
166
+ ContextService::merge_context_files(const std::vector<ContextFile> &files) {
167
+ if (files.empty()) {
168
+ return "";
169
+ }
170
+
171
+ std::ostringstream merged;
172
+ merged << "# Cursor Context\n\n";
173
+
174
+ // Group files by source
175
+ std::map<std::string, std::vector<const ContextFile *>> files_by_source;
176
+ for (const auto &file : files) {
177
+ files_by_source[file.source].push_back(&file);
178
+ }
179
+
180
+ // Output in order: global, project, local
181
+ std::vector<std::string> source_order = {"global", "project", "local"};
182
+
183
+ for (const auto &source : source_order) {
184
+ if (files_by_source.find(source) == files_by_source.end()) {
185
+ continue;
186
+ }
187
+
188
+ merged << "## " << source << " Context\n\n";
189
+
190
+ for (const auto *file : files_by_source[source]) {
191
+ std::string display_path = get_display_path(file->file_path, ".");
192
+ merged << "### From: " << display_path << "\n\n";
193
+ merged << file->content;
194
+
195
+ if (!file->content.empty() && file->content.back() != '\n') {
196
+ merged << "\n";
197
+ }
198
+ merged << "\n";
199
+ }
200
+ }
201
+
202
+ return merged.str();
203
+ }
204
+
205
+ std::string
206
+ ContextService::find_project_root(const std::string &starting_directory) {
207
+ std::filesystem::path current_path =
208
+ std::filesystem::absolute(starting_directory);
209
+
210
+ while (current_path.has_parent_path()) {
211
+ if (is_project_root(current_path.string())) {
212
+ return current_path.string();
213
+ }
214
+ current_path = current_path.parent_path();
215
+ }
216
+
217
+ return ""; // No project root found
218
+ }
219
+
220
+ bool ContextService::is_project_root(const std::string &directory) {
221
+ std::vector<std::string> project_markers = {
222
+ ".git", "package.json", "CMakeLists.txt", "Makefile",
223
+ "Cargo.toml", "pom.xml", "build.gradle", "requirements.txt",
224
+ "setup.py", "go.mod", ".gitignore"};
225
+
226
+ for (const auto &marker : project_markers) {
227
+ std::string marker_path = directory + "/" + marker;
228
+ if (std::filesystem::exists(marker_path)) {
229
+ return true;
230
+ }
231
+ }
232
+
233
+ return false;
234
+ }
235
+
236
+ void ContextService::refresh_context_cache() {
237
+ context_cache.clear();
238
+ cached_working_directory.clear();
239
+ }
240
+
241
+ std::string ContextService::get_context_template() {
242
+ return R"(# Cursor Context File
243
+
244
+ This file provides context and instructions for Cursor AI assistant.
245
+
246
+ ## Project Overview
247
+
248
+ Brief description of this project/component.
249
+
250
+ ## Key Information
251
+
252
+ - Important facts about the codebase
253
+ - Coding standards and conventions
254
+ - Architecture decisions
255
+ - Dependencies and requirements
256
+
257
+ ## Instructions for AI
258
+
259
+ - Specific guidance for AI when working in this context
260
+ - Preferred approaches or patterns
261
+ - Things to avoid or be careful about
262
+
263
+ ## Examples
264
+
265
+ ```
266
+ Example code or commands that are commonly used in this context
267
+ ```
268
+
269
+ ## References
270
+
271
+ - Links to documentation
272
+ - Related files or components
273
+ - External resources
274
+ )";
275
+ }
276
+
277
+ bool ContextService::create_context_file(const std::string &directory,
278
+ const std::string &content) {
279
+ try {
280
+ std::string file_path = directory + "/CURSOR.md";
281
+
282
+ // Don't overwrite existing file
283
+ if (std::filesystem::exists(file_path)) {
284
+ return false;
285
+ }
286
+
287
+ std::ofstream file(file_path);
288
+ if (!file.is_open()) {
289
+ return false;
290
+ }
291
+
292
+ if (content.empty()) {
293
+ file << get_context_template();
294
+ } else {
295
+ file << content;
296
+ }
297
+
298
+ return true;
299
+ } catch (const std::exception &) {
300
+ return false;
301
+ }
302
+ }
303
+
304
+ std::string ContextService::get_home_directory() {
305
+ const char *home = std::getenv("HOME");
306
+ if (!home) {
307
+ home = std::getenv("USERPROFILE"); // Windows
308
+ }
309
+ return home ? std::string(home) : "";
310
+ }
311
+
312
+ bool ContextService::is_readable_file(const std::string &file_path) {
313
+ try {
314
+ return std::filesystem::exists(file_path) &&
315
+ std::filesystem::is_regular_file(file_path);
316
+ } catch (const std::exception &) {
317
+ return false;
318
+ }
319
+ }
320
+
321
+ std::string ContextService::load_file_content(const std::string &file_path) {
322
+ try {
323
+ std::ifstream file(file_path);
324
+ if (!file.is_open()) {
325
+ return "";
326
+ }
327
+
328
+ std::ostringstream content;
329
+ content << file.rdbuf();
330
+ return content.str();
331
+ } catch (const std::exception &) {
332
+ return "";
333
+ }
334
+ }
335
+
336
+ std::string
337
+ ContextService::get_display_path(const std::string &file_path,
338
+ const std::string &base_directory) {
339
+ try {
340
+ std::filesystem::path rel_path =
341
+ std::filesystem::relative(file_path, base_directory);
342
+ return rel_path.string();
343
+ } catch (const std::exception &) {
344
+ return file_path;
345
+ }
346
+ }
347
+
348
+ } // namespace Services
@@ -0,0 +1,148 @@
1
+ #include "services/database_service.h"
2
+ #include <iostream>
3
+ #include <vector>
4
+
5
+ namespace cursor {
6
+
7
+ DatabaseService::DatabaseService()
8
+ #ifdef HAVE_PQXX
9
+ : connection_(nullptr)
10
+ #endif
11
+ {
12
+ }
13
+
14
+ DatabaseService::~DatabaseService() { disconnect(); }
15
+
16
+ bool DatabaseService::connect(const std::string &host, int port,
17
+ const std::string &dbname,
18
+ const std::string &user,
19
+ const std::string &password) {
20
+ #ifdef HAVE_PQXX
21
+ try {
22
+ std::string connection_string =
23
+ "host=" + host + " port=" + std::to_string(port) + " dbname=" + dbname +
24
+ " user=" + user + " password=" + password;
25
+
26
+ connection_ = std::make_unique<pqxx::connection>(connection_string);
27
+
28
+ // The pqxx::connection constructor throws on failure, so if we get here,
29
+ // the connection is open.
30
+ std::cout << "Connected to database: " << connection_->dbname()
31
+ << std::endl;
32
+ return true;
33
+ } catch (const std::exception &e) {
34
+ std::cerr << "Database connection error: " << e.what() << std::endl;
35
+ return false;
36
+ }
37
+ #else
38
+ (void)host;
39
+ (void)port;
40
+ (void)dbname;
41
+ (void)user;
42
+ (void)password;
43
+ return false;
44
+ #endif
45
+ }
46
+
47
+ void DatabaseService::disconnect() {
48
+ #ifdef HAVE_PQXX
49
+ connection_.reset();
50
+ #endif
51
+ }
52
+
53
+ bool DatabaseService::isConnected() const {
54
+ #ifdef HAVE_PQXX
55
+ return connection_ && connection_->is_open();
56
+ #else
57
+ return false;
58
+ #endif
59
+ }
60
+
61
+ bool DatabaseService::executeQuery(const std::string &query,
62
+ const std::vector<std::string> &params) {
63
+ #ifdef HAVE_PQXX
64
+ if (!isConnected()) {
65
+ std::cerr << "Not connected to database" << std::endl;
66
+ return false;
67
+ }
68
+
69
+ try {
70
+ pqxx::work txn(*connection_);
71
+ #if defined(__APPLE__)
72
+ pqxx::params p;
73
+ for (const auto &param : params) {
74
+ p.append(param);
75
+ }
76
+ txn.exec(query, p);
77
+ #else
78
+ std::string q = query;
79
+ for (size_t i = 0; i < params.size(); ++i) {
80
+ std::string placeholder = "$" + std::to_string(i + 1);
81
+ size_t pos = q.find(placeholder);
82
+ if (pos != std::string::npos) {
83
+ q.replace(pos, placeholder.size(), txn.quote(params[i]));
84
+ }
85
+ }
86
+ txn.exec(q);
87
+ #endif
88
+ txn.commit();
89
+ return true;
90
+ } catch (const std::exception &e) {
91
+ std::cerr << "Query execution error: " << e.what() << std::endl;
92
+ return false;
93
+ }
94
+ #else
95
+ (void)query;
96
+ (void)params;
97
+ std::cerr << "Database support is disabled as libpqxx is not available."
98
+ << std::endl;
99
+ return false;
100
+ #endif
101
+ }
102
+
103
+ std::unique_ptr<pqxx::result>
104
+ DatabaseService::executeSelect(const std::string &query,
105
+ const std::vector<std::string> &params) {
106
+ #ifdef HAVE_PQXX
107
+ if (!isConnected()) {
108
+ std::cerr << "Not connected to database" << std::endl;
109
+ return nullptr;
110
+ }
111
+
112
+ try {
113
+ pqxx::work txn(*connection_);
114
+ #if defined(__APPLE__)
115
+ pqxx::params p;
116
+ for (const auto &param : params) {
117
+ p.append(param);
118
+ }
119
+ auto result = txn.exec(query, p);
120
+ txn.commit();
121
+ return std::make_unique<pqxx::result>(std::move(result));
122
+ #else
123
+ std::string q = query;
124
+ for (size_t i = 0; i < params.size(); ++i) {
125
+ std::string placeholder = "$" + std::to_string(i + 1);
126
+ size_t pos = q.find(placeholder);
127
+ if (pos != std::string::npos) {
128
+ q.replace(pos, placeholder.size(), txn.quote(params[i]));
129
+ }
130
+ }
131
+ auto result = txn.exec(q);
132
+ txn.commit();
133
+ return std::make_unique<pqxx::result>(std::move(result));
134
+ #endif
135
+ } catch (const std::exception &e) {
136
+ std::cerr << "Select query error: " << e.what() << std::endl;
137
+ return nullptr;
138
+ }
139
+ #else
140
+ (void)query;
141
+ (void)params;
142
+ std::cerr << "Database support is disabled as libpqxx is not available."
143
+ << std::endl;
144
+ return nullptr;
145
+ #endif
146
+ }
147
+
148
+ } // namespace cursor