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
package/test-roots.mjs ADDED
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test script for MCP roots/list functionality
5
+ *
6
+ * This script spawns the MCP server and tests the roots/list endpoint
7
+ * by sending JSON-RPC requests via stdio.
8
+ */
9
+
10
+ import { spawn } from 'child_process';
11
+ import { fileURLToPath } from 'url';
12
+ import { dirname, join } from 'path';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+
17
+ // Configuration
18
+ const SERVER_PATH = join(__dirname, 'dist', 'index.js');
19
+ const REPOSITORY_URL = process.env.REPOSITORY_GIT_REMOTE_URL || 'https://github.com/jetbrains/embark-mcp.git';
20
+
21
+ // Colors for terminal output
22
+ const colors = {
23
+ reset: '\x1b[0m',
24
+ green: '\x1b[32m',
25
+ red: '\x1b[31m',
26
+ yellow: '\x1b[33m',
27
+ blue: '\x1b[34m',
28
+ gray: '\x1b[90m',
29
+ };
30
+
31
+ function log(message, color = colors.reset) {
32
+ console.log(`${color}${message}${colors.reset}`);
33
+ }
34
+
35
+ function logSuccess(message) {
36
+ log(`✓ ${message}`, colors.green);
37
+ }
38
+
39
+ function logError(message) {
40
+ log(`✗ ${message}`, colors.red);
41
+ }
42
+
43
+ function logInfo(message) {
44
+ log(`ℹ ${message}`, colors.blue);
45
+ }
46
+
47
+ function logDebug(message) {
48
+ log(` ${message}`, colors.gray);
49
+ }
50
+
51
+ /**
52
+ * Send a JSON-RPC request to the server
53
+ */
54
+ function sendRequest(server, request) {
55
+ return new Promise((resolve, reject) => {
56
+ const requestStr = JSON.stringify(request) + '\n';
57
+ logDebug(`→ ${requestStr.trim()}`);
58
+
59
+ let responseBuffer = '';
60
+ let resolved = false;
61
+
62
+ const onData = (data) => {
63
+ responseBuffer += data.toString();
64
+
65
+ // Try to parse complete JSON objects
66
+ const lines = responseBuffer.split('\n');
67
+ responseBuffer = lines.pop(); // Keep incomplete line in buffer
68
+
69
+ for (const line of lines) {
70
+ if (line.trim()) {
71
+ try {
72
+ const response = JSON.parse(line);
73
+ logDebug(`← ${line}`);
74
+
75
+ // Check if this is the response to our request
76
+ if (response.id === request.id) {
77
+ resolved = true;
78
+ server.stdout.off('data', onData);
79
+ resolve(response);
80
+ }
81
+ } catch (e) {
82
+ // Not valid JSON, continue accumulating
83
+ }
84
+ }
85
+ }
86
+ };
87
+
88
+ server.stdout.on('data', onData);
89
+
90
+ // Timeout after 5 seconds
91
+ setTimeout(() => {
92
+ if (!resolved) {
93
+ server.stdout.off('data', onData);
94
+ reject(new Error('Request timeout'));
95
+ }
96
+ }, 5000);
97
+
98
+ server.stdin.write(requestStr);
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Test the roots/list endpoint
104
+ */
105
+ async function testRootsList(server) {
106
+ log('\n--- Testing roots/list ---', colors.yellow);
107
+
108
+ const request = {
109
+ jsonrpc: '2.0',
110
+ id: 2,
111
+ method: 'roots/list',
112
+ };
113
+
114
+ try {
115
+ const response = await sendRequest(server, request);
116
+
117
+ if (response.error) {
118
+ logError(`Server returned error: ${JSON.stringify(response.error)}`);
119
+ return false;
120
+ }
121
+
122
+ if (!response.result) {
123
+ logError('Response missing result field');
124
+ return false;
125
+ }
126
+
127
+ const { roots } = response.result;
128
+
129
+ if (!Array.isArray(roots)) {
130
+ logError('roots field is not an array');
131
+ return false;
132
+ }
133
+
134
+ logSuccess('roots/list returned valid response');
135
+ logInfo(`Found ${roots.length} root(s)`);
136
+
137
+ if (roots.length === 0) {
138
+ log(' No roots configured (this is valid if REPOSITORY_GIT_REMOTE_URL is not set)', colors.yellow);
139
+ return true;
140
+ }
141
+
142
+ // Validate each root
143
+ let allValid = true;
144
+ for (const [index, root] of roots.entries()) {
145
+ logInfo(`Root ${index + 1}:`);
146
+
147
+ if (!root.uri) {
148
+ logError(` Missing uri field`);
149
+ allValid = false;
150
+ continue;
151
+ }
152
+
153
+ logSuccess(` uri: ${root.uri}`);
154
+
155
+ if (root.name) {
156
+ logInfo(` name: ${root.name}`);
157
+ }
158
+
159
+ // Validate URI format (should start with embark:// for this server)
160
+ if (!root.uri.startsWith('embark://')) {
161
+ log(` Warning: URI doesn't start with embark:// (got: ${root.uri})`, colors.yellow);
162
+ }
163
+ }
164
+
165
+ return allValid;
166
+ } catch (error) {
167
+ logError(`Failed to test roots/list: ${error.message}`);
168
+ return false;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Test server initialization
174
+ */
175
+ async function testInitialize(server) {
176
+ log('\n--- Testing initialization ---', colors.yellow);
177
+
178
+ const request = {
179
+ jsonrpc: '2.0',
180
+ id: 1,
181
+ method: 'initialize',
182
+ params: {
183
+ protocolVersion: '2024-11-05',
184
+ capabilities: {
185
+ roots: {
186
+ listChanged: true,
187
+ },
188
+ },
189
+ clientInfo: {
190
+ name: 'test-client',
191
+ version: '1.0.0',
192
+ },
193
+ },
194
+ };
195
+
196
+ try {
197
+ const response = await sendRequest(server, request);
198
+
199
+ if (response.error) {
200
+ logError(`Initialization error: ${JSON.stringify(response.error)}`);
201
+ return false;
202
+ }
203
+
204
+ if (!response.result) {
205
+ logError('Initialization response missing result');
206
+ return false;
207
+ }
208
+
209
+ logSuccess('Server initialized successfully');
210
+
211
+ // Check if server advertises roots capability
212
+ if (response.result.capabilities?.roots) {
213
+ logSuccess('Server advertises roots capability');
214
+ logDebug(` ${JSON.stringify(response.result.capabilities.roots)}`);
215
+ } else {
216
+ logError('Server does not advertise roots capability');
217
+ return false;
218
+ }
219
+
220
+ return true;
221
+ } catch (error) {
222
+ logError(`Failed to initialize: ${error.message}`);
223
+ return false;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Main test runner
229
+ */
230
+ async function runTests() {
231
+ log('='.repeat(60), colors.blue);
232
+ log('MCP Server Roots Testing', colors.blue);
233
+ log('='.repeat(60), colors.blue);
234
+
235
+ logInfo(`Server path: ${SERVER_PATH}`);
236
+ logInfo(`Test repository: ${REPOSITORY_URL}`);
237
+
238
+ // Spawn the server
239
+ log('\n--- Starting MCP server ---', colors.yellow);
240
+ const server = spawn('node', [SERVER_PATH], {
241
+ env: {
242
+ ...process.env,
243
+ REPOSITORY_GIT_REMOTE_URL: REPOSITORY_URL,
244
+ },
245
+ stdio: ['pipe', 'pipe', 'pipe'],
246
+ });
247
+
248
+ // Log stderr for debugging
249
+ server.stderr.on('data', (data) => {
250
+ logDebug(`[stderr] ${data.toString().trim()}`);
251
+ });
252
+
253
+ server.on('error', (error) => {
254
+ logError(`Failed to start server: ${error.message}`);
255
+ process.exit(1);
256
+ });
257
+
258
+ // Wait a bit for server to start
259
+ await new Promise(resolve => setTimeout(resolve, 500));
260
+
261
+ let allTestsPassed = true;
262
+
263
+ try {
264
+ // Test 1: Initialize
265
+ const initSuccess = await testInitialize(server);
266
+ if (!initSuccess) {
267
+ allTestsPassed = false;
268
+ log('\n❌ Initialization test failed', colors.red);
269
+ }
270
+
271
+ // Test 2: Roots list
272
+ if (initSuccess) {
273
+ const rootsSuccess = await testRootsList(server);
274
+ if (!rootsSuccess) {
275
+ allTestsPassed = false;
276
+ log('\n❌ Roots test failed', colors.red);
277
+ }
278
+ }
279
+
280
+ // Summary
281
+ log('\n' + '='.repeat(60), colors.blue);
282
+ if (allTestsPassed) {
283
+ log('✓ All tests passed!', colors.green);
284
+ log('='.repeat(60), colors.blue);
285
+ server.kill();
286
+ process.exit(0);
287
+ } else {
288
+ log('✗ Some tests failed', colors.red);
289
+ log('='.repeat(60), colors.blue);
290
+ server.kill();
291
+ process.exit(1);
292
+ }
293
+ } catch (error) {
294
+ logError(`Test execution failed: ${error.message}`);
295
+ console.error(error);
296
+ server.kill();
297
+ process.exit(1);
298
+ }
299
+ }
300
+
301
+ // Run tests
302
+ runTests().catch((error) => {
303
+ logError(`Fatal error: ${error.message}`);
304
+ console.error(error);
305
+ process.exit(1);
306
+ });
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test script for snippet extraction functionality
5
+ */
6
+
7
+ import { fileURLToPath } from 'url';
8
+ import { dirname, join } from 'path';
9
+ import { extractSnippetFromGit } from './dist/git-utils.js';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+
14
+ // Colors for terminal output
15
+ const colors = {
16
+ reset: '\x1b[0m',
17
+ green: '\x1b[32m',
18
+ red: '\x1b[31m',
19
+ yellow: '\x1b[33m',
20
+ blue: '\x1b[34m',
21
+ gray: '\x1b[90m',
22
+ };
23
+
24
+ function log(message, color = colors.reset) {
25
+ console.log(`${color}${message}${colors.reset}`);
26
+ }
27
+
28
+ function logSuccess(message) {
29
+ log(`✓ ${message}`, colors.green);
30
+ }
31
+
32
+ function logError(message) {
33
+ log(`✗ ${message}`, colors.red);
34
+ }
35
+
36
+ function logInfo(message) {
37
+ log(`ℹ ${message}`, colors.blue);
38
+ }
39
+
40
+ /**
41
+ * Test snippet extraction from this repository
42
+ */
43
+ async function testSnippetExtraction() {
44
+ log('='.repeat(60), colors.blue);
45
+ log('Testing Snippet Extraction', colors.blue);
46
+ log('='.repeat(60), colors.blue);
47
+
48
+ const repoPath = __dirname;
49
+ const testCases = [
50
+ {
51
+ name: 'Extract from git-utils.ts',
52
+ relativePath: 'src/git-utils.ts',
53
+ revision: 'HEAD',
54
+ // Extract a reasonable portion from the middle of the file
55
+ startOffset: 1500,
56
+ endOffset: 1700,
57
+ description: 'Extract 200 bytes from git-utils.ts'
58
+ },
59
+ {
60
+ name: 'Extract from package.json',
61
+ relativePath: 'package.json',
62
+ revision: null, // Will use HEAD
63
+ startOffset: 0,
64
+ endOffset: 100,
65
+ description: 'Extract first 100 bytes of package.json'
66
+ },
67
+ {
68
+ name: 'Extract beginning of git-utils.ts',
69
+ relativePath: 'src/git-utils.ts',
70
+ revision: 'HEAD',
71
+ startOffset: 0,
72
+ endOffset: 150,
73
+ description: 'Extract file header'
74
+ }
75
+ ];
76
+
77
+ let allTestsPassed = true;
78
+
79
+ for (const testCase of testCases) {
80
+ log(`\n--- ${testCase.name} ---`, colors.yellow);
81
+ logInfo(testCase.description);
82
+ logInfo(`File: ${testCase.relativePath}`);
83
+ logInfo(`Offsets: ${testCase.startOffset}-${testCase.endOffset}`);
84
+ logInfo(`Revision: ${testCase.revision || 'HEAD'}`);
85
+
86
+ try {
87
+ const snippet = extractSnippetFromGit(
88
+ repoPath,
89
+ testCase.relativePath,
90
+ testCase.revision,
91
+ testCase.startOffset,
92
+ testCase.endOffset
93
+ );
94
+
95
+ if (snippet === null) {
96
+ logError('Failed to extract snippet (returned null)');
97
+ allTestsPassed = false;
98
+ continue;
99
+ }
100
+
101
+ if (snippet.length === 0) {
102
+ logError('Extracted snippet is empty');
103
+ allTestsPassed = false;
104
+ continue;
105
+ }
106
+
107
+ logSuccess(`Successfully extracted ${snippet.length} bytes`);
108
+ log('\nSnippet preview:', colors.gray);
109
+ log('---', colors.gray);
110
+ log(snippet.slice(0, 200) + (snippet.length > 200 ? '...' : ''), colors.gray);
111
+ log('---', colors.gray);
112
+ } catch (error) {
113
+ logError(`Test failed with error: ${error.message}`);
114
+ allTestsPassed = false;
115
+ }
116
+ }
117
+
118
+ // Summary
119
+ log('\n' + '='.repeat(60), colors.blue);
120
+ if (allTestsPassed) {
121
+ log('✓ All tests passed!', colors.green);
122
+ log('='.repeat(60), colors.blue);
123
+ process.exit(0);
124
+ } else {
125
+ log('✗ Some tests failed', colors.red);
126
+ log('='.repeat(60), colors.blue);
127
+ process.exit(1);
128
+ }
129
+ }
130
+
131
+ // Run tests
132
+ testSnippetExtraction().catch((error) => {
133
+ logError(`Fatal error: ${error.message}`);
134
+ console.error(error);
135
+ process.exit(1);
136
+ });
package/watch-logs.sh ADDED
@@ -0,0 +1,78 @@
1
+ #!/bin/bash
2
+
3
+ # Watch logs script for Embark MCP Server
4
+ # This script helps you monitor the server logs in real-time during Claude Code integration testing
5
+
6
+ LOG_FILE="$HOME/.embark/debug.log"
7
+
8
+ # Colors
9
+ GREEN='\033[0;32m'
10
+ BLUE='\033[0;34m'
11
+ YELLOW='\033[1;33m'
12
+ RED='\033[0;31m'
13
+ NC='\033[0m' # No Color
14
+
15
+ echo -e "${BLUE}============================================================${NC}"
16
+ echo -e "${BLUE}Embark MCP Server Log Watcher${NC}"
17
+ echo -e "${BLUE}============================================================${NC}"
18
+ echo ""
19
+ echo -e "${YELLOW}Log file:${NC} $LOG_FILE"
20
+ echo ""
21
+
22
+ # Check if log file exists
23
+ if [ ! -f "$LOG_FILE" ]; then
24
+ echo -e "${RED}⚠ Log file does not exist yet.${NC}"
25
+ echo -e "${YELLOW}ℹ Make sure ENABLE_LOCAL_LOGS=true is set in your .mcp.json${NC}"
26
+ echo ""
27
+ echo -e "Example .mcp.json configuration:"
28
+ echo -e "${BLUE}"
29
+ cat << 'EOF'
30
+ {
31
+ "mcpServers": {
32
+ "embark-mcp": {
33
+ "command": "node",
34
+ "args": ["/path/to/embark-remote-mcp/dist/index.js"],
35
+ "env": {
36
+ "REPOSITORY_GIT_REMOTE_URL": "https://github.com/your-org/your-repo.git",
37
+ "ENABLE_LOCAL_LOGS": "true"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ EOF
43
+ echo -e "${NC}"
44
+ echo ""
45
+ echo -e "Waiting for log file to be created..."
46
+ echo -e "${YELLOW}(Restart Claude Code to create the log file)${NC}"
47
+ echo ""
48
+
49
+ # Wait for file to be created
50
+ while [ ! -f "$LOG_FILE" ]; do
51
+ sleep 1
52
+ done
53
+
54
+ echo -e "${GREEN}✓ Log file created!${NC}"
55
+ echo ""
56
+ fi
57
+
58
+ echo -e "${GREEN}✓ Watching logs...${NC}"
59
+ echo -e "${YELLOW}ℹ Press Ctrl+C to stop${NC}"
60
+ echo ""
61
+ echo -e "${BLUE}------------------------------------------------------------${NC}"
62
+ echo ""
63
+
64
+ # Filter and colorize logs
65
+ tail -f "$LOG_FILE" | while IFS= read -r line; do
66
+ # Check for specific patterns and colorize
67
+ if echo "$line" | grep -q "ListRoots"; then
68
+ echo -e "${GREEN}$line${NC}"
69
+ elif echo "$line" | grep -q '"level": "error"'; then
70
+ echo -e "${RED}$line${NC}"
71
+ elif echo "$line" | grep -q '"level": "warn"'; then
72
+ echo -e "${YELLOW}$line${NC}"
73
+ elif echo "$line" | grep -q "root"; then
74
+ echo -e "${BLUE}$line${NC}"
75
+ else
76
+ echo "$line"
77
+ fi
78
+ done