@hypnosis/docker-mcp-server 1.0.3 → 1.2.1

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 (79) hide show
  1. package/README.md +95 -22
  2. package/dist/adapters/redis.d.ts.map +1 -1
  3. package/dist/adapters/redis.js +18 -6
  4. package/dist/adapters/redis.js.map +1 -1
  5. package/dist/discovery/compose-parser.d.ts +4 -0
  6. package/dist/discovery/compose-parser.d.ts.map +1 -1
  7. package/dist/discovery/compose-parser.js +25 -0
  8. package/dist/discovery/compose-parser.js.map +1 -1
  9. package/dist/discovery/project-discovery.d.ts.map +1 -1
  10. package/dist/discovery/project-discovery.js +24 -0
  11. package/dist/discovery/project-discovery.js.map +1 -1
  12. package/dist/discovery/remote-discovery.d.ts +99 -0
  13. package/dist/discovery/remote-discovery.d.ts.map +1 -0
  14. package/dist/discovery/remote-discovery.js +410 -0
  15. package/dist/discovery/remote-discovery.js.map +1 -0
  16. package/dist/discovery/types.d.ts +4 -0
  17. package/dist/discovery/types.d.ts.map +1 -1
  18. package/dist/index.js +87 -14
  19. package/dist/index.js.map +1 -1
  20. package/dist/managers/compose-manager.d.ts +3 -1
  21. package/dist/managers/compose-manager.d.ts.map +1 -1
  22. package/dist/managers/compose-manager.js +10 -1
  23. package/dist/managers/compose-manager.js.map +1 -1
  24. package/dist/managers/container-manager.d.ts +53 -1
  25. package/dist/managers/container-manager.d.ts.map +1 -1
  26. package/dist/managers/container-manager.js +175 -71
  27. package/dist/managers/container-manager.js.map +1 -1
  28. package/dist/tools/container-tools.d.ts +9 -1
  29. package/dist/tools/container-tools.d.ts.map +1 -1
  30. package/dist/tools/container-tools.js +231 -14
  31. package/dist/tools/container-tools.js.map +1 -1
  32. package/dist/tools/database-tools.d.ts.map +1 -1
  33. package/dist/tools/database-tools.js +36 -4
  34. package/dist/tools/database-tools.js.map +1 -1
  35. package/dist/tools/discovery-tools.d.ts +29 -0
  36. package/dist/tools/discovery-tools.d.ts.map +1 -0
  37. package/dist/tools/discovery-tools.js +173 -0
  38. package/dist/tools/discovery-tools.js.map +1 -0
  39. package/dist/tools/env-tools.d.ts +5 -0
  40. package/dist/tools/env-tools.d.ts.map +1 -1
  41. package/dist/tools/env-tools.js +158 -15
  42. package/dist/tools/env-tools.js.map +1 -1
  43. package/dist/tools/executor-tool.d.ts +5 -0
  44. package/dist/tools/executor-tool.d.ts.map +1 -1
  45. package/dist/tools/executor-tool.js +60 -5
  46. package/dist/tools/executor-tool.js.map +1 -1
  47. package/dist/tools/mcp-health-tool.d.ts +11 -0
  48. package/dist/tools/mcp-health-tool.d.ts.map +1 -1
  49. package/dist/tools/mcp-health-tool.js +25 -4
  50. package/dist/tools/mcp-health-tool.js.map +1 -1
  51. package/dist/tools/profile-tool.d.ts +46 -0
  52. package/dist/tools/profile-tool.d.ts.map +1 -0
  53. package/dist/tools/profile-tool.js +91 -0
  54. package/dist/tools/profile-tool.js.map +1 -0
  55. package/dist/utils/compose-exec.d.ts +28 -3
  56. package/dist/utils/compose-exec.d.ts.map +1 -1
  57. package/dist/utils/compose-exec.js +100 -26
  58. package/dist/utils/compose-exec.js.map +1 -1
  59. package/dist/utils/docker-client.d.ts +73 -8
  60. package/dist/utils/docker-client.d.ts.map +1 -1
  61. package/dist/utils/docker-client.js +492 -16
  62. package/dist/utils/docker-client.js.map +1 -1
  63. package/dist/utils/profiles-file.d.ts +57 -0
  64. package/dist/utils/profiles-file.d.ts.map +1 -0
  65. package/dist/utils/profiles-file.js +167 -0
  66. package/dist/utils/profiles-file.js.map +1 -0
  67. package/dist/utils/retry.d.ts +49 -0
  68. package/dist/utils/retry.d.ts.map +1 -0
  69. package/dist/utils/retry.js +120 -0
  70. package/dist/utils/retry.js.map +1 -0
  71. package/dist/utils/ssh-config.d.ts +104 -0
  72. package/dist/utils/ssh-config.d.ts.map +1 -0
  73. package/dist/utils/ssh-config.js +346 -0
  74. package/dist/utils/ssh-config.js.map +1 -0
  75. package/dist/utils/ssh-exec.d.ts +59 -0
  76. package/dist/utils/ssh-exec.d.ts.map +1 -0
  77. package/dist/utils/ssh-exec.js +156 -0
  78. package/dist/utils/ssh-exec.js.map +1 -0
  79. package/package.json +21 -3
@@ -1,45 +1,369 @@
1
1
  /**
2
2
  * Docker Client Wrapper
3
- * Обёртка над Dockerode для централизованного управления
3
+ * Centralized Docker API management with SSH tunnel support
4
4
  */
5
5
  import Docker from 'dockerode';
6
+ import { existsSync, unlinkSync } from 'fs';
7
+ import { resolve, join } from 'path';
8
+ import { tmpdir } from 'os';
9
+ import { spawn } from 'child_process';
6
10
  import { logger } from './logger.js';
11
+ import { retryWithTimeout, createNetworkRetryPredicate } from './retry.js';
12
+ import { loadProfilesFile, profileDataToSSHConfig } from './profiles-file.js';
7
13
  /**
8
- * Wrapper над Dockerode для централизованного управления
14
+ * Dockerode wrapper for centralized Docker API management
9
15
  */
10
16
  export class DockerClient {
11
17
  docker;
12
- constructor() {
13
- this.docker = new Docker();
14
- logger.debug('Dockerode client initialized');
18
+ sshConfig;
19
+ isRemote;
20
+ activeSocketPath = null;
21
+ sshProcessPid = null;
22
+ tunnelCreationLock = null;
23
+ tunnelHealthCheckInterval = null;
24
+ constructor(sshConfig) {
25
+ this.sshConfig = sshConfig || null;
26
+ this.isRemote = !!this.sshConfig;
27
+ if (this.sshConfig) {
28
+ // For SSH, create temporary Docker client, tunnel will be created on first use
29
+ // Use local socket by default, will be replaced after tunnel creation
30
+ this.docker = new Docker();
31
+ logger.info(`Dockerode client initialized with SSH config (${this.sshConfig.host}:${this.sshConfig.port || 22})`);
32
+ }
33
+ else {
34
+ // Local Docker client
35
+ this.docker = new Docker();
36
+ logger.debug('Dockerode client initialized (local)');
37
+ }
38
+ }
39
+ /**
40
+ * Cleanup SSH tunnel (called on shutdown)
41
+ */
42
+ cleanup() {
43
+ // Stop healthcheck interval
44
+ if (this.tunnelHealthCheckInterval) {
45
+ clearInterval(this.tunnelHealthCheckInterval);
46
+ this.tunnelHealthCheckInterval = null;
47
+ }
48
+ if (!this.isRemote || !this.activeSocketPath) {
49
+ return;
50
+ }
51
+ logger.info('Cleaning up SSH tunnel...');
52
+ // Remove socket file
53
+ try {
54
+ if (existsSync(this.activeSocketPath)) {
55
+ unlinkSync(this.activeSocketPath);
56
+ logger.debug(`Removed SSH socket: ${this.activeSocketPath}`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ logger.warn(`Failed to remove SSH socket: ${error.message}`);
61
+ }
62
+ // Kill SSH process if we have PID
63
+ if (this.sshProcessPid) {
64
+ try {
65
+ process.kill(this.sshProcessPid, 'SIGTERM');
66
+ logger.debug(`Killed SSH process: ${this.sshProcessPid}`);
67
+ }
68
+ catch (error) {
69
+ // Process might already be dead
70
+ logger.debug(`SSH process already terminated: ${this.sshProcessPid}`);
71
+ }
72
+ }
73
+ this.activeSocketPath = null;
74
+ this.sshProcessPid = null;
75
+ }
76
+ /**
77
+ * Ensure SSH tunnel is created and recreate Docker client with correct socket
78
+ * With mutex to prevent race conditions
79
+ */
80
+ async ensureSSHTunnel() {
81
+ if (!this.sshConfig) {
82
+ return;
83
+ }
84
+ // If tunnel creation is already in progress, wait for it
85
+ if (this.tunnelCreationLock) {
86
+ logger.debug('Tunnel creation already in progress, waiting...');
87
+ await this.tunnelCreationLock;
88
+ return;
89
+ }
90
+ logger.info(`Ensuring SSH tunnel is created for ${this.sshConfig.host}:${this.sshConfig.port || 22}`);
91
+ // Create lock and start tunnel creation
92
+ this.tunnelCreationLock = (async () => {
93
+ try {
94
+ const socketPath = await this.createSSHTunnel(this.sshConfig);
95
+ // Store active socket path for cleanup
96
+ this.activeSocketPath = socketPath;
97
+ // Recreate Docker client with correct socket
98
+ this.docker = new Docker({
99
+ socketPath: socketPath,
100
+ });
101
+ logger.info(`Docker client updated with SSH tunnel socket: ${socketPath}`);
102
+ // Start periodic healthcheck for tunnel
103
+ this.startTunnelHealthCheck();
104
+ return socketPath;
105
+ }
106
+ catch (error) {
107
+ logger.error(`Failed to ensure SSH tunnel: ${error.message}`);
108
+ throw error;
109
+ }
110
+ finally {
111
+ // Release lock
112
+ this.tunnelCreationLock = null;
113
+ }
114
+ })();
115
+ await this.tunnelCreationLock;
116
+ }
117
+ /**
118
+ * Start periodic healthcheck for SSH tunnel
119
+ */
120
+ startTunnelHealthCheck() {
121
+ // Clear existing interval if any
122
+ if (this.tunnelHealthCheckInterval) {
123
+ clearInterval(this.tunnelHealthCheckInterval);
124
+ }
125
+ // Check tunnel every 60 seconds
126
+ this.tunnelHealthCheckInterval = setInterval(async () => {
127
+ if (!this.activeSocketPath || !this.isRemote) {
128
+ return;
129
+ }
130
+ try {
131
+ // Quick ping to check if Docker is reachable
132
+ await this.docker.ping();
133
+ logger.debug('SSH tunnel healthcheck: OK');
134
+ }
135
+ catch (error) {
136
+ logger.warn(`SSH tunnel healthcheck failed: ${error.message}`);
137
+ logger.info('Attempting to recreate SSH tunnel...');
138
+ // Try to recreate tunnel
139
+ try {
140
+ await this.ensureSSHTunnel();
141
+ logger.info('SSH tunnel recreated successfully');
142
+ }
143
+ catch (recreateError) {
144
+ logger.error(`Failed to recreate SSH tunnel: ${recreateError.message}`);
145
+ }
146
+ }
147
+ }, 60000); // 60 seconds
148
+ // Unref the interval so it doesn't keep the process alive
149
+ this.tunnelHealthCheckInterval.unref();
150
+ logger.debug('SSH tunnel healthcheck started (60s interval)');
151
+ }
152
+ /**
153
+ * Create SSH tunnel to remote Docker socket
154
+ * @returns Path to local socket file
155
+ */
156
+ async createSSHTunnel(config) {
157
+ // Check platform support for Unix sockets
158
+ if (process.platform === 'win32') {
159
+ throw new Error('SSH tunneling with Unix sockets is not supported on Windows. Please use WSL2 or Docker Desktop.');
160
+ }
161
+ // Unique name for socket file
162
+ const socketPath = join(tmpdir(), `docker-ssh-${config.host}-${config.port || 22}.sock`);
163
+ // Check if tunnel is already running
164
+ if (existsSync(socketPath)) {
165
+ // Проверяем, работает ли туннель — пробуем подключиться
166
+ logger.debug(`SSH tunnel socket exists: ${socketPath}, checking if it's alive...`);
167
+ try {
168
+ // Try quick ping through existing socket
169
+ const testDocker = new Docker({ socketPath });
170
+ await testDocker.ping();
171
+ logger.debug(`SSH tunnel socket is alive: ${socketPath}`);
172
+ return socketPath;
173
+ }
174
+ catch {
175
+ // Socket file exists but tunnel is dead - remove and recreate
176
+ logger.warn(`SSH tunnel socket exists but is dead, recreating: ${socketPath}`);
177
+ try {
178
+ unlinkSync(socketPath);
179
+ }
180
+ catch {
181
+ // Ignore deletion error
182
+ }
183
+ }
184
+ }
185
+ // Check SSH key existence (if specified)
186
+ if (config.privateKeyPath) {
187
+ const keyPath = this.resolveKeyPath(config.privateKeyPath);
188
+ if (!existsSync(keyPath)) {
189
+ logger.warn(`SSH private key not found at: ${keyPath}. Make sure it's accessible via SSH agent or ~/.ssh/config`);
190
+ }
191
+ else {
192
+ logger.debug(`SSH key found at: ${keyPath}`);
193
+ }
194
+ }
195
+ // Build SSH command for tunnel creation
196
+ const sshArgs = [
197
+ '-N', // Don't execute commands, tunnel only
198
+ '-f', // Background mode
199
+ '-o', 'StrictHostKeyChecking=no',
200
+ '-o', 'UserKnownHostsFile=/dev/null',
201
+ '-o', 'ExitOnForwardFailure=yes',
202
+ '-o', 'ServerAliveInterval=60',
203
+ '-o', 'ServerAliveCountMax=3',
204
+ '-L', `${socketPath}:/var/run/docker.sock`, // Local socket -> remote socket
205
+ ];
206
+ // Add key if specified
207
+ if (config.privateKeyPath) {
208
+ const keyPath = this.resolveKeyPath(config.privateKeyPath);
209
+ sshArgs.push('-i', keyPath);
210
+ }
211
+ // Add port and host
212
+ if (config.port && config.port !== 22) {
213
+ sshArgs.push('-p', String(config.port));
214
+ }
215
+ sshArgs.push(`${config.username}@${config.host}`);
216
+ // Start SSH tunnel
217
+ logger.info(`Creating SSH tunnel: ${config.username}@${config.host}:${config.port || 22}`);
218
+ return new Promise((resolve, reject) => {
219
+ try {
220
+ logger.debug(`Executing SSH command: ssh ${sshArgs.join(' ')}`);
221
+ const sshProcess = spawn('ssh', sshArgs, {
222
+ stdio: ['ignore', 'pipe', 'pipe'],
223
+ detached: true,
224
+ });
225
+ // Store PID for cleanup
226
+ if (sshProcess.pid) {
227
+ this.sshProcessPid = sshProcess.pid;
228
+ logger.debug(`SSH process PID: ${this.sshProcessPid}`);
229
+ }
230
+ let stderrOutput = '';
231
+ let stdoutOutput = '';
232
+ sshProcess.stdout?.on('data', (data) => {
233
+ stdoutOutput += data.toString();
234
+ });
235
+ sshProcess.stderr?.on('data', (data) => {
236
+ stderrOutput += data.toString();
237
+ // Логируем stderr для отладки
238
+ logger.debug(`SSH stderr: ${data.toString().trim()}`);
239
+ });
240
+ sshProcess.on('error', (error) => {
241
+ logger.error(`SSH tunnel process error: ${error.message}`);
242
+ reject(new Error(`SSH tunnel failed: ${error.message}`));
243
+ });
244
+ // With -f flag, process exits immediately after starting in background
245
+ // Wait a bit and check socket
246
+ setTimeout(() => {
247
+ sshProcess.unref();
248
+ // Wait for socket creation
249
+ this.waitForSocket(socketPath, 10000) // Increase timeout to 10 seconds
250
+ .then(() => {
251
+ logger.info(`SSH tunnel socket created successfully: ${socketPath}`);
252
+ // Store socket path for cleanup
253
+ this.activeSocketPath = socketPath;
254
+ resolve(socketPath);
255
+ })
256
+ .catch((error) => {
257
+ logger.error(`SSH tunnel socket not created: ${error.message}`);
258
+ if (stderrOutput) {
259
+ logger.error(`SSH stderr output: ${stderrOutput}`);
260
+ }
261
+ if (stdoutOutput) {
262
+ logger.error(`SSH stdout output: ${stdoutOutput}`);
263
+ }
264
+ reject(new Error(`SSH tunnel socket not created: ${error.message}`));
265
+ });
266
+ }, 500); // Give 500ms for process startup
267
+ }
268
+ catch (error) {
269
+ logger.error(`Failed to start SSH tunnel: ${error.message}`);
270
+ reject(new Error(`SSH tunnel failed: ${error.message}`));
271
+ }
272
+ });
273
+ }
274
+ /**
275
+ * Wait for socket file creation
276
+ */
277
+ async waitForSocket(socketPath, timeout) {
278
+ const startTime = Date.now();
279
+ const checkInterval = 100; // Проверяем каждые 100ms
280
+ return new Promise((resolve, reject) => {
281
+ const checkSocket = setInterval(() => {
282
+ if (existsSync(socketPath)) {
283
+ clearInterval(checkSocket);
284
+ resolve();
285
+ }
286
+ else if (Date.now() - startTime > timeout) {
287
+ clearInterval(checkSocket);
288
+ reject(new Error(`Socket not created within ${timeout}ms`));
289
+ }
290
+ }, checkInterval);
291
+ });
292
+ }
293
+ /**
294
+ * Resolve SSH key path (support for ~)
295
+ */
296
+ resolveKeyPath(keyPath) {
297
+ if (keyPath.startsWith('~')) {
298
+ const home = process.env.HOME || process.env.USERPROFILE || '';
299
+ return keyPath.replace('~', home);
300
+ }
301
+ return resolve(keyPath);
15
302
  }
16
303
  /**
17
304
  * Проверка подключения к Docker
305
+ * С retry логикой для удаленных подключений
18
306
  */
19
307
  async ping() {
20
- try {
308
+ // Для удаленных подключений сначала создаем туннель
309
+ if (this.isRemote) {
310
+ await this.ensureSSHTunnel();
311
+ }
312
+ const pingFn = async () => {
21
313
  await this.docker.ping();
22
- logger.info('Docker connection verified');
314
+ logger.info(`Docker connection verified${this.isRemote ? ` (remote: ${this.sshConfig?.host})` : ' (local)'}`);
315
+ };
316
+ try {
317
+ // Для удаленных подключений используем retry
318
+ if (this.isRemote) {
319
+ await retryWithTimeout(pingFn, {
320
+ maxAttempts: 3,
321
+ timeout: 30000,
322
+ shouldRetry: createNetworkRetryPredicate(),
323
+ });
324
+ }
325
+ else {
326
+ await pingFn();
327
+ }
23
328
  }
24
329
  catch (error) {
330
+ const errorMessage = this.isRemote
331
+ ? `Failed to connect to remote Docker at ${this.sshConfig?.host}: ${error.message}`
332
+ : 'Docker is not running. Please start Docker Desktop and try again.';
25
333
  logger.error('Docker connection failed:', error);
26
- throw new Error('Docker is not running. Please start Docker Desktop and try again.');
334
+ throw new Error(errorMessage);
27
335
  }
28
336
  }
29
337
  /**
30
- * Получить native Dockerode instance
338
+ * Get native Dockerode instance
31
339
  */
32
340
  getClient() {
33
341
  return this.docker;
34
342
  }
35
343
  /**
36
- * Список контейнеров
344
+ * List containers
345
+ * With retry logic for remote connections
37
346
  */
38
347
  async listContainers(options) {
39
- return this.docker.listContainers(options);
348
+ // Для удаленных подключений сначала создаем туннель
349
+ if (this.isRemote) {
350
+ await this.ensureSSHTunnel();
351
+ }
352
+ const listFn = async () => {
353
+ return this.docker.listContainers(options);
354
+ };
355
+ // Для удаленных подключений используем retry
356
+ if (this.isRemote) {
357
+ return retryWithTimeout(listFn, {
358
+ maxAttempts: 3,
359
+ timeout: 30000,
360
+ shouldRetry: createNetworkRetryPredicate(),
361
+ });
362
+ }
363
+ return listFn();
40
364
  }
41
365
  /**
42
- * Получить контейнер по ID или имени
366
+ * Get container by ID or name
43
367
  */
44
368
  getContainer(id) {
45
369
  return this.docker.getContainer(id);
@@ -48,12 +372,164 @@ export class DockerClient {
48
372
  // Singleton instance
49
373
  let dockerClientInstance = null;
50
374
  /**
51
- * Получить singleton instance DockerClient
375
+ * Get singleton instance of DockerClient
376
+ * @param sshConfig - SSH configuration (optional, for remote Docker)
52
377
  */
53
- export function getDockerClient() {
54
- if (!dockerClientInstance) {
55
- dockerClientInstance = new DockerClient();
378
+ export function getDockerClient(sshConfig) {
379
+ // Если конфигурация изменилась, пересоздаем клиент
380
+ if (!dockerClientInstance || sshConfig !== undefined) {
381
+ // Cleanup old instance if exists
382
+ if (dockerClientInstance) {
383
+ dockerClientInstance.cleanup();
384
+ }
385
+ dockerClientInstance = new DockerClient(sshConfig);
56
386
  }
57
387
  return dockerClientInstance;
58
388
  }
389
+ /**
390
+ * Reset singleton instance (for testing)
391
+ */
392
+ export function resetDockerClient() {
393
+ if (dockerClientInstance) {
394
+ dockerClientInstance.cleanup();
395
+ }
396
+ dockerClientInstance = null;
397
+ }
398
+ /**
399
+ * Cleanup all Docker clients (for graceful shutdown)
400
+ */
401
+ export function cleanupDockerClient() {
402
+ if (dockerClientInstance) {
403
+ dockerClientInstance.cleanup();
404
+ }
405
+ }
406
+ // ============================================================================
407
+ // Profile-based Docker Client Pool
408
+ // ============================================================================
409
+ /**
410
+ * Pool of Docker clients by profile name
411
+ * Allows parallel access to multiple Docker environments (local and remote)
412
+ */
413
+ const clientPool = new Map();
414
+ /**
415
+ * Local Docker client (cached)
416
+ */
417
+ let localDockerClient = null;
418
+ /**
419
+ * Load profile configuration from profiles.json
420
+ * @param profileName - Profile name to load
421
+ * @returns SSHConfig or null for local mode
422
+ * @throws Error if profile not found or invalid
423
+ */
424
+ function loadProfileConfig(profileName) {
425
+ const profilesFile = process.env.DOCKER_MCP_PROFILES_FILE;
426
+ if (!profilesFile) {
427
+ throw new Error('DOCKER_MCP_PROFILES_FILE environment variable not set. Cannot load profile.');
428
+ }
429
+ // Load profiles file (synchronous!)
430
+ const fileResult = loadProfilesFile(profilesFile);
431
+ if (fileResult.errors.length > 0) {
432
+ throw new Error(`Failed to load profiles file: ${fileResult.errors.join(', ')}`);
433
+ }
434
+ if (!fileResult.config) {
435
+ throw new Error(`Profiles file not found or empty: ${profilesFile}`);
436
+ }
437
+ // Get profile data
438
+ const profileData = fileResult.config.profiles[profileName];
439
+ if (!profileData) {
440
+ const available = Object.keys(fileResult.config.profiles).join(', ');
441
+ throw new Error(`Profile "${profileName}" not found. Available profiles: ${available}`);
442
+ }
443
+ // Check if local mode
444
+ if (profileData.mode === 'local') {
445
+ logger.info(`Profile "${profileName}" is configured for LOCAL mode`);
446
+ return null;
447
+ }
448
+ // Convert to SSHConfig
449
+ try {
450
+ const config = profileDataToSSHConfig(profileData);
451
+ logger.info(`Profile "${profileName}" loaded for REMOTE mode (${config.host})`);
452
+ return config;
453
+ }
454
+ catch (error) {
455
+ if (error.code === 'LOCAL_MODE') {
456
+ logger.info(`Profile "${profileName}" is configured for LOCAL mode`);
457
+ return null;
458
+ }
459
+ throw error;
460
+ }
461
+ }
462
+ /**
463
+ * Get Docker client for specific profile
464
+ * @param profileName - Profile name (undefined = local Docker)
465
+ * @returns DockerClient instance
466
+ *
467
+ * @example
468
+ * // Local Docker (default)
469
+ * const localClient = getDockerClientForProfile();
470
+ *
471
+ * // Remote Docker (production profile)
472
+ * const prodClient = getDockerClientForProfile('production');
473
+ */
474
+ export function getDockerClientForProfile(profileName) {
475
+ // No profile specified = local Docker
476
+ if (!profileName) {
477
+ if (!localDockerClient) {
478
+ localDockerClient = new DockerClient();
479
+ logger.debug('Created LOCAL Docker client');
480
+ }
481
+ return localDockerClient;
482
+ }
483
+ // Check if client already exists in pool
484
+ if (clientPool.has(profileName)) {
485
+ logger.debug(`Using cached Docker client for profile: ${profileName}`);
486
+ return clientPool.get(profileName);
487
+ }
488
+ // Load profile configuration (synchronous!)
489
+ logger.info(`Loading Docker client for profile: ${profileName}`);
490
+ const sshConfig = loadProfileConfig(profileName);
491
+ // Create client (local or remote based on config)
492
+ const client = new DockerClient(sshConfig);
493
+ // Cache in pool
494
+ clientPool.set(profileName, client);
495
+ logger.info(`Docker client cached for profile: ${profileName}`);
496
+ return client;
497
+ }
498
+ /**
499
+ * Clear client pool (for testing or cleanup)
500
+ */
501
+ export function clearClientPool() {
502
+ logger.info(`Clearing Docker client pool (${clientPool.size} clients)`);
503
+ // Cleanup all clients in pool
504
+ for (const [profileName, client] of clientPool.entries()) {
505
+ try {
506
+ client.cleanup();
507
+ logger.debug(`Cleaned up client for profile: ${profileName}`);
508
+ }
509
+ catch (error) {
510
+ logger.warn(`Failed to cleanup client for profile ${profileName}: ${error.message}`);
511
+ }
512
+ }
513
+ clientPool.clear();
514
+ // Cleanup local client
515
+ if (localDockerClient) {
516
+ try {
517
+ localDockerClient.cleanup();
518
+ logger.debug('Cleaned up LOCAL Docker client');
519
+ }
520
+ catch (error) {
521
+ logger.warn(`Failed to cleanup local client: ${error.message}`);
522
+ }
523
+ localDockerClient = null;
524
+ }
525
+ }
526
+ /**
527
+ * Cleanup all Docker clients in pool (for graceful shutdown)
528
+ */
529
+ export function cleanupAllDockerClients() {
530
+ // Cleanup singleton
531
+ cleanupDockerClient();
532
+ // Cleanup pool
533
+ clearClientPool();
534
+ }
59
535
  //# sourceMappingURL=docker-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"docker-client.js","sourceRoot":"","sources":["../../src/utils/docker-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;GAEG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,CAAS;IAEvB;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,mEAAmE,CACpE,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,OAAqC;QACxD,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;CACF;AAED,qBAAqB;AACrB,IAAI,oBAAoB,GAAwB,IAAI,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,oBAAoB,GAAG,IAAI,YAAY,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,oBAAoB,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"docker-client.js","sourceRoot":"","sources":["../../src/utils/docker-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Profiles File Loader
3
+ * Load SSH profiles from JSON configuration file
4
+ */
5
+ import type { SSHConfig } from './ssh-config.js';
6
+ /**
7
+ * Profiles configuration file structure
8
+ */
9
+ export interface ProfilesConfig {
10
+ /** Default profile name to use if not specified */
11
+ default?: string;
12
+ /** SSH profiles by name */
13
+ profiles: Record<string, SSHProfileData>;
14
+ }
15
+ /**
16
+ * SSH profile data in config file
17
+ */
18
+ export interface SSHProfileData {
19
+ /** Profile mode: 'local' for local Docker, 'remote' or undefined for remote Docker */
20
+ mode?: 'local' | 'remote';
21
+ /** Server address (required for remote mode) */
22
+ host?: string;
23
+ /** Username for SSH connection (required for remote mode) */
24
+ username?: string;
25
+ /** SSH port (default: 22) */
26
+ port?: number;
27
+ /** Path to private SSH key */
28
+ privateKeyPath?: string;
29
+ /** Passphrase for encrypted SSH key */
30
+ passphrase?: string;
31
+ /** Password for authentication (not recommended for production) */
32
+ password?: string;
33
+ /** Base path for Docker projects on remote server (e.g., "/var/www") */
34
+ projectsPath?: string;
35
+ }
36
+ /**
37
+ * Result of loading profiles file
38
+ */
39
+ export interface ProfilesFileResult {
40
+ /** Loaded profiles configuration */
41
+ config: ProfilesConfig | null;
42
+ /** Validation errors */
43
+ errors: string[];
44
+ }
45
+ /**
46
+ * Load profiles from JSON file
47
+ *
48
+ * @param filePath - Path to profiles JSON file
49
+ * @returns Profiles configuration and errors
50
+ */
51
+ export declare function loadProfilesFile(filePath: string): ProfilesFileResult;
52
+ /**
53
+ * Convert profile data to SSHConfig
54
+ * @throws Error with code 'LOCAL_MODE' if profile is configured for local Docker
55
+ */
56
+ export declare function profileDataToSSHConfig(data: SSHProfileData): SSHConfig;
57
+ //# sourceMappingURL=profiles-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles-file.d.ts","sourceRoot":"","sources":["../../src/utils/profiles-file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sFAAsF;IACtF,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,wBAAwB;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CA2IrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,CAsBtE"}