@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,175 @@
1
+ #include "version.h"
2
+ #include <filesystem>
3
+ #include <iostream>
4
+ #include <string>
5
+
6
+ #include <curl/curl.h>
7
+
8
+ #ifdef __APPLE__
9
+ #include <mach-o/dyld.h>
10
+ #endif
11
+
12
+ namespace {
13
+
14
+ size_t write_to_string(void *ptr, size_t size, size_t nmemb, void *userdata) {
15
+ auto *str = static_cast<std::string *>(userdata);
16
+ str->append(static_cast<char *>(ptr), size * nmemb);
17
+ return size * nmemb;
18
+ }
19
+
20
+ size_t write_to_file(void *ptr, size_t size, size_t nmemb, void *userdata) {
21
+ auto *file = static_cast<FILE *>(userdata);
22
+ return fwrite(ptr, size, nmemb, file);
23
+ }
24
+
25
+ std::string get_platform_binary_name() {
26
+ #ifdef _WIN32
27
+ return "cursor-windows.exe";
28
+ #elif defined(__APPLE__)
29
+ return "cursor-macos";
30
+ #else
31
+ return "cursor-linux";
32
+ #endif
33
+ }
34
+
35
+ std::string get_exe_path() {
36
+ try {
37
+ return std::filesystem::canonical("/proc/self/exc").string();
38
+ } catch (...) {
39
+ }
40
+ #ifdef __APPLE__
41
+ char buf[1024];
42
+ uint32_t size = sizeof(buf);
43
+ if (_NSGetExecutablePath(buf, &size) == 0) {
44
+ return std::filesystem::canonical(buf).string();
45
+ }
46
+ #endif
47
+ return {};
48
+ }
49
+
50
+ std::string fetch_latest_version() {
51
+ CURL *curl = curl_easy_init();
52
+ if (!curl)
53
+ return {};
54
+
55
+ std::string response;
56
+ curl_easy_setopt(curl, CURLOPT_URL,
57
+ "https://api.github.com/repos/bniladridas/cursor/releases/"
58
+ "latest");
59
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, "cursor-agent");
60
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
61
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
62
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
63
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
64
+
65
+ CURLcode res = curl_easy_perform(curl);
66
+ curl_easy_cleanup(curl);
67
+
68
+ if (res != CURLE_OK)
69
+ return {};
70
+
71
+ auto tag_pos = response.find("\"tag_name\":\"");
72
+ if (tag_pos == std::string::npos)
73
+ return {};
74
+ tag_pos += 13;
75
+ auto tag_end = response.find("\"", tag_pos);
76
+ return response.substr(tag_pos, tag_end - tag_pos);
77
+ }
78
+
79
+ } // namespace
80
+
81
+ namespace Version {
82
+
83
+ const char *get_version() { return cursor_version_string; }
84
+
85
+ const char *get_build_info() {
86
+ static std::string build_info;
87
+ if (build_info.empty()) {
88
+ build_info = std::string(__DATE__) + " " + __TIME__;
89
+ }
90
+ return build_info.c_str();
91
+ }
92
+
93
+ void print_version_info() {
94
+ std::cout << "Cursor v" << get_version() << "\n";
95
+ std::cout << "Built: " << get_build_info() << "\n";
96
+ }
97
+
98
+ std::string check_update() {
99
+ std::string latest = fetch_latest_version();
100
+ if (latest.empty() || latest == get_version())
101
+ return {};
102
+ return latest;
103
+ }
104
+
105
+ bool download_and_install(const std::string &version) {
106
+ std::string binary_name = get_platform_binary_name();
107
+ std::string url =
108
+ "https://github.com/bniladridas/cursor/releases/download/" + version +
109
+ "/" + binary_name;
110
+
111
+ std::string tmp = "/tmp/cursor-update-" + version;
112
+ #ifdef _WIN32
113
+ tmp += ".exe";
114
+ #endif
115
+
116
+ std::cout << "Downloading v" << version << "...\n";
117
+
118
+ FILE *fp = fopen(tmp.c_str(), "wb");
119
+ if (!fp) {
120
+ std::cerr << "Failed to create temp file\n";
121
+ return false;
122
+ }
123
+
124
+ CURL *curl = curl_easy_init();
125
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
126
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, "cursor-agent");
127
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_file);
128
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
129
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
130
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
131
+
132
+ CURLcode res = curl_easy_perform(curl);
133
+ curl_easy_cleanup(curl);
134
+ fclose(fp);
135
+
136
+ if (res != CURLE_OK) {
137
+ std::cerr << "Download failed: " << curl_easy_strerror(res) << "\n";
138
+ std::filesystem::remove(tmp);
139
+ return false;
140
+ }
141
+
142
+ std::filesystem::permissions(tmp,
143
+ std::filesystem::perms::owner_exec |
144
+ std::filesystem::perms::owner_read |
145
+ std::filesystem::perms::owner_write,
146
+ std::filesystem::perm_options::add);
147
+
148
+ std::string exe = get_exe_path();
149
+ if (exe.empty()) {
150
+ std::cerr << "Downloaded to: " << tmp << "\nManually replace binary.\n";
151
+ return false;
152
+ }
153
+
154
+ std::string backup = exe + ".bak";
155
+ std::error_code ec;
156
+ std::filesystem::rename(exe, backup, ec);
157
+ if (ec) {
158
+ std::cerr << "Failed to backup: " << ec.message() << "\n";
159
+ std::filesystem::remove(tmp);
160
+ return false;
161
+ }
162
+
163
+ std::filesystem::rename(tmp, exe, ec);
164
+ if (ec) {
165
+ std::cerr << "Failed to install: " << ec.message() << "\n";
166
+ std::filesystem::rename(backup, exe);
167
+ std::filesystem::remove(tmp);
168
+ return false;
169
+ }
170
+
171
+ std::cout << "Updated to v" << version << " successfully!\n";
172
+ return true;
173
+ }
174
+
175
+ } // namespace Version
@@ -0,0 +1,195 @@
1
+ networks:
2
+ e2e-network:
3
+ driver: bridge
4
+
5
+ services:
6
+ mock-together:
7
+ image: nginx:alpine
8
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
9
+ healthcheck:
10
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
11
+ interval: 10s
12
+ timeout: 5s
13
+ retries: 3
14
+ start_period: 10s
15
+ container_name: mock-together
16
+ environment:
17
+ - MOCK_TYPE=together
18
+ ports:
19
+ - "8081:80"
20
+ volumes:
21
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
22
+ networks:
23
+ - e2e-network
24
+
25
+ mock-cerebras:
26
+ image: nginx:alpine
27
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
28
+ healthcheck:
29
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
30
+ interval: 10s
31
+ timeout: 5s
32
+ retries: 3
33
+ start_period: 10s
34
+ container_name: mock-cerebras
35
+ environment:
36
+ - MOCK_TYPE=cerebras
37
+ ports:
38
+ - "8082:80"
39
+ volumes:
40
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
41
+ networks:
42
+ - e2e-network
43
+
44
+ mock-fireworks:
45
+ image: nginx:alpine
46
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
47
+ healthcheck:
48
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
49
+ interval: 10s
50
+ timeout: 5s
51
+ retries: 3
52
+ start_period: 10s
53
+ container_name: mock-fireworks
54
+ environment:
55
+ - MOCK_TYPE=fireworks
56
+ ports:
57
+ - "8083:80"
58
+ volumes:
59
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
60
+ networks:
61
+ - e2e-network
62
+
63
+ mock-groq:
64
+ image: nginx:alpine
65
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
66
+ healthcheck:
67
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
68
+ interval: 10s
69
+ timeout: 5s
70
+ retries: 3
71
+ start_period: 10s
72
+ container_name: mock-groq
73
+ environment:
74
+ - MOCK_TYPE=groq
75
+ ports:
76
+ - "8084:80"
77
+ volumes:
78
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
79
+ networks:
80
+ - e2e-network
81
+
82
+ mock-deepseek:
83
+ image: nginx:alpine
84
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
85
+ healthcheck:
86
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
87
+ interval: 10s
88
+ timeout: 5s
89
+ retries: 3
90
+ start_period: 10s
91
+ container_name: mock-deepseek
92
+ environment:
93
+ - MOCK_TYPE=deepseek
94
+ ports:
95
+ - "8085:80"
96
+ volumes:
97
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
98
+ networks:
99
+ - e2e-network
100
+
101
+ mock-openai:
102
+ image: nginx:alpine
103
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
104
+ healthcheck:
105
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
106
+ interval: 10s
107
+ timeout: 5s
108
+ retries: 3
109
+ start_period: 10s
110
+ container_name: mock-openai
111
+ environment:
112
+ - MOCK_TYPE=openai
113
+ ports:
114
+ - "8086:80"
115
+ volumes:
116
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
117
+ networks:
118
+ - e2e-network
119
+
120
+ mock-ollama:
121
+ image: nginx:alpine
122
+ entrypoint: ["/bin/sh", "/start_nginx.sh"]
123
+ healthcheck:
124
+ test: ["CMD", "wget", "-qO-", "--spider", "http://127.0.0.1/health"]
125
+ interval: 10s
126
+ timeout: 5s
127
+ retries: 3
128
+ start_period: 10s
129
+ container_name: mock-ollama
130
+ environment:
131
+ - MOCK_TYPE=ollama
132
+ ports:
133
+ - "11434:80"
134
+ volumes:
135
+ - ./tests/mocks/start_nginx.sh:/start_nginx.sh:ro
136
+ networks:
137
+ - e2e-network
138
+
139
+ e2e-tests:
140
+ build:
141
+ context: .
142
+ dockerfile: .github/packaging/docker/Dockerfile
143
+ target: builder
144
+ container_name: cursor-e2e-tests
145
+ depends_on:
146
+ - mock-together
147
+ - mock-cerebras
148
+ - mock-fireworks
149
+ - mock-groq
150
+ - mock-deepseek
151
+ - mock-openai
152
+ - mock-ollama
153
+ environment:
154
+ - TOGETHER_API_KEY=test-key
155
+ - CEREBRAS_API_KEY=test-key
156
+ - FIREWORKS_API_KEY=test-key
157
+ - GROQ_API_KEY=test-key
158
+ - DEEPSEEK_API_KEY=test-key
159
+ - OPENAI_API_KEY=test-key
160
+ - SERPAPI_KEY=test-key
161
+ - OLLAMA_HOST=http://mock-ollama:11434
162
+ - TEST_MODE=1
163
+ - BUILDKIT_INLINE_CACHE=1
164
+ volumes:
165
+ - .:/app
166
+ - /app/build
167
+ - /root/.cache
168
+ working_dir: /app
169
+ user: root
170
+ command:
171
+ - "bash"
172
+ - "-c"
173
+ - "ulimit -c unlimited && /app/tests/e2e/run_tests_in_docker.sh || touch /app/tests/e2e/.e2e_failed"
174
+ security_opt:
175
+ - seccomp:unconfined
176
+ cap_add:
177
+ - SYS_PTRACE
178
+ stop_grace_period: 10s
179
+ stop_signal: SIGTERM
180
+ healthcheck:
181
+ test: ["CMD", "true"]
182
+ interval: 60s
183
+ timeout: 5s
184
+ retries: 1
185
+ restart: "no"
186
+ networks:
187
+ - e2e-network
188
+ deploy:
189
+ resources:
190
+ limits:
191
+ cpus: '2'
192
+ memory: 4G
193
+ pids: 1024
194
+ tmpfs:
195
+ - /tmp:exec,mode=1777
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/expect -f
2
+
3
+ set timeout 30
4
+ set test_passed 1
5
+ set BINARY_PATH $env(BINARY_PATH)
6
+
7
+ # Function to run a test
8
+ proc run_test {test_name mode_selection expected_response} {
9
+ global test_passed BINARY_PATH
10
+
11
+ send_user "Running test: $test_name\n"
12
+
13
+ # Start the agent
14
+ spawn $BINARY_PATH
15
+ expect "Mode"
16
+
17
+ # Select online mode
18
+ send "1\r"
19
+ expect "Provider"
20
+
21
+ # Select the provider
22
+ send "$mode_selection\r"
23
+ expect "Ready"
24
+
25
+ # Send a test message
26
+ send "Hello\r"
27
+ expect {
28
+ "$expected_response" {
29
+ send_user "✓ Test $test_name passed\n"
30
+ }
31
+ timeout {
32
+ send_user "✗ Test $test_name failed: timeout\n"
33
+ set test_passed 0
34
+ }
35
+ eof {
36
+ send_user "✗ Test $test_name failed: unexpected EOF\n"
37
+ set test_passed 0
38
+ }
39
+ }
40
+
41
+ # Exit
42
+ send "exit\r"
43
+ expect eof
44
+ }
45
+
46
+ # Test Fireworks
47
+ run_test "Fireworks" "3" "Mock Fireworks response"
48
+
49
+ # Test Groq
50
+ run_test "Groq" "4" "Mock Groq response"
51
+
52
+ # Test DeepSeek
53
+ run_test "DeepSeek" "5" "Mock DeepSeek response"
54
+
55
+ # Test OpenAI
56
+ run_test "OpenAI" "6" "Mock OpenAI response"
57
+
58
+ # Test Together (existing)
59
+ run_test "Together" "1" "Mock Together AI response"
60
+
61
+ # Test Cerebras (existing)
62
+ run_test "Cerebras" "2" "Mock Cerebras response"
63
+
64
+ if {$test_passed} {
65
+ send_user "All E2E tests passed!\n"
66
+ exit 0
67
+ } else {
68
+ send_user "Some E2E tests failed!\n"
69
+ exit 1
70
+ }
@@ -0,0 +1,115 @@
1
+ #!/bin/bash
2
+ set -e
3
+ set -o pipefail
4
+
5
+ # Cleanup function to ensure proper shutdown
6
+ cleanup() {
7
+ local exit_code=$?
8
+ echo "=== Cleaning up test environment ==="
9
+ # Kill any remaining child processes
10
+ pkill -P $$ 2>/dev/null || true
11
+ # Return the exit code without exiting
12
+ return $exit_code
13
+ }
14
+
15
+ # Set up trap to ensure cleanup runs on exit and preserves exit code
16
+ handle_exit() {
17
+ cleanup
18
+ exit $?
19
+ }
20
+ trap handle_exit EXIT INT TERM
21
+
22
+ # Print environment for debugging
23
+ echo "=== Environment ==="
24
+ printenv | sort
25
+ echo "=================="
26
+
27
+ # Enable core dumps for debugging segfaults
28
+ ulimit -c unlimited
29
+
30
+ # Set test data directory
31
+ export TEST_DATA_DIR="/tmp/cursor_test_data"
32
+
33
+ # Clean up any previous builds
34
+ echo "=== Cleaning previous builds ==="
35
+ rm -rf /tmp/app
36
+ mkdir -p /tmp/app
37
+
38
+ # Copy only the necessary files using cp
39
+ echo "=== Copying application files ==="
40
+ cp -r /app/. /tmp/app/
41
+ rm -rf /tmp/app/build
42
+ rm -rf /tmp/app/.git
43
+
44
+ # Verify expect is installed
45
+ echo "=== Verifying test dependencies ==="
46
+ command -v expect >/dev/null 2>&1 || { echo >&2 "expect is required but not installed. Aborting."; exit 1; }
47
+ command -v python3 >/dev/null 2>&1 || { echo >&2 "python3 is required but not installed. Aborting."; exit 1; }
48
+
49
+ # Wait for mock services to be ready
50
+ echo "=== Waiting for mock services to be ready ==="
51
+ for service in mock-together mock-cerebras mock-fireworks mock-groq mock-deepseek mock-openai mock-ollama; do
52
+ echo "Waiting for $service..."
53
+ timeout 60 bash -c "until wget -qO- http://$service/health 2>/dev/null | grep -q 'healthy'; do sleep 2; done" || {
54
+ echo "Service $service failed to become ready"
55
+ exit 1
56
+ }
57
+ echo "$service is ready"
58
+ done
59
+
60
+ # Build the project
61
+ echo "=== Building the project ==="
62
+ cd /tmp/app
63
+ mkdir -p build
64
+ cd build
65
+ cmake ..
66
+ make -j1
67
+
68
+ # Set binary path for E2E tests
69
+ export BINARY_PATH="/tmp/app/build/bin/cursor-agent"
70
+
71
+ # Run unit tests
72
+ echo "=== Running unit tests ==="
73
+ ctest --output-on-failure
74
+
75
+ # Run E2E tests
76
+ echo "=== Running E2E tests ==="
77
+ cd ../tests/e2e
78
+ chmod +x ./run_e2e_tests.sh
79
+
80
+ # Create test data directory
81
+ mkdir -p "$TEST_DATA_DIR"
82
+
83
+ # Set environment variables for debugging
84
+ export EXPECT_DEBUG=1
85
+
86
+ # Run tests with a longer timeout and better error handling
87
+ set +e
88
+ start_time=$(date +%s)
89
+ timeout 600s ./run_e2e_tests.sh > >(tee -a e2e_test.log) 2>&1
90
+ result=$?
91
+ end_time=$(date +%s)
92
+ duration=$((end_time - start_time))
93
+ set -e
94
+
95
+ # Copy all test artifacts to the host
96
+ cp -r e2e_test.log "$TEST_DATA_DIR/"* /app/tests/e2e/ 2>/dev/null || true
97
+
98
+ # Check test results
99
+ if [ $result -eq 0 ]; then
100
+ echo "=== E2E tests completed successfully in ${duration}s ==="
101
+ echo "=== Test logs saved to /app/tests/e2e/e2e_test.log ==="
102
+ touch /app/tests/e2e/.e2e_success
103
+ # Exit with success code
104
+ exit 0
105
+ else
106
+ echo "=== E2E tests failed after ${duration}s (exit code: $result) ==="
107
+ echo "=== Last 50 lines of test output ==="
108
+ tail -n 50 e2e_test.log || true
109
+ echo "=== Expect debug logs ==="
110
+ cat "$TEST_DATA_DIR/"expect_*.log 2>/dev/null || echo "No debug logs available"
111
+ echo "========================="
112
+ echo "=== Full test log available in /app/tests/e2e/e2e_test.log ==="
113
+ # Exit with failure code
114
+ exit $result
115
+ fi
@@ -0,0 +1,16 @@
1
+ #include "version.h"
2
+ #include <gtest/gtest.h>
3
+
4
+ // Basic test to verify the testing framework works
5
+ TEST(BasicTest, SanityCheck) { EXPECT_EQ(1 + 1, 2); }
6
+
7
+ // Test for version functionality
8
+ TEST(VersionTest, VersionCommand) {
9
+ const char *version = Version::get_version();
10
+ EXPECT_STREQ(version, cursor_version_string);
11
+ }
12
+
13
+ int main(int argc, char **argv) {
14
+ ::testing::InitGoogleTest(&argc, argv);
15
+ return RUN_ALL_TESTS();
16
+ }
@@ -0,0 +1,98 @@
1
+ import http.server
2
+ import socketserver
3
+ import json
4
+ import time
5
+
6
+ class Handler(http.server.BaseHTTPRequestHandler):
7
+ def _set_headers(self, content_type='application/json'):
8
+ self.send_response(200)
9
+ self.send_header('Content-type', content_type)
10
+ self.end_headers()
11
+
12
+ def do_HEAD(self):
13
+ """Handle HEAD requests (used for health checks)"""
14
+ self._set_headers('text/plain')
15
+
16
+ def do_GET(self):
17
+ if self.path == '/' or self.path == '/health':
18
+ self._set_headers('text/plain')
19
+ self.wfile.write(b'healthy\n')
20
+ elif self.path == '/api/tags':
21
+ self._set_headers()
22
+ response = {
23
+ 'models': [
24
+ {
25
+ 'name': 'llama3',
26
+ 'modified_at': '2023-09-23T00:00:00Z',
27
+ 'size': 4096,
28
+ 'digest': 'mock-digest-123',
29
+ 'details': {
30
+ 'format': 'gguf',
31
+ 'family': 'llama',
32
+ 'parameter_size': '8B',
33
+ 'quantization_level': 'Q4_0'
34
+ }
35
+ }
36
+ ]
37
+ }
38
+ self.wfile.write(json.dumps(response).encode('utf-8'))
39
+ else:
40
+ self.send_response(404)
41
+ self.end_headers()
42
+
43
+ def do_POST(self):
44
+ content_length = int(self.headers['Content-Length'])
45
+ post_data = self.rfile.read(content_length)
46
+
47
+ try:
48
+ data = json.loads(post_data.decode('utf-8'))
49
+
50
+ if self.path == '/api/generate':
51
+ self._set_headers()
52
+ response = {
53
+ 'model': data.get('model', 'llama3'),
54
+ 'created_at': '2023-09-23T00:00:00Z',
55
+ 'response': 'This is a mock response from Ollama.',
56
+ 'done': True,
57
+ 'context': [0] * 64, # Mock context
58
+ 'total_duration': 1000000000, # 1 second in nanoseconds
59
+ 'load_duration': 100000000,
60
+ 'prompt_eval_count': len(data.get('prompt', '').split()),
61
+ 'eval_count': 10,
62
+ 'eval_duration': 900000000
63
+ }
64
+ self.wfile.write(json.dumps(response).encode('utf-8'))
65
+ elif self.path == '/api/chat':
66
+ self._set_headers()
67
+ response = {
68
+ 'model': data.get('model', 'llama3.2:3b'),
69
+ 'created_at': '2023-09-23T00:00:00Z',
70
+ 'message': {
71
+ 'role': 'assistant',
72
+ 'content': 'This is a mock response from Ollama.'
73
+ },
74
+ 'done': True,
75
+ 'total_duration': 1000000000,
76
+ 'load_duration': 100000000,
77
+ 'prompt_eval_count': 10,
78
+ 'eval_count': 10,
79
+ 'eval_duration': 900000000
80
+ }
81
+ self.wfile.write(json.dumps(response).encode('utf-8'))
82
+ else:
83
+ self.send_response(404)
84
+ self.end_headers()
85
+
86
+ except json.JSONDecodeError:
87
+ self.send_response(400)
88
+ self.end_headers()
89
+ self.wfile.write(b'Invalid JSON')
90
+
91
+ def run(server_class=http.server.HTTPServer, handler_class=Handler, port=11434):
92
+ server_address = ('0.0.0.0', port)
93
+ httpd = server_class(server_address, handler_class)
94
+ print(f'Starting mock Ollama server on port {port}...')
95
+ httpd.serve_forever()
96
+
97
+ if __name__ == '__main__':
98
+ run()