@edgible-team/cli 1.0.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 (102) hide show
  1. package/LICENSE +136 -0
  2. package/README.md +450 -0
  3. package/dist/client/api-client.js +1057 -0
  4. package/dist/client/index.js +21 -0
  5. package/dist/commands/agent.js +1280 -0
  6. package/dist/commands/ai.js +608 -0
  7. package/dist/commands/application.js +885 -0
  8. package/dist/commands/auth.js +570 -0
  9. package/dist/commands/base/BaseCommand.js +93 -0
  10. package/dist/commands/base/CommandHandler.js +7 -0
  11. package/dist/commands/base/command-wrapper.js +58 -0
  12. package/dist/commands/base/middleware.js +77 -0
  13. package/dist/commands/config.js +116 -0
  14. package/dist/commands/connectivity.js +59 -0
  15. package/dist/commands/debug.js +98 -0
  16. package/dist/commands/discover.js +144 -0
  17. package/dist/commands/examples/migrated-command-example.js +180 -0
  18. package/dist/commands/gateway.js +494 -0
  19. package/dist/commands/managedGateway.js +787 -0
  20. package/dist/commands/utils/config-validator.js +76 -0
  21. package/dist/commands/utils/gateway-prompt.js +79 -0
  22. package/dist/commands/utils/input-parser.js +120 -0
  23. package/dist/commands/utils/output-formatter.js +109 -0
  24. package/dist/config/app-config.js +99 -0
  25. package/dist/detection/SystemCapabilityDetector.js +1244 -0
  26. package/dist/detection/ToolDetector.js +305 -0
  27. package/dist/detection/WorkloadDetector.js +314 -0
  28. package/dist/di/bindings.js +99 -0
  29. package/dist/di/container.js +88 -0
  30. package/dist/di/types.js +32 -0
  31. package/dist/index.js +52 -0
  32. package/dist/interfaces/IDaemonManager.js +3 -0
  33. package/dist/repositories/config-repository.js +62 -0
  34. package/dist/repositories/gateway-repository.js +35 -0
  35. package/dist/scripts/postinstall.js +101 -0
  36. package/dist/services/AgentStatusManager.js +299 -0
  37. package/dist/services/ConnectivityTester.js +271 -0
  38. package/dist/services/DependencyInstaller.js +475 -0
  39. package/dist/services/LocalAgentManager.js +2216 -0
  40. package/dist/services/application/ApplicationService.js +299 -0
  41. package/dist/services/auth/AuthService.js +214 -0
  42. package/dist/services/aws.js +644 -0
  43. package/dist/services/daemon/DaemonManagerFactory.js +65 -0
  44. package/dist/services/daemon/DockerDaemonManager.js +395 -0
  45. package/dist/services/daemon/LaunchdDaemonManager.js +257 -0
  46. package/dist/services/daemon/PodmanDaemonManager.js +369 -0
  47. package/dist/services/daemon/SystemdDaemonManager.js +221 -0
  48. package/dist/services/daemon/WindowsServiceDaemonManager.js +210 -0
  49. package/dist/services/daemon/index.js +16 -0
  50. package/dist/services/edgible.js +3060 -0
  51. package/dist/services/gateway/GatewayService.js +334 -0
  52. package/dist/state/config.js +146 -0
  53. package/dist/types/AgentConfig.js +5 -0
  54. package/dist/types/AgentStatus.js +5 -0
  55. package/dist/types/ApiClient.js +5 -0
  56. package/dist/types/ApiRequests.js +5 -0
  57. package/dist/types/ApiResponses.js +5 -0
  58. package/dist/types/Application.js +5 -0
  59. package/dist/types/CaddyJson.js +5 -0
  60. package/dist/types/UnifiedAgentStatus.js +56 -0
  61. package/dist/types/WireGuard.js +5 -0
  62. package/dist/types/Workload.js +5 -0
  63. package/dist/types/agent.js +5 -0
  64. package/dist/types/command-options.js +5 -0
  65. package/dist/types/connectivity.js +5 -0
  66. package/dist/types/errors.js +250 -0
  67. package/dist/types/gateway-types.js +5 -0
  68. package/dist/types/index.js +48 -0
  69. package/dist/types/models/ApplicationData.js +5 -0
  70. package/dist/types/models/CertificateData.js +5 -0
  71. package/dist/types/models/DeviceData.js +5 -0
  72. package/dist/types/models/DevicePoolData.js +5 -0
  73. package/dist/types/models/OrganizationData.js +5 -0
  74. package/dist/types/models/OrganizationInviteData.js +5 -0
  75. package/dist/types/models/ProviderConfiguration.js +5 -0
  76. package/dist/types/models/ResourceData.js +5 -0
  77. package/dist/types/models/ServiceResourceData.js +5 -0
  78. package/dist/types/models/UserData.js +5 -0
  79. package/dist/types/route.js +5 -0
  80. package/dist/types/validation/schemas.js +218 -0
  81. package/dist/types/validation.js +5 -0
  82. package/dist/utils/FileIntegrityManager.js +256 -0
  83. package/dist/utils/PathMigration.js +219 -0
  84. package/dist/utils/PathResolver.js +235 -0
  85. package/dist/utils/PlatformDetector.js +277 -0
  86. package/dist/utils/console-logger.js +130 -0
  87. package/dist/utils/docker-compose-parser.js +179 -0
  88. package/dist/utils/errors.js +130 -0
  89. package/dist/utils/health-checker.js +155 -0
  90. package/dist/utils/json-logger.js +72 -0
  91. package/dist/utils/log-formatter.js +293 -0
  92. package/dist/utils/logger.js +59 -0
  93. package/dist/utils/network-utils.js +217 -0
  94. package/dist/utils/output.js +182 -0
  95. package/dist/utils/passwordValidation.js +91 -0
  96. package/dist/utils/progress.js +167 -0
  97. package/dist/utils/sudo-checker.js +22 -0
  98. package/dist/utils/urls.js +32 -0
  99. package/dist/utils/validation.js +31 -0
  100. package/dist/validation/schemas.js +175 -0
  101. package/dist/validation/validator.js +67 -0
  102. package/package.json +83 -0
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ /**
3
+ * Example of a migrated command using all the new infrastructure
4
+ * This demonstrates how to use:
5
+ * - Dependency injection
6
+ * - Logger abstraction
7
+ * - Validation with Zod
8
+ * - Command wrapper
9
+ * - Shared utilities
10
+ * - Proper TypeScript types
11
+ *
12
+ * This is a reference implementation for migrating other commands
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.setupExampleGatewayCreateCommand = setupExampleGatewayCreateCommand;
19
+ const container_1 = require("../../di/container");
20
+ const types_1 = require("../../di/types");
21
+ const command_wrapper_1 = require("../base/command-wrapper");
22
+ const validator_1 = require("../../validation/validator");
23
+ const schemas_1 = require("../../validation/schemas");
24
+ const gateway_prompt_1 = require("../utils/gateway-prompt");
25
+ const output_formatter_1 = require("../utils/output-formatter");
26
+ const config_validator_1 = require("../utils/config-validator");
27
+ const chalk_1 = __importDefault(require("chalk"));
28
+ /**
29
+ * Example: Migrated gateway create command
30
+ * This shows the pattern for all command migrations
31
+ */
32
+ function setupExampleGatewayCreateCommand(program) {
33
+ const gatewayCommand = program
34
+ .command('gateway')
35
+ .description('Manage gateways')
36
+ .alias('gw');
37
+ gatewayCommand
38
+ .command('create')
39
+ .description('Create a new gateway device and EC2 instance')
40
+ .option('-n, --name <name>', 'Gateway name')
41
+ .option('-d, --description <description>', 'Gateway description')
42
+ .option('-p, --profile <profile>', 'AWS profile to use')
43
+ .option('-r, --region <region>', 'AWS region')
44
+ .option('-t, --instance-type <type>', 'EC2 instance type', 't3.micro')
45
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
46
+ // Get dependencies from container
47
+ const container = (0, container_1.getContainer)();
48
+ const logger = container.get(types_1.TYPES.Logger);
49
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
50
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
51
+ // Validate configuration
52
+ (0, config_validator_1.validateConfig)(configRepository, {
53
+ requireAuth: true,
54
+ requireOrganization: true,
55
+ });
56
+ // Validate and parse options using Zod
57
+ const validatedOptions = (0, validator_1.validateOptions)(schemas_1.createGatewayRequestSchema, {
58
+ name: options.name,
59
+ description: options.description,
60
+ awsProfile: options.profile,
61
+ region: options.region,
62
+ instanceType: options.instanceType,
63
+ });
64
+ // Log command execution
65
+ logger.info('Creating gateway', { name: validatedOptions.name });
66
+ // Use the service
67
+ const result = await gatewayService.createGateway({
68
+ name: validatedOptions.name,
69
+ description: validatedOptions.description,
70
+ awsProfile: validatedOptions.awsProfile,
71
+ region: validatedOptions.region,
72
+ instanceType: validatedOptions.instanceType,
73
+ });
74
+ // Format output
75
+ console.log((0, output_formatter_1.formatSuccess)('Gateway created successfully!'));
76
+ console.log(chalk_1.default.blue('\n📋 Gateway Details:'));
77
+ console.log((0, output_formatter_1.formatGateway)({
78
+ device: result.gateway,
79
+ ec2Instance: result.ec2Instance,
80
+ }));
81
+ logger.debug('Gateway creation completed', { gatewayId: result.gateway.id });
82
+ }, {
83
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
84
+ requireAuth: true,
85
+ requireOrganization: true,
86
+ }));
87
+ /**
88
+ * Example: Migrated gateway list command
89
+ */
90
+ gatewayCommand
91
+ .command('list')
92
+ .description('List all gateway devices')
93
+ .option('--json', 'Output as JSON')
94
+ .alias('ls')
95
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
96
+ const container = (0, container_1.getContainer)();
97
+ const logger = container.get(types_1.TYPES.Logger);
98
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
99
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
100
+ (0, config_validator_1.validateConfig)(configRepository, {
101
+ requireAuth: true,
102
+ requireOrganization: true,
103
+ });
104
+ logger.debug('Listing gateways');
105
+ const response = await gatewayService.listGateways();
106
+ if (options.json) {
107
+ console.log(JSON.stringify({
108
+ gateways: response.gateways.map((gateway) => ({
109
+ id: gateway.device.id,
110
+ name: gateway.device.name,
111
+ description: gateway.device.description,
112
+ ec2Instance: gateway.ec2Instance?.instanceId,
113
+ publicIp: gateway.ec2Instance?.publicIp,
114
+ privateIp: gateway.ec2Instance?.privateIp,
115
+ region: gateway.ec2Instance?.region,
116
+ state: gateway.ec2Instance?.state,
117
+ createdAt: gateway.device.createdAt,
118
+ })),
119
+ }, null, 2));
120
+ return;
121
+ }
122
+ if (response.gateways.length === 0) {
123
+ console.log(chalk_1.default.yellow('⚠ No gateways found'));
124
+ console.log(chalk_1.default.gray('Use "edgible gateway create" to create a gateway'));
125
+ return;
126
+ }
127
+ console.log(chalk_1.default.blue.bold('🌐 Gateway Devices:\n'));
128
+ response.gateways.forEach((gateway) => {
129
+ console.log((0, output_formatter_1.formatGateway)(gateway));
130
+ });
131
+ }, {
132
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
133
+ requireAuth: true,
134
+ requireOrganization: true,
135
+ }));
136
+ /**
137
+ * Example: Migrated gateway delete command using shared utilities
138
+ */
139
+ gatewayCommand
140
+ .command('delete')
141
+ .description('Delete a gateway device and EC2 instance')
142
+ .option('-i, --id <id>', 'Gateway ID to delete')
143
+ .option('-f, --force', 'Force delete even if applications exist')
144
+ .alias('rm')
145
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
146
+ const container = (0, container_1.getContainer)();
147
+ const logger = container.get(types_1.TYPES.Logger);
148
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
149
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
150
+ (0, config_validator_1.validateConfig)(configRepository, {
151
+ requireAuth: true,
152
+ requireOrganization: true,
153
+ });
154
+ // Use shared utility to get gateway ID
155
+ const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
156
+ if (!gatewayId) {
157
+ throw new Error('Gateway ID is required');
158
+ }
159
+ logger.info('Deleting gateway', { gatewayId });
160
+ await gatewayService.deleteGateway(gatewayId, options.force || false);
161
+ console.log((0, output_formatter_1.formatSuccess)('Gateway deleted successfully!'));
162
+ }, {
163
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
164
+ requireAuth: true,
165
+ requireOrganization: true,
166
+ }));
167
+ }
168
+ /**
169
+ * Migration checklist:
170
+ *
171
+ * ✅ Use DI container to get services
172
+ * ✅ Use logger instead of console.log
173
+ * ✅ Validate inputs with Zod schemas
174
+ * ✅ Use wrapCommand for error handling
175
+ * ✅ Use shared utilities for common operations
176
+ * ✅ Use proper TypeScript types (no any)
177
+ * ✅ Validate configuration before execution
178
+ * ✅ Format output consistently
179
+ */
180
+ //# sourceMappingURL=migrated-command-example.js.map
@@ -0,0 +1,494 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.setupGatewayCommands = setupGatewayCommands;
40
+ const inquirer_1 = __importDefault(require("inquirer"));
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const child_process_1 = require("child_process");
43
+ const command_wrapper_1 = require("./base/command-wrapper");
44
+ const container_1 = require("../di/container");
45
+ const types_1 = require("../di/types");
46
+ const config_validator_1 = require("./utils/config-validator");
47
+ const output_formatter_1 = require("./utils/output-formatter");
48
+ const gateway_prompt_1 = require("./utils/gateway-prompt");
49
+ /**
50
+ * Gateway command group
51
+ */
52
+ function setupGatewayCommands(program) {
53
+ const gatewayCommand = program
54
+ .command('gateway')
55
+ .description('Manage gateways')
56
+ .alias('gw');
57
+ gatewayCommand
58
+ .command('create')
59
+ .description('Create a new gateway device and EC2 instance')
60
+ .addHelpText('after', `
61
+ Examples:
62
+ $ edgible gateway create --name mygateway --region us-east-1
63
+ $ edgible gateway create --name mygateway --profile default --instance-type t3.micro
64
+ `)
65
+ .option('-n, --name <name>', 'Gateway name')
66
+ .option('-d, --description <description>', 'Gateway description')
67
+ .option('-p, --profile <profile>', 'AWS profile to use')
68
+ .option('-r, --region <region>', 'AWS region')
69
+ .option('-t, --instance-type <type>', 'EC2 instance type', 't3.micro')
70
+ .alias('new')
71
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
72
+ const container = (0, container_1.getContainer)();
73
+ const logger = container.get(types_1.TYPES.Logger);
74
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
75
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
76
+ (0, config_validator_1.validateConfig)(configRepository, {
77
+ requireAuth: true,
78
+ requireOrganization: true,
79
+ });
80
+ let gatewayName = options.name;
81
+ let description = options.description;
82
+ let awsProfile = options.profile;
83
+ let region = options.region;
84
+ let instanceType = options.instanceType || 't3.micro';
85
+ // If not provided via options, prompt for input
86
+ if (!gatewayName) {
87
+ const nameAnswer = await inquirer_1.default.prompt([
88
+ {
89
+ type: 'input',
90
+ name: 'name',
91
+ message: 'Enter gateway name:',
92
+ validate: (input) => {
93
+ if (!input.trim()) {
94
+ return 'Gateway name is required';
95
+ }
96
+ return true;
97
+ },
98
+ },
99
+ ]);
100
+ gatewayName = nameAnswer.name.trim();
101
+ }
102
+ if (!description) {
103
+ const descAnswer = await inquirer_1.default.prompt([
104
+ {
105
+ type: 'input',
106
+ name: 'description',
107
+ message: 'Enter gateway description (optional):',
108
+ default: `Gateway: ${gatewayName}`,
109
+ },
110
+ ]);
111
+ description = descAnswer.description.trim();
112
+ }
113
+ if (!awsProfile) {
114
+ // Check available AWS profiles
115
+ const { AWSService } = await Promise.resolve().then(() => __importStar(require('../services/aws')));
116
+ const awsService = new AWSService();
117
+ const awsCheck = await awsService.checkAWSCLI();
118
+ if (!awsCheck.available) {
119
+ logger.error('AWS CLI is not installed or not available');
120
+ console.log(chalk_1.default.red('✗ AWS CLI is not installed or not available'));
121
+ console.log(chalk_1.default.gray('Please install AWS CLI and configure credentials'));
122
+ return;
123
+ }
124
+ const profileChoices = awsCheck.profiles.map((profile) => ({
125
+ name: profile,
126
+ value: profile,
127
+ }));
128
+ if (profileChoices.length === 0) {
129
+ logger.error('No AWS profiles found');
130
+ console.log(chalk_1.default.red('✗ No AWS profiles found'));
131
+ console.log(chalk_1.default.gray('Please run "aws configure" to set up your AWS credentials'));
132
+ return;
133
+ }
134
+ const profileAnswer = await inquirer_1.default.prompt([
135
+ {
136
+ type: 'list',
137
+ name: 'profile',
138
+ message: 'Select AWS profile:',
139
+ choices: profileChoices,
140
+ },
141
+ ]);
142
+ awsProfile = profileAnswer.profile;
143
+ }
144
+ if (!region) {
145
+ const regionAnswer = await inquirer_1.default.prompt([
146
+ {
147
+ type: 'input',
148
+ name: 'region',
149
+ message: 'Enter AWS region:',
150
+ default: 'us-east-1',
151
+ validate: (input) => {
152
+ if (!input.trim()) {
153
+ return 'AWS region is required';
154
+ }
155
+ return true;
156
+ },
157
+ },
158
+ ]);
159
+ region = regionAnswer.region.trim();
160
+ }
161
+ logger.info('Creating gateway', { name: gatewayName, region, instanceType });
162
+ const createConfig = {
163
+ name: gatewayName,
164
+ };
165
+ if (description && description.trim())
166
+ createConfig.description = description;
167
+ if (awsProfile && awsProfile.trim())
168
+ createConfig.awsProfile = awsProfile;
169
+ if (region && region.trim())
170
+ createConfig.region = region;
171
+ if (instanceType && instanceType.trim())
172
+ createConfig.instanceType = instanceType;
173
+ const result = await gatewayService.createGateway(createConfig);
174
+ console.log(chalk_1.default.green('\n✓ Gateway created successfully!'));
175
+ console.log(chalk_1.default.blue('\n📋 Gateway Details:'));
176
+ console.log((0, output_formatter_1.formatGateway)({
177
+ device: result.gateway,
178
+ ec2Instance: result.ec2Instance,
179
+ }));
180
+ }, {
181
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
182
+ requireAuth: true,
183
+ requireOrganization: true,
184
+ }));
185
+ gatewayCommand
186
+ .command('list')
187
+ .description('List all gateway devices')
188
+ .option('--json', 'Output as JSON')
189
+ .alias('ls')
190
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
191
+ const container = (0, container_1.getContainer)();
192
+ const logger = container.get(types_1.TYPES.Logger);
193
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
194
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
195
+ (0, config_validator_1.validateConfig)(configRepository, {
196
+ requireAuth: true,
197
+ requireOrganization: true,
198
+ });
199
+ logger.debug('Listing gateways');
200
+ const response = await gatewayService.listGateways();
201
+ if (response.gateways.length === 0) {
202
+ console.log(chalk_1.default.yellow('⚠ No gateways found'));
203
+ console.log(chalk_1.default.gray('Use "edgible gateway create" to create a gateway'));
204
+ return;
205
+ }
206
+ if (options.json) {
207
+ console.log(JSON.stringify({
208
+ gateways: response.gateways.map((gateway) => ({
209
+ id: gateway.device.id,
210
+ name: gateway.device.name,
211
+ description: gateway.device.description,
212
+ ec2Instance: gateway.ec2Instance?.instanceId,
213
+ publicIp: gateway.ec2Instance?.publicIp,
214
+ privateIp: gateway.ec2Instance?.privateIp,
215
+ region: gateway.ec2Instance?.region,
216
+ state: gateway.ec2Instance?.state,
217
+ createdAt: gateway.device.createdAt,
218
+ })),
219
+ }, null, 2));
220
+ return;
221
+ }
222
+ console.log((0, output_formatter_1.formatList)(response.gateways, (gateway) => (0, output_formatter_1.formatGateway)(gateway), '🌐 Gateway Devices:', 'No gateways found'));
223
+ }, {
224
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
225
+ requireAuth: true,
226
+ requireOrganization: true,
227
+ }));
228
+ gatewayCommand
229
+ .command('get')
230
+ .description('Get status of a specific gateway')
231
+ .option('-i, --id <id>', 'Gateway ID')
232
+ .alias('status')
233
+ .alias('info')
234
+ .action(async (options) => {
235
+ console.log(chalk_1.default.yellow('Not yet implemented.'));
236
+ });
237
+ gatewayCommand
238
+ .command('update')
239
+ .description('Update an existing gateway')
240
+ .option('-i, --id <id>', 'Gateway ID')
241
+ .action(async (options) => {
242
+ console.log(chalk_1.default.yellow('Not yet implemented.'));
243
+ });
244
+ gatewayCommand
245
+ .command('delete')
246
+ .description('Delete a gateway device and EC2 instance')
247
+ .option('-i, --id <id>', 'Gateway ID to delete')
248
+ .option('-f, --force', 'Force delete even if applications exist')
249
+ .alias('rm')
250
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
251
+ const container = (0, container_1.getContainer)();
252
+ const logger = container.get(types_1.TYPES.Logger);
253
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
254
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
255
+ (0, config_validator_1.validateConfig)(configRepository, {
256
+ requireAuth: true,
257
+ requireOrganization: true,
258
+ });
259
+ const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
260
+ if (!gatewayId) {
261
+ throw new Error('Gateway ID is required');
262
+ }
263
+ // Confirm deletion
264
+ const confirm = await inquirer_1.default.prompt([
265
+ {
266
+ type: 'confirm',
267
+ name: 'confirm',
268
+ message: `Are you sure you want to delete gateway ${gatewayId}?`,
269
+ default: false,
270
+ },
271
+ ]);
272
+ if (!confirm.confirm) {
273
+ logger.info('Gateway deletion cancelled');
274
+ console.log(chalk_1.default.gray('Deletion cancelled'));
275
+ return;
276
+ }
277
+ logger.info('Deleting gateway', { gatewayId, force: options.force || false });
278
+ await gatewayService.deleteGateway(gatewayId, options.force || false);
279
+ console.log(chalk_1.default.green('✓ Gateway deleted successfully!'));
280
+ }, {
281
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
282
+ requireAuth: true,
283
+ requireOrganization: true,
284
+ }));
285
+ gatewayCommand
286
+ .command('resync')
287
+ .description('Resync agent code on a gateway')
288
+ .option('-i, --id <id>', 'Gateway ID to resync')
289
+ .option('-v, --version <version>', 'Agent version to deploy')
290
+ .option('--local', 'Upload agent from local dist directory instead of downloading from S3')
291
+ .option('--install-from-local', 'Upload agent from local dist directory instead of downloading from S3')
292
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
293
+ // Map --local to installFromLocal for backward compatibility
294
+ const installFromLocal = options.local || options.installFromLocal;
295
+ const container = (0, container_1.getContainer)();
296
+ const logger = container.get(types_1.TYPES.Logger);
297
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
298
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
299
+ const edgibleService = container.get(types_1.TYPES.EdgibleService);
300
+ (0, config_validator_1.validateConfig)(configRepository, {
301
+ requireAuth: true,
302
+ requireOrganization: true,
303
+ });
304
+ const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
305
+ if (!gatewayId) {
306
+ throw new Error('Gateway ID is required');
307
+ }
308
+ logger.info('Resyncing agent on gateway', { gatewayId, version: options.version, installFromLocal });
309
+ // TODO: Extract resyncGatewayAgent to GatewaySshService
310
+ const result = await edgibleService.resyncGatewayAgent(gatewayId, options.version, installFromLocal);
311
+ console.log(chalk_1.default.green('\n✓ Agent resynced successfully!'));
312
+ console.log(chalk_1.default.blue('\n📋 Resync Details:'));
313
+ console.log(chalk_1.default.white(` Gateway ID: ${gatewayId}`));
314
+ console.log(chalk_1.default.white(` Agent Version: ${result.agentVersion}`));
315
+ console.log(chalk_1.default.white(` Sync Time: ${new Date(result.syncTimestamp).toLocaleString()}`));
316
+ }, {
317
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
318
+ requireAuth: true,
319
+ requireOrganization: true,
320
+ }));
321
+ gatewayCommand
322
+ .command('logs')
323
+ .description('Retrieve agent logs from a gateway')
324
+ .option('-i, --id <id>', 'Gateway ID to get logs from')
325
+ .option('-n, --lines <number>', 'Number of log lines', '50')
326
+ .option('-f, --follow', 'Follow logs in real-time')
327
+ .option('-l, --level <level>', 'Log level filter', 'all')
328
+ .option('-c, --comprehensive', 'Show comprehensive diagnostics (status, system info, WireGuard, Caddy, etc.)')
329
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
330
+ const container = (0, container_1.getContainer)();
331
+ const logger = container.get(types_1.TYPES.Logger);
332
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
333
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
334
+ const edgibleService = container.get(types_1.TYPES.EdgibleService);
335
+ (0, config_validator_1.validateConfig)(configRepository, {
336
+ requireAuth: true,
337
+ requireOrganization: true,
338
+ });
339
+ const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
340
+ if (!gatewayId) {
341
+ throw new Error('Gateway ID is required');
342
+ }
343
+ const lines = parseInt(options.lines || '50') || 50;
344
+ const follow = options.follow || false;
345
+ const level = options.level || 'all';
346
+ const comprehensive = options.comprehensive || false;
347
+ logger.info('Retrieving gateway logs', {
348
+ gatewayId,
349
+ lines: follow ? undefined : lines,
350
+ follow,
351
+ level,
352
+ comprehensive,
353
+ });
354
+ // TODO: Extract getGatewayLogs to GatewayDiagnosticsService
355
+ const result = await edgibleService.getGatewayLogs(gatewayId, {
356
+ lines: follow ? undefined : lines,
357
+ follow: follow,
358
+ level: level,
359
+ comprehensive: comprehensive,
360
+ });
361
+ if (result.success) {
362
+ console.log(result.logs);
363
+ }
364
+ else {
365
+ logger.error('Failed to retrieve logs');
366
+ console.log(chalk_1.default.red('✗ Failed to retrieve logs'));
367
+ }
368
+ }, {
369
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
370
+ requireAuth: true,
371
+ requireOrganization: true,
372
+ }));
373
+ gatewayCommand
374
+ .command('ssh')
375
+ .description('Connect to a gateway via SSH (interactive shell)')
376
+ .option('-i, --id <id>', 'Gateway ID to connect to')
377
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
378
+ const container = (0, container_1.getContainer)();
379
+ const logger = container.get(types_1.TYPES.Logger);
380
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
381
+ const gatewayRepository = container.get(types_1.TYPES.GatewayRepository);
382
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
383
+ (0, config_validator_1.validateConfig)(configRepository, {
384
+ requireAuth: true,
385
+ requireOrganization: true,
386
+ });
387
+ const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
388
+ if (!gatewayId) {
389
+ throw new Error('Gateway ID is required');
390
+ }
391
+ const gatewayInfo = gatewayRepository.getGateway(gatewayId);
392
+ if (!gatewayInfo) {
393
+ throw new Error('Gateway not found in local configuration');
394
+ }
395
+ logger.info('Connecting to gateway via SSH', { gatewayId, publicIp: gatewayInfo.publicIp });
396
+ console.log(chalk_1.default.blue(`\nConnecting to gateway: ${gatewayId}`));
397
+ console.log(chalk_1.default.gray(`Public IP: ${gatewayInfo.publicIp}`));
398
+ console.log(chalk_1.default.gray(`Region: ${gatewayInfo.region}`));
399
+ console.log(chalk_1.default.yellow('\nOpening SSH connection...\n'));
400
+ // Get SSH key path
401
+ const { AWSService } = await Promise.resolve().then(() => __importStar(require('../services/aws')));
402
+ const awsService = new AWSService(configRepository.getAWSProfile(), gatewayInfo.region);
403
+ // Wait for instance to be ready
404
+ console.log(chalk_1.default.gray('Waiting for instance to be ready...'));
405
+ const isReady = await awsService.waitForSSHReady(gatewayInfo.ec2InstanceId);
406
+ if (!isReady) {
407
+ logger.error('Instance is not ready for SSH connections', { instanceId: gatewayInfo.ec2InstanceId });
408
+ console.log(chalk_1.default.red('✗ Instance is not ready for SSH connections'));
409
+ return;
410
+ }
411
+ // Build SSH command
412
+ const sshKeyPath = gatewayInfo.keyPath;
413
+ const sshCommand = `ssh -i "${sshKeyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ec2-user@${gatewayInfo.publicIp}`;
414
+ console.log(chalk_1.default.green('✓ Opening interactive SSH session...'));
415
+ console.log(chalk_1.default.gray('─'.repeat(80)));
416
+ console.log(chalk_1.default.gray('Tip: Type "exit" to disconnect from the gateway\n'));
417
+ // Execute SSH using child_process
418
+ const sshProcess = (0, child_process_1.spawn)('sh', ['-c', sshCommand], {
419
+ stdio: 'inherit',
420
+ shell: false,
421
+ });
422
+ sshProcess.on('error', (error) => {
423
+ logger.error('SSH connection error', error);
424
+ console.error(chalk_1.default.red('✗ SSH connection error:'), error.message);
425
+ console.log(chalk_1.default.yellow('\nMake sure SSH is installed and the key file has correct permissions (chmod 600)'));
426
+ throw error;
427
+ });
428
+ sshProcess.on('exit', (code) => {
429
+ if (code === 0) {
430
+ logger.debug('SSH session ended normally');
431
+ console.log(chalk_1.default.gray('\nSSH session ended'));
432
+ }
433
+ else {
434
+ logger.warn('SSH session ended with non-zero code', { code });
435
+ console.log(chalk_1.default.yellow(`\nSSH session ended with code: ${code}`));
436
+ }
437
+ });
438
+ }, {
439
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
440
+ requireAuth: true,
441
+ requireOrganization: true,
442
+ }));
443
+ gatewayCommand
444
+ .command('wipe-logs')
445
+ .description('Clear agent log file on a gateway')
446
+ .option('-i, --id <id>', 'Gateway ID to wipe logs for')
447
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
448
+ const container = (0, container_1.getContainer)();
449
+ const logger = container.get(types_1.TYPES.Logger);
450
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
451
+ const gatewayService = container.get(types_1.TYPES.GatewayService);
452
+ const edgibleService = container.get(types_1.TYPES.EdgibleService);
453
+ (0, config_validator_1.validateConfig)(configRepository, {
454
+ requireAuth: true,
455
+ requireOrganization: true,
456
+ });
457
+ const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
458
+ if (!gatewayId) {
459
+ throw new Error('Gateway ID is required');
460
+ }
461
+ logger.info('Wiping gateway logs', { gatewayId });
462
+ // Confirm action
463
+ const confirm = await inquirer_1.default.prompt([
464
+ {
465
+ type: 'confirm',
466
+ name: 'confirm',
467
+ message: `Are you sure you want to clear all logs on gateway ${gatewayId}?`,
468
+ default: false,
469
+ },
470
+ ]);
471
+ if (!confirm.confirm) {
472
+ logger.info('Log wipe cancelled');
473
+ console.log(chalk_1.default.gray('Log wipe cancelled'));
474
+ return;
475
+ }
476
+ // Get gateway logs and wipe them
477
+ const result = await edgibleService.wipeGatewayLogs(gatewayId);
478
+ if (result.success) {
479
+ console.log(chalk_1.default.green('✓ Gateway logs cleared successfully!'));
480
+ console.log(chalk_1.default.gray(` Log file: ${result.logFile || 'agent.log'}`));
481
+ }
482
+ else {
483
+ console.log(chalk_1.default.red('✗ Failed to clear logs'));
484
+ if (result.message) {
485
+ console.log(chalk_1.default.yellow(result.message));
486
+ }
487
+ }
488
+ }, {
489
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
490
+ requireAuth: true,
491
+ requireOrganization: true,
492
+ }));
493
+ }
494
+ //# sourceMappingURL=gateway.js.map