embark-cli 1.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 (73) hide show
  1. package/.claude/CLAUDE.md +33 -0
  2. package/.claude/settings.local.json +32 -0
  3. package/.github/WORKFLOWS.md +147 -0
  4. package/.github/workflows/ci.yml +49 -0
  5. package/.github/workflows/publish.yml +109 -0
  6. package/.idea/embark-remote-mcp.iml +9 -0
  7. package/.idea/encodings.xml +4 -0
  8. package/.idea/indexLayout.xml +8 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/.mcp.json +14 -0
  11. package/GIT_DISCOVERY.md +231 -0
  12. package/INTEGRATION_TESTING.md +243 -0
  13. package/MULTI_REPOSITORY_SEARCH.md +242 -0
  14. package/README.md +434 -0
  15. package/dist/auth/auth-helper.d.ts +3 -0
  16. package/dist/auth/auth-helper.d.ts.map +1 -0
  17. package/dist/auth/auth-helper.js +171 -0
  18. package/dist/auth/auth-helper.js.map +1 -0
  19. package/dist/auth/index.d.ts +4 -0
  20. package/dist/auth/index.d.ts.map +1 -0
  21. package/dist/auth/index.js +24 -0
  22. package/dist/auth/index.js.map +1 -0
  23. package/dist/auth/jba-login.d.ts +17 -0
  24. package/dist/auth/jba-login.d.ts.map +1 -0
  25. package/dist/auth/jba-login.js +345 -0
  26. package/dist/auth/jba-login.js.map +1 -0
  27. package/dist/auth/types.d.ts +16 -0
  28. package/dist/auth/types.d.ts.map +1 -0
  29. package/dist/auth/types.js +3 -0
  30. package/dist/auth/types.js.map +1 -0
  31. package/dist/config.d.ts +26 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +54 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/embark-client.d.ts +56 -0
  36. package/dist/embark-client.d.ts.map +1 -0
  37. package/dist/embark-client.js +543 -0
  38. package/dist/embark-client.js.map +1 -0
  39. package/dist/git-utils.d.ts +47 -0
  40. package/dist/git-utils.d.ts.map +1 -0
  41. package/dist/git-utils.js +232 -0
  42. package/dist/git-utils.js.map +1 -0
  43. package/dist/handlers.d.ts +80 -0
  44. package/dist/handlers.d.ts.map +1 -0
  45. package/dist/handlers.js +301 -0
  46. package/dist/handlers.js.map +1 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +165 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/logger.d.ts +4 -0
  52. package/dist/logger.d.ts.map +1 -0
  53. package/dist/logger.js +92 -0
  54. package/dist/logger.js.map +1 -0
  55. package/dist/stats-server.d.ts +3 -0
  56. package/dist/stats-server.d.ts.map +1 -0
  57. package/dist/stats-server.js +623 -0
  58. package/dist/stats-server.js.map +1 -0
  59. package/dist/stats.d.ts +118 -0
  60. package/dist/stats.d.ts.map +1 -0
  61. package/dist/stats.js +206 -0
  62. package/dist/stats.js.map +1 -0
  63. package/dist/tools.d.ts +9 -0
  64. package/dist/tools.d.ts.map +1 -0
  65. package/dist/tools.js +62 -0
  66. package/dist/tools.js.map +1 -0
  67. package/package.json +47 -0
  68. package/test-git-discovery.mjs +322 -0
  69. package/test-multi-repo-filters.mjs +151 -0
  70. package/test-multiple-roots.mjs +436 -0
  71. package/test-roots.mjs +306 -0
  72. package/test-snippet-extraction.mjs +136 -0
  73. package/watch-logs.sh +78 -0
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test script for Git repository discovery from roots
5
+ *
6
+ * This script tests that the server can:
7
+ * 1. Accept roots from a client (simulated)
8
+ * 2. Discover Git remote URLs from those directories
9
+ * 3. Use the discovered URLs for searches
10
+ */
11
+
12
+ import { spawn } from 'child_process';
13
+ import { fileURLToPath } from 'url';
14
+ import { dirname, join } from 'path';
15
+ import { execSync } from 'child_process';
16
+
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = dirname(__filename);
19
+
20
+ // Configuration
21
+ const SERVER_PATH = join(__dirname, 'dist', 'index.js');
22
+ const TEST_ROOT = process.cwd(); // Use current directory as test root
23
+
24
+ // Colors for terminal output
25
+ const colors = {
26
+ reset: '\x1b[0m',
27
+ green: '\x1b[32m',
28
+ red: '\x1b[31m',
29
+ yellow: '\x1b[33m',
30
+ blue: '\x1b[34m',
31
+ gray: '\x1b[90m',
32
+ };
33
+
34
+ function log(message, color = colors.reset) {
35
+ console.log(`${color}${message}${colors.reset}`);
36
+ }
37
+
38
+ function logSuccess(message) {
39
+ log(`✓ ${message}`, colors.green);
40
+ }
41
+
42
+ function logError(message) {
43
+ log(`✗ ${message}`, colors.red);
44
+ }
45
+
46
+ function logInfo(message) {
47
+ log(`ℹ ${message}`, colors.blue);
48
+ }
49
+
50
+ function logDebug(message) {
51
+ log(` ${message}`, colors.gray);
52
+ }
53
+
54
+ /**
55
+ * Get Git remote URL from current directory
56
+ */
57
+ function getLocalGitRemote() {
58
+ try {
59
+ const result = execSync('git remote get-url origin', {
60
+ cwd: TEST_ROOT,
61
+ encoding: 'utf-8',
62
+ });
63
+ return result.trim();
64
+ } catch (error) {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Send a JSON-RPC request to the server
71
+ */
72
+ function sendRequest(server, request) {
73
+ return new Promise((resolve, reject) => {
74
+ const requestStr = JSON.stringify(request) + '\n';
75
+ logDebug(`→ ${requestStr.trim()}`);
76
+
77
+ let responseBuffer = '';
78
+ let resolved = false;
79
+
80
+ const onData = (data) => {
81
+ responseBuffer += data.toString();
82
+
83
+ // Try to parse complete JSON objects
84
+ const lines = responseBuffer.split('\n');
85
+ responseBuffer = lines.pop(); // Keep incomplete line in buffer
86
+
87
+ for (const line of lines) {
88
+ if (line.trim()) {
89
+ try {
90
+ const response = JSON.parse(line);
91
+ logDebug(`← ${line}`);
92
+
93
+ // Check if this is the response to our request
94
+ if (response.id === request.id) {
95
+ resolved = true;
96
+ server.stdout.off('data', onData);
97
+ resolve(response);
98
+ } else if (response.method === 'roots/list') {
99
+ // Server is requesting roots from us
100
+ logInfo('Server requested roots from client');
101
+ const rootsResponse = {
102
+ jsonrpc: '2.0',
103
+ id: response.id,
104
+ result: {
105
+ roots: [
106
+ {
107
+ uri: `file://${TEST_ROOT}`,
108
+ name: 'Test Project'
109
+ }
110
+ ]
111
+ }
112
+ };
113
+ const responseStr = JSON.stringify(rootsResponse) + '\n';
114
+ logDebug(`→ ${responseStr.trim()}`);
115
+ server.stdin.write(responseStr);
116
+ }
117
+ } catch (e) {
118
+ // Not valid JSON, continue accumulating
119
+ }
120
+ }
121
+ }
122
+ };
123
+
124
+ server.stdout.on('data', onData);
125
+
126
+ // Timeout after 10 seconds
127
+ setTimeout(() => {
128
+ if (!resolved) {
129
+ server.stdout.off('data', onData);
130
+ reject(new Error('Request timeout'));
131
+ }
132
+ }, 10000);
133
+
134
+ server.stdin.write(requestStr);
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Test server initialization
140
+ */
141
+ async function testInitialize(server) {
142
+ log('\n--- Testing initialization ---', colors.yellow);
143
+
144
+ const request = {
145
+ jsonrpc: '2.0',
146
+ id: 1,
147
+ method: 'initialize',
148
+ params: {
149
+ protocolVersion: '2024-11-05',
150
+ capabilities: {
151
+ roots: {
152
+ listChanged: true,
153
+ },
154
+ },
155
+ clientInfo: {
156
+ name: 'test-client',
157
+ version: '1.0.0',
158
+ },
159
+ },
160
+ };
161
+
162
+ try {
163
+ const response = await sendRequest(server, request);
164
+
165
+ if (response.error) {
166
+ logError(`Initialization error: ${JSON.stringify(response.error)}`);
167
+ return false;
168
+ }
169
+
170
+ if (!response.result) {
171
+ logError('Initialization response missing result');
172
+ return false;
173
+ }
174
+
175
+ logSuccess('Server initialized successfully');
176
+ return true;
177
+ } catch (error) {
178
+ logError(`Failed to initialize: ${error.message}`);
179
+ return false;
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Test that Git discovery works by making a search
185
+ */
186
+ async function testGitDiscovery(server, expectedGitUrl) {
187
+ log('\n--- Testing Git repository discovery ---', colors.yellow);
188
+
189
+ // Wait a bit for the server to process roots
190
+ await new Promise(resolve => setTimeout(resolve, 1000));
191
+
192
+ // Make a search request without specifying repository
193
+ const request = {
194
+ jsonrpc: '2.0',
195
+ id: 3,
196
+ method: 'tools/call',
197
+ params: {
198
+ name: 'semantic_code_search',
199
+ arguments: {
200
+ text: 'test search query',
201
+ }
202
+ }
203
+ };
204
+
205
+ try {
206
+ const response = await sendRequest(server, request);
207
+
208
+ if (response.error) {
209
+ logError(`Search error: ${JSON.stringify(response.error)}`);
210
+ return false;
211
+ }
212
+
213
+ const content = response.result?.content?.[0]?.text || '';
214
+
215
+ // Check if the response indicates the discovered repository was used
216
+ if (content.includes(expectedGitUrl) || !content.includes('No repository URL configured')) {
217
+ logSuccess('Git repository was discovered and used for search');
218
+ logInfo(`Repository: ${expectedGitUrl}`);
219
+ return true;
220
+ } else {
221
+ logError('Search did not use discovered Git repository');
222
+ logDebug(`Response: ${content}`);
223
+ return false;
224
+ }
225
+ } catch (error) {
226
+ logError(`Failed to test Git discovery: ${error.message}`);
227
+ return false;
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Main test runner
233
+ */
234
+ async function runTests() {
235
+ log('='.repeat(60), colors.blue);
236
+ log('MCP Server Git Discovery Testing', colors.blue);
237
+ log('='.repeat(60), colors.blue);
238
+
239
+ logInfo(`Server path: ${SERVER_PATH}`);
240
+ logInfo(`Test root: ${TEST_ROOT}`);
241
+
242
+ // Check if current directory is a Git repository
243
+ const gitRemote = getLocalGitRemote();
244
+ if (!gitRemote) {
245
+ logError('Current directory is not a Git repository or has no remote');
246
+ log('Please run this test from a Git repository with a configured remote', colors.yellow);
247
+ process.exit(1);
248
+ }
249
+
250
+ logInfo(`Expected Git remote: ${gitRemote}`);
251
+
252
+ // Spawn the server (without REPOSITORY_GIT_REMOTE_URL env var)
253
+ log('\n--- Starting MCP server ---', colors.yellow);
254
+ const server = spawn('node', [SERVER_PATH], {
255
+ env: {
256
+ ...process.env,
257
+ ENABLE_LOCAL_LOGS: 'true',
258
+ // Intentionally NOT setting REPOSITORY_GIT_REMOTE_URL
259
+ },
260
+ stdio: ['pipe', 'pipe', 'pipe'],
261
+ });
262
+
263
+ // Log stderr for debugging
264
+ server.stderr.on('data', (data) => {
265
+ logDebug(`[stderr] ${data.toString().trim()}`);
266
+ });
267
+
268
+ server.on('error', (error) => {
269
+ logError(`Failed to start server: ${error.message}`);
270
+ process.exit(1);
271
+ });
272
+
273
+ // Wait a bit for server to start
274
+ await new Promise(resolve => setTimeout(resolve, 500));
275
+
276
+ let allTestsPassed = true;
277
+
278
+ try {
279
+ // Test 1: Initialize
280
+ const initSuccess = await testInitialize(server);
281
+ if (!initSuccess) {
282
+ allTestsPassed = false;
283
+ log('\n❌ Initialization test failed', colors.red);
284
+ }
285
+
286
+ // Test 2: Git discovery
287
+ if (initSuccess) {
288
+ const discoverySuccess = await testGitDiscovery(server, gitRemote);
289
+ if (!discoverySuccess) {
290
+ allTestsPassed = false;
291
+ log('\n❌ Git discovery test failed', colors.red);
292
+ }
293
+ }
294
+
295
+ // Summary
296
+ log('\n' + '='.repeat(60), colors.blue);
297
+ if (allTestsPassed) {
298
+ log('✓ All tests passed!', colors.green);
299
+ log('✓ Server successfully discovered Git repository from roots', colors.green);
300
+ log('='.repeat(60), colors.blue);
301
+ server.kill();
302
+ process.exit(0);
303
+ } else {
304
+ log('✗ Some tests failed', colors.red);
305
+ log('='.repeat(60), colors.blue);
306
+ server.kill();
307
+ process.exit(1);
308
+ }
309
+ } catch (error) {
310
+ logError(`Test execution failed: ${error.message}`);
311
+ console.error(error);
312
+ server.kill();
313
+ process.exit(1);
314
+ }
315
+ }
316
+
317
+ // Run tests
318
+ runTests().catch((error) => {
319
+ logError(`Fatal error: ${error.message}`);
320
+ console.error(error);
321
+ process.exit(1);
322
+ });
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test script for multi-repository filtering with environment variables
5
+ *
6
+ * This script tests the INCLUDE_REPOSITORY_URLS and EXCLUDE_REPOSITORY_URLS
7
+ * environment variable functionality.
8
+ */
9
+
10
+ import { fileURLToPath } from 'url';
11
+ import { dirname, join } from 'path';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+
16
+ // Colors for terminal output
17
+ const colors = {
18
+ reset: '\x1b[0m',
19
+ green: '\x1b[32m',
20
+ red: '\x1b[31m',
21
+ yellow: '\x1b[33m',
22
+ blue: '\x1b[34m',
23
+ gray: '\x1b[90m',
24
+ cyan: '\x1b[36m',
25
+ };
26
+
27
+ function log(message, color = colors.reset) {
28
+ console.log(`${color}${message}${colors.reset}`);
29
+ }
30
+
31
+ function logSuccess(message) {
32
+ log(`✓ ${message}`, colors.green);
33
+ }
34
+
35
+ function logInfo(message) {
36
+ log(`ℹ ${message}`, colors.blue);
37
+ }
38
+
39
+ function logSection(message) {
40
+ log(`\n${'='.repeat(60)}`, colors.cyan);
41
+ log(message, colors.cyan);
42
+ log('='.repeat(60), colors.cyan);
43
+ }
44
+
45
+ /**
46
+ * Main test runner
47
+ */
48
+ async function runTests() {
49
+ log('='.repeat(60), colors.blue);
50
+ log('Multi-Repository Filter Testing', colors.blue);
51
+ log('='.repeat(60), colors.blue);
52
+
53
+ logInfo('This test demonstrates the multi-repository search functionality');
54
+ logInfo('with INCLUDE_REPOSITORY_URLS and EXCLUDE_REPOSITORY_URLS environment variables\n');
55
+
56
+ // Test scenarios
57
+ const scenarios = [
58
+ {
59
+ name: 'No filters (search all discovered repositories)',
60
+ env: {},
61
+ description: 'When no filter env vars are set, all discovered repositories are searched',
62
+ },
63
+ {
64
+ name: 'Include additions (add specific repositories to search)',
65
+ env: {
66
+ INCLUDE_REPOSITORY_URLS: 'https://github.com/owner/repo1.git,https://github.com/owner/repo2.git'
67
+ },
68
+ description: 'Discovered repositories plus the ones in INCLUDE_REPOSITORY_URLS are searched',
69
+ },
70
+ {
71
+ name: 'Exclude filter (skip specified repositories)',
72
+ env: {
73
+ EXCLUDE_REPOSITORY_URLS: 'https://github.com/owner/large-repo.git'
74
+ },
75
+ description: 'All repositories except those in EXCLUDE_REPOSITORY_URLS are searched',
76
+ },
77
+ {
78
+ name: 'Both filters (include then exclude)',
79
+ env: {
80
+ INCLUDE_REPOSITORY_URLS: 'https://github.com/owner/repo1.git,https://github.com/owner/repo2.git,https://github.com/owner/repo3.git',
81
+ EXCLUDE_REPOSITORY_URLS: 'https://github.com/owner/repo3.git'
82
+ },
83
+ description: 'Repositories from INCLUDE_REPOSITORY_URLS are added, then anything in EXCLUDE_REPOSITORY_URLS is removed',
84
+ },
85
+ ];
86
+
87
+ scenarios.forEach((scenario, index) => {
88
+ logSection(`Scenario ${index + 1}: ${scenario.name}`);
89
+ logInfo(scenario.description);
90
+
91
+ if (Object.keys(scenario.env).length === 0) {
92
+ log('\n No environment variables set', colors.gray);
93
+ } else {
94
+ log('\n Environment variables:', colors.gray);
95
+ Object.entries(scenario.env).forEach(([key, value]) => {
96
+ log(` ${key}=${value}`, colors.gray);
97
+ });
98
+ }
99
+
100
+ log('\n To test this scenario, run:', colors.yellow);
101
+ const envVars = Object.entries(scenario.env)
102
+ .map(([key, value]) => `${key}="${value}"`)
103
+ .join(' ');
104
+ const command = envVars
105
+ ? ` ${envVars} node dist/index.js`
106
+ : ` node dist/index.js`;
107
+ log(command, colors.yellow);
108
+ });
109
+
110
+ logSection('Implementation Details');
111
+
112
+ logInfo('How it works:');
113
+ log(' 1. Server discovers all Git repositories from workspace roots', colors.gray);
114
+ log(' 2. Before each search, repositories are adjusted based on env vars:', colors.gray);
115
+ log(' - If INCLUDE_REPOSITORY_URLS is set: those repos are added to the list', colors.gray);
116
+ log(' - If EXCLUDE_REPOSITORY_URLS is set: those repos are removed', colors.gray);
117
+ log(' 3. If multiple repos remain after filtering: multi-repo search', colors.gray);
118
+ log(' 4. If only one repo remains: single-repo search (cleaner output)', colors.gray);
119
+ log(' 5. If no repos remain: error message', colors.gray);
120
+
121
+ logSection('Configuration Format');
122
+
123
+ log(' INCLUDE_REPOSITORY_URLS: Comma-separated list of Git URLs to include', colors.gray);
124
+ log(' Example: export INCLUDE_REPOSITORY_URLS="https://github.com/owner/repo1.git,https://github.com/owner/repo2.git"', colors.gray);
125
+
126
+ log('\n EXCLUDE_REPOSITORY_URLS: Comma-separated list of Git URLs to exclude', colors.gray);
127
+ log(' Example: export EXCLUDE_REPOSITORY_URLS="https://github.com/owner/large-repo.git"', colors.gray);
128
+
129
+ logSection('Backward Compatibility');
130
+
131
+ log(' ✓ Existing single-repository setups continue to work', colors.green);
132
+ log(' ✓ REPOSITORY_GIT_REMOTE_URL env var still supported as fallback', colors.green);
133
+ log(' ✓ No breaking changes to existing tool parameters', colors.green);
134
+
135
+ logSection('Summary');
136
+
137
+ logSuccess('Multi-repository search is now implemented!');
138
+ log(' • By default: searches all discovered repositories', colors.gray);
139
+ log(' • With INCLUDE_REPOSITORY_URLS: searches discovered repos plus specified URLs', colors.gray);
140
+ log(' • With EXCLUDE_REPOSITORY_URLS: searches all except specified repos', colors.gray);
141
+ log(' • Results are aggregated with clear repository labels', colors.gray);
142
+ log(' • Parallel search execution for better performance', colors.gray);
143
+
144
+ log('\n');
145
+ }
146
+
147
+ // Run tests
148
+ runTests().catch((error) => {
149
+ console.error('Fatal error:', error);
150
+ process.exit(1);
151
+ });