@edgible-team/cli 1.2.11 → 1.2.15

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 (74) hide show
  1. package/dist/commands/agent/install.d.ts +4 -0
  2. package/dist/commands/agent/install.d.ts.map +1 -1
  3. package/dist/commands/agent/install.js +155 -129
  4. package/dist/commands/agent.d.ts.map +1 -1
  5. package/dist/commands/agent.js +4 -0
  6. package/dist/commands/ai/helpers.d.ts.map +1 -1
  7. package/dist/commands/ai/helpers.js +10 -5
  8. package/dist/commands/debug.d.ts.map +1 -1
  9. package/dist/commands/debug.js +7 -3
  10. package/dist/commands/stack/deploy.d.ts +6 -0
  11. package/dist/commands/stack/deploy.d.ts.map +1 -0
  12. package/dist/commands/stack/deploy.js +58 -0
  13. package/dist/commands/stack/diff.d.ts +7 -0
  14. package/dist/commands/stack/diff.d.ts.map +1 -0
  15. package/dist/commands/stack/diff.js +64 -0
  16. package/dist/commands/stack/status.d.ts +9 -0
  17. package/dist/commands/stack/status.d.ts.map +1 -0
  18. package/dist/commands/stack/status.js +53 -0
  19. package/dist/commands/stack/teardown.d.ts +6 -0
  20. package/dist/commands/stack/teardown.d.ts.map +1 -0
  21. package/dist/commands/stack/teardown.js +104 -0
  22. package/dist/commands/stack/validate.d.ts +7 -0
  23. package/dist/commands/stack/validate.d.ts.map +1 -0
  24. package/dist/commands/stack/validate.js +42 -0
  25. package/dist/commands/stack.d.ts +10 -0
  26. package/dist/commands/stack.d.ts.map +1 -0
  27. package/dist/commands/stack.js +112 -0
  28. package/dist/index.js +2 -0
  29. package/dist/services/DependencyInstaller.d.ts +2 -9
  30. package/dist/services/DependencyInstaller.d.ts.map +1 -1
  31. package/dist/services/DependencyInstaller.js +5 -30
  32. package/dist/services/application/ApplicationService.d.ts +3 -0
  33. package/dist/services/application/ApplicationService.d.ts.map +1 -1
  34. package/dist/services/application/ApplicationService.js +3 -0
  35. package/dist/services/instances.d.ts +23 -0
  36. package/dist/services/instances.d.ts.map +1 -1
  37. package/dist/services/instances.js +46 -1
  38. package/dist/services/stack/DependencyGraphManager.d.ts +69 -0
  39. package/dist/services/stack/DependencyGraphManager.d.ts.map +1 -0
  40. package/dist/services/stack/DependencyGraphManager.js +204 -0
  41. package/dist/services/stack/DeviceResolver.d.ts +63 -0
  42. package/dist/services/stack/DeviceResolver.d.ts.map +1 -0
  43. package/dist/services/stack/DeviceResolver.js +147 -0
  44. package/dist/services/stack/GatewayResolver.d.ts +84 -0
  45. package/dist/services/stack/GatewayResolver.d.ts.map +1 -0
  46. package/dist/services/stack/GatewayResolver.js +179 -0
  47. package/dist/services/stack/StackParser.d.ts +38 -0
  48. package/dist/services/stack/StackParser.d.ts.map +1 -0
  49. package/dist/services/stack/StackParser.js +234 -0
  50. package/dist/services/stack/StackService.d.ts +76 -0
  51. package/dist/services/stack/StackService.d.ts.map +1 -0
  52. package/dist/services/stack/StackService.js +476 -0
  53. package/dist/types/ApiRequests.d.ts +8 -0
  54. package/dist/types/ApiRequests.d.ts.map +1 -1
  55. package/dist/types/models/ApplicationData.d.ts +22 -0
  56. package/dist/types/models/ApplicationData.d.ts.map +1 -1
  57. package/dist/types/models/OrganizationData.d.ts +2 -0
  58. package/dist/types/models/OrganizationData.d.ts.map +1 -1
  59. package/dist/types/stack.d.ts +191 -0
  60. package/dist/types/stack.d.ts.map +1 -0
  61. package/dist/types/stack.js +5 -0
  62. package/dist/types/validation/schemas.d.ts +41 -23
  63. package/dist/types/validation/schemas.d.ts.map +1 -1
  64. package/dist/types/validation/schemas.js +20 -0
  65. package/dist/utils/run-as-user.d.ts +24 -0
  66. package/dist/utils/run-as-user.d.ts.map +1 -0
  67. package/dist/utils/run-as-user.js +42 -0
  68. package/dist/utils/stack-errors.d.ts +103 -0
  69. package/dist/utils/stack-errors.d.ts.map +1 -0
  70. package/dist/utils/stack-errors.js +158 -0
  71. package/dist/validation/stack-schemas.d.ts +535 -0
  72. package/dist/validation/stack-schemas.d.ts.map +1 -0
  73. package/dist/validation/stack-schemas.js +178 -0
  74. package/package.json +4 -2
@@ -7,5 +7,9 @@ export declare function handleAgentInstall(options: {
7
7
  type?: string;
8
8
  dev?: boolean;
9
9
  local?: boolean;
10
+ noInteractive?: boolean;
11
+ deviceId?: string;
12
+ devicePassword?: string;
13
+ autoInstallDeps?: boolean;
10
14
  }, logger: Logger, configManager: ConfigManager, edgibleService: EdgibleService, authService: AuthService, agentManager: LocalAgentManager): Promise<void>;
11
15
  //# sourceMappingURL=install.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/commands/agent/install.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAU9D,wBAAsB,kBAAkB,CACtC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,EAC1D,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,iBAAiB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAkZf"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/commands/agent/install.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAU9D,wBAAsB,kBAAkB,CACtC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,EAC1J,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,iBAAiB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6af"}
@@ -56,6 +56,9 @@ async function handleAgentInstall(options, logger, configManager, edgibleService
56
56
  requireAuth: true,
57
57
  requireOrganization: true,
58
58
  });
59
+ const noInteractive = options.noInteractive === true;
60
+ const deviceIdFromEnv = process.env['EDGIBLE_DEVICE_ID'];
61
+ const devicePasswordFromEnv = process.env['EDGIBLE_DEVICE_PASSWORD'];
59
62
  console.log(chalk_1.default.blue.bold('\n═══════════════════════════════════════════'));
60
63
  console.log(chalk_1.default.blue.bold(' Edgible Agent Installation'));
61
64
  console.log(chalk_1.default.blue.bold('═══════════════════════════════════════════\n'));
@@ -68,144 +71,157 @@ async function handleAgentInstall(options, logger, configManager, edgibleService
68
71
  console.log(chalk_1.default.yellow('⚠ ' + PlatformDetector_1.PlatformDetector.getRootRequirementMessage()));
69
72
  console.log(chalk_1.default.gray(' Some installation options require elevated privileges.\n'));
70
73
  }
71
- // Step 2: Device Selection (moved from start command)
74
+ // Step 2: Device Selection (or use flags/env in non-interactive)
72
75
  const config = configManager.getConfig();
73
- let deviceId = config.deviceId;
74
- let devicePassword = config.devicePassword;
75
- console.log(chalk_1.default.blue('📱 Device Selection'));
76
- console.log(chalk_1.default.gray('Select which serving device this agent should represent:\n'));
77
- try {
78
- // Fetch available serving devices
79
- const servingDevicesResp = await edgibleService.listServingDevices();
80
- const servingDevices = servingDevicesResp?.devices || [];
81
- if (servingDevices.length > 0) {
82
- // Show list of devices to select from
83
- const deviceChoices = servingDevices.map((d) => {
84
- const isCurrentDevice = config.deviceId === d.id;
85
- const displayName = `${d.name || d.id}${d.description ? ` - ${d.description}` : ''}${isCurrentDevice ? chalk_1.default.gray(' (current)') : ''}`;
86
- return {
87
- name: displayName,
88
- value: d.id
89
- };
90
- });
91
- // Add option to create new device
92
- deviceChoices.push({
93
- name: chalk_1.default.cyan('➕ Create new serving device'),
94
- value: '__create_new__'
95
- });
96
- const { selectedDeviceId } = await inquirer_1.default.prompt([{
97
- type: 'list',
98
- name: 'selectedDeviceId',
99
- message: 'Select serving device:',
100
- choices: deviceChoices,
101
- default: config.deviceId || undefined
102
- }]);
103
- if (selectedDeviceId === '__create_new__') {
104
- // Create new device
76
+ let deviceId = options.deviceId ?? deviceIdFromEnv ?? config.deviceId;
77
+ let devicePassword = options.devicePassword ?? devicePasswordFromEnv ?? config.devicePassword;
78
+ if (noInteractive) {
79
+ if (!deviceId || !devicePassword) {
80
+ throw new Error('Non-interactive install requires device credentials. Set --device-id and --device-password, or EDGIBLE_DEVICE_ID and EDGIBLE_DEVICE_PASSWORD, or run interactively once to save config.');
81
+ }
82
+ if (!options.type) {
83
+ throw new Error('Non-interactive install requires --type (e.g. --type launchd on macOS).');
84
+ }
85
+ console.log(chalk_1.default.blue('📱 Device (non-interactive)'));
86
+ console.log(chalk_1.default.gray(`Using device: ${deviceId}\n`));
87
+ configManager.updateConfig({ deviceId, devicePassword, deviceType: 'serving' });
88
+ }
89
+ else {
90
+ console.log(chalk_1.default.blue('📱 Device Selection'));
91
+ console.log(chalk_1.default.gray('Select which serving device this agent should represent:\n'));
92
+ try {
93
+ // Fetch available serving devices
94
+ const servingDevicesResp = await edgibleService.listServingDevices();
95
+ const servingDevices = servingDevicesResp?.devices || [];
96
+ if (servingDevices.length > 0) {
97
+ // Show list of devices to select from
98
+ const deviceChoices = servingDevices.map((d) => {
99
+ const isCurrentDevice = config.deviceId === d.id;
100
+ const displayName = `${d.name || d.id}${d.description ? ` - ${d.description}` : ''}${isCurrentDevice ? chalk_1.default.gray(' (current)') : ''}`;
101
+ return {
102
+ name: displayName,
103
+ value: d.id
104
+ };
105
+ });
106
+ // Add option to create new device
107
+ deviceChoices.push({
108
+ name: chalk_1.default.cyan('➕ Create new serving device'),
109
+ value: '__create_new__'
110
+ });
111
+ const { selectedDeviceId } = await inquirer_1.default.prompt([{
112
+ type: 'list',
113
+ name: 'selectedDeviceId',
114
+ message: 'Select serving device:',
115
+ choices: deviceChoices,
116
+ default: config.deviceId || undefined
117
+ }]);
118
+ if (selectedDeviceId === '__create_new__') {
119
+ // Create new device
120
+ const deviceNameAnswer = await inquirer_1.default.prompt([{
121
+ type: 'input',
122
+ name: 'deviceName',
123
+ message: 'Enter a name for this device:',
124
+ default: `${os.hostname()}-${os.platform()}`,
125
+ validate: (input) => {
126
+ if (!input.trim()) {
127
+ return 'Device name is required';
128
+ }
129
+ return true;
130
+ }
131
+ }]);
132
+ const descriptionAnswer = await inquirer_1.default.prompt([{
133
+ type: 'input',
134
+ name: 'description',
135
+ message: 'Enter device description (optional):',
136
+ default: `Serving device: ${deviceNameAnswer.deviceName}`
137
+ }]);
138
+ console.log(chalk_1.default.gray('\nCreating device...'));
139
+ const createResponse = await edgibleService.createServingDevice({
140
+ name: deviceNameAnswer.deviceName.trim(),
141
+ description: descriptionAnswer.description.trim()
142
+ });
143
+ deviceId = createResponse.device.id;
144
+ devicePassword = createResponse.device.password;
145
+ console.log(chalk_1.default.green(`✓ Device created: ${deviceId}`));
146
+ console.log(chalk_1.default.yellow(`\n⚠ Device Password: ${devicePassword}`));
147
+ console.log(chalk_1.default.yellow('⚠ Please save this password securely!\n'));
148
+ // Verify device credentials
149
+ if (devicePassword && deviceId) {
150
+ console.log(chalk_1.default.gray('Verifying device credentials...'));
151
+ try {
152
+ const isValid = await authService.verifyDeviceCredentials(deviceId, devicePassword);
153
+ if (isValid) {
154
+ console.log(chalk_1.default.green('✓ Device credentials verified\n'));
155
+ }
156
+ }
157
+ catch (verifyError) {
158
+ console.log(chalk_1.default.yellow('⚠ Could not verify device credentials\n'));
159
+ }
160
+ }
161
+ // Save device credentials to config
162
+ configManager.updateConfig({
163
+ deviceId: deviceId,
164
+ deviceName: deviceNameAnswer.deviceName.trim(),
165
+ devicePassword: devicePassword,
166
+ deviceType: 'serving'
167
+ });
168
+ }
169
+ else {
170
+ // Use existing device - need to fetch full details to get password
171
+ deviceId = selectedDeviceId;
172
+ if (!deviceId) {
173
+ throw new Error('No device selected');
174
+ }
175
+ console.log(chalk_1.default.gray('Retrieving device credentials...\n'));
176
+ // Fetch device details to get the plaintext password
177
+ const deviceResponse = await edgibleService.getDevice(deviceId);
178
+ devicePassword = deviceResponse.device?.password || '';
179
+ if (!devicePassword) {
180
+ throw new Error('Could not retrieve device password from API');
181
+ }
182
+ // Save device credentials to config
183
+ configManager.updateConfig({
184
+ deviceId,
185
+ devicePassword,
186
+ deviceType: 'serving'
187
+ });
188
+ console.log(chalk_1.default.green(`✓ Using device: ${deviceId}\n`));
189
+ }
190
+ }
191
+ else {
192
+ // No devices exist, must create one
193
+ console.log(chalk_1.default.yellow('No serving devices found. Creating a new one...\n'));
105
194
  const deviceNameAnswer = await inquirer_1.default.prompt([{
106
195
  type: 'input',
107
196
  name: 'deviceName',
108
197
  message: 'Enter a name for this device:',
109
198
  default: `${os.hostname()}-${os.platform()}`,
110
- validate: (input) => {
111
- if (!input.trim()) {
112
- return 'Device name is required';
113
- }
114
- return true;
115
- }
199
+ validate: (input) => input.trim().length > 0 || 'Device name is required'
116
200
  }]);
117
- const descriptionAnswer = await inquirer_1.default.prompt([{
118
- type: 'input',
119
- name: 'description',
120
- message: 'Enter device description (optional):',
121
- default: `Serving device: ${deviceNameAnswer.deviceName}`
122
- }]);
123
- console.log(chalk_1.default.gray('\nCreating device...'));
124
201
  const createResponse = await edgibleService.createServingDevice({
125
202
  name: deviceNameAnswer.deviceName.trim(),
126
- description: descriptionAnswer.description.trim()
203
+ description: `Serving device: ${deviceNameAnswer.deviceName}`
127
204
  });
128
205
  deviceId = createResponse.device.id;
129
206
  devicePassword = createResponse.device.password;
130
207
  console.log(chalk_1.default.green(`✓ Device created: ${deviceId}`));
131
208
  console.log(chalk_1.default.yellow(`\n⚠ Device Password: ${devicePassword}`));
132
209
  console.log(chalk_1.default.yellow('⚠ Please save this password securely!\n'));
133
- // Verify device credentials
134
- if (devicePassword && deviceId) {
135
- console.log(chalk_1.default.gray('Verifying device credentials...'));
136
- try {
137
- const isValid = await authService.verifyDeviceCredentials(deviceId, devicePassword);
138
- if (isValid) {
139
- console.log(chalk_1.default.green('✓ Device credentials verified\n'));
140
- }
141
- }
142
- catch (verifyError) {
143
- console.log(chalk_1.default.yellow('⚠ Could not verify device credentials\n'));
144
- }
145
- }
146
- // Save device credentials to config
147
- configManager.updateConfig({
148
- deviceId: deviceId,
149
- deviceName: deviceNameAnswer.deviceName.trim(),
150
- devicePassword: devicePassword,
151
- deviceType: 'serving'
152
- });
153
- }
154
- else {
155
- // Use existing device - need to fetch full details to get password
156
- deviceId = selectedDeviceId;
157
- if (!deviceId) {
158
- throw new Error('No device selected');
159
- }
160
- console.log(chalk_1.default.gray('Retrieving device credentials...\n'));
161
- // Fetch device details to get the plaintext password
162
- const deviceResponse = await edgibleService.getDevice(deviceId);
163
- devicePassword = deviceResponse.device?.password || '';
164
- if (!devicePassword) {
165
- throw new Error('Could not retrieve device password from API');
166
- }
167
- // Save device credentials to config
168
210
  configManager.updateConfig({
169
211
  deviceId,
212
+ deviceName: deviceNameAnswer.deviceName.trim(),
170
213
  devicePassword,
171
214
  deviceType: 'serving'
172
215
  });
173
- console.log(chalk_1.default.green(`✓ Using device: ${deviceId}\n`));
174
216
  }
175
217
  }
176
- else {
177
- // No devices exist, must create one
178
- console.log(chalk_1.default.yellow('No serving devices found. Creating a new one...\n'));
179
- const deviceNameAnswer = await inquirer_1.default.prompt([{
180
- type: 'input',
181
- name: 'deviceName',
182
- message: 'Enter a name for this device:',
183
- default: `${os.hostname()}-${os.platform()}`,
184
- validate: (input) => input.trim().length > 0 || 'Device name is required'
185
- }]);
186
- const createResponse = await edgibleService.createServingDevice({
187
- name: deviceNameAnswer.deviceName.trim(),
188
- description: `Serving device: ${deviceNameAnswer.deviceName}`
189
- });
190
- deviceId = createResponse.device.id;
191
- devicePassword = createResponse.device.password;
192
- console.log(chalk_1.default.green(`✓ Device created: ${deviceId}`));
193
- console.log(chalk_1.default.yellow(`\n⚠ Device Password: ${devicePassword}`));
194
- console.log(chalk_1.default.yellow('⚠ Please save this password securely!\n'));
195
- configManager.updateConfig({
196
- deviceId,
197
- deviceName: deviceNameAnswer.deviceName.trim(),
198
- devicePassword,
199
- deviceType: 'serving'
200
- });
218
+ catch (error) {
219
+ logger.error('Error during device selection', error);
220
+ const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred';
221
+ console.error(chalk_1.default.red('Error during device selection:'), errorMessage);
222
+ throw error;
201
223
  }
202
224
  }
203
- catch (error) {
204
- logger.error('Error during device selection', error);
205
- const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred';
206
- console.error(chalk_1.default.red('Error during device selection:'), errorMessage);
207
- throw error;
208
- }
209
225
  // Verify we have device credentials
210
226
  if (!deviceId || !devicePassword) {
211
227
  throw new Error('Device credentials are required');
@@ -224,16 +240,20 @@ async function handleAgentInstall(options, logger, configManager, edgibleService
224
240
  return;
225
241
  }
226
242
  let selectedType;
227
- if (options.type) {
243
+ if (options.type || noInteractive) {
244
+ const typeToUse = options.type ?? (noInteractive ? 'launchd' : undefined);
245
+ if (!typeToUse) {
246
+ throw new Error('Installation type is required in non-interactive mode (e.g. --type launchd).');
247
+ }
228
248
  // Type specified via flag - validate it's a supported daemon type
229
249
  const supportedTypes = ['systemd', 'launchd', 'windows-service'];
230
- if (!supportedTypes.includes(options.type)) {
231
- console.error(chalk_1.default.red(`✗ Installation type '${options.type}' is not supported`));
250
+ if (!supportedTypes.includes(typeToUse)) {
251
+ console.error(chalk_1.default.red(`✗ Installation type '${typeToUse}' is not supported`));
232
252
  console.error(chalk_1.default.yellow(` Only daemon installations are supported: ${supportedTypes.join(', ')}`));
233
253
  console.error(chalk_1.default.yellow(` Docker and Podman installations are no longer available`));
234
254
  return;
235
255
  }
236
- selectedType = options.type;
256
+ selectedType = typeToUse;
237
257
  const option = availableOptions.find(opt => opt.type === selectedType);
238
258
  if (!option) {
239
259
  console.error(chalk_1.default.red(`✗ Installation type '${selectedType}' not available on this platform`));
@@ -279,11 +299,12 @@ async function handleAgentInstall(options, logger, configManager, edgibleService
279
299
  console.log(chalk_1.default.blue('🔍 Checking System Dependencies'));
280
300
  console.log(chalk_1.default.gray('Verifying required tools are installed...\n'));
281
301
  const dependencyInstaller = new DependencyInstaller_1.DependencyInstaller();
302
+ const autoInstallDeps = options.autoInstallDeps === true || (noInteractive && options.autoInstallDeps !== false);
282
303
  try {
283
304
  await dependencyInstaller.checkAndInstallDependencies({
284
305
  includeWireGuardGo: false, // Use kernel WireGuard by default
285
306
  includeIptables: platform === 'linux', // Only check iptables on Linux
286
- autoInstall: false // Prompt user for installation
307
+ autoInstall: autoInstallDeps
287
308
  });
288
309
  console.log(chalk_1.default.green('✓ Dependencies verified\n'));
289
310
  }
@@ -292,16 +313,21 @@ async function handleAgentInstall(options, logger, configManager, edgibleService
292
313
  console.error(chalk_1.default.red(` ${error instanceof Error ? error.message : String(error)}`));
293
314
  console.log(chalk_1.default.yellow('\n⚠ Some dependencies are missing. The agent may not function correctly.'));
294
315
  console.log(chalk_1.default.yellow(' You can install them manually or run: edgible agent setup --auto-install\n'));
295
- // Ask if user wants to continue anyway
296
- const { continueAnyway } = await inquirer_1.default.prompt([{
297
- type: 'confirm',
298
- name: 'continueAnyway',
299
- message: 'Continue with installation anyway?',
300
- default: false
301
- }]);
302
- if (!continueAnyway) {
303
- console.log(chalk_1.default.gray('Installation cancelled.'));
304
- return;
316
+ if (noInteractive) {
317
+ console.log(chalk_1.default.yellow('Non-interactive: continuing anyway.\n'));
318
+ }
319
+ else {
320
+ // Ask if user wants to continue anyway
321
+ const { continueAnyway } = await inquirer_1.default.prompt([{
322
+ type: 'confirm',
323
+ name: 'continueAnyway',
324
+ message: 'Continue with installation anyway?',
325
+ default: false
326
+ }]);
327
+ if (!continueAnyway) {
328
+ console.log(chalk_1.default.gray('Installation cancelled.'));
329
+ return;
330
+ }
305
331
  }
306
332
  }
307
333
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+IzD"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmJzD"}
@@ -29,6 +29,10 @@ function setupAgentCommands(program) {
29
29
  .option('--type <type>', 'Installation type (systemd|launchd|windows-service)')
30
30
  .option('--dev', 'Run in development mode (foreground, no daemon)')
31
31
  .option('--local', 'Use local agent build from agent-v2/dist/ (development only)')
32
+ .option('--no-interactive', 'Non-interactive mode for CI/VMs: use config or --device-id/--device-password, skip prompts')
33
+ .option('--device-id <id>', 'Serving device ID (non-interactive); can use EDGIBLE_DEVICE_ID')
34
+ .option('--device-password <password>', 'Serving device password (non-interactive); can use EDGIBLE_DEVICE_PASSWORD')
35
+ .option('--auto-install-deps', 'Install missing dependencies (WireGuard, Caddy, etc.) without prompting')
32
36
  .action((0, command_wrapper_1.wrapCommand)(async (options) => {
33
37
  await (0, install_1.handleAgentInstall)(options, instances_1.logger, instances_1.configManager, instances_1.edgibleService, instances_1.authService, instances_1.localAgentManager);
34
38
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/helpers.ts"],"names":[],"mappings":"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"}
@@ -66,6 +66,7 @@ const chalk_1 = __importDefault(require("chalk"));
66
66
  const inquirer_1 = __importDefault(require("inquirer"));
67
67
  const child_process_1 = require("child_process");
68
68
  const os = __importStar(require("os"));
69
+ const run_as_user_1 = require("../../utils/run-as-user");
69
70
  const path = __importStar(require("path"));
70
71
  const fs = __importStar(require("fs"));
71
72
  const node_fetch_1 = __importDefault(require("node-fetch"));
@@ -447,6 +448,7 @@ async function setupPlatformIntegration(options) {
447
448
  const webUIResult = await createOpenWebUIApplication({
448
449
  ollamaUrl: ollamaUrl,
449
450
  deviceId: deviceId,
451
+ ollamaAppId: createdOllamaApp.id,
450
452
  configManager: instances_1.configManager,
451
453
  applicationService: instances_1.applicationService,
452
454
  gatewayService: instances_1.gatewayService,
@@ -524,10 +526,10 @@ async function installOllama() {
524
526
  });
525
527
  }
526
528
  else if (platform === 'darwin') {
527
- // macOS - check for Homebrew
529
+ // macOS - check for Homebrew; run as real user so brew installs under user not root (e.g. when CLI was started with sudo)
528
530
  try {
529
- (0, child_process_1.execSync)('brew --version', { encoding: 'utf8', timeout: 2000, stdio: 'ignore' });
530
- (0, child_process_1.execSync)('brew install ollama', {
531
+ (0, run_as_user_1.execAsRealUser)('brew --version', { encoding: 'utf8', timeout: 2000, stdio: 'ignore' });
532
+ (0, run_as_user_1.execAsRealUser)('brew install ollama', {
531
533
  encoding: 'utf8',
532
534
  stdio: 'inherit',
533
535
  });
@@ -1368,7 +1370,9 @@ async function createOllamaApplication(config) {
1368
1370
  };
1369
1371
  }
1370
1372
  /**
1371
- * Create Open WebUI application on Edgible platform
1373
+ * Create Open WebUI application on Edgible platform.
1374
+ * When ollamaAppId is provided, open-webui is created with a dependency on the ollama application
1375
+ * so it stays suspended until ollama is deployed (ADR-0004).
1372
1376
  */
1373
1377
  async function createOpenWebUIApplication(config) {
1374
1378
  // Always use the same device as Ollama (same device as agent)
@@ -1398,7 +1402,8 @@ async function createOpenWebUIApplication(config) {
1398
1402
  'isWorking': true,
1399
1403
  'deleteVolumesOnDeletion': true // Delete volumes when application is deleted
1400
1404
  },
1401
- requireOrgAuth: true // Enable authentication - X-Auth-Email header already passed by auth system
1405
+ requireOrgAuth: true, // Enable authentication - X-Auth-Email header already passed by auth system
1406
+ dependsOnApplicationIds: config.ollamaAppId ? [config.ollamaAppId] : undefined,
1402
1407
  });
1403
1408
  return {
1404
1409
  app: result,
@@ -1 +1 @@
1
- {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/commands/debug.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6lBzD"}
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/commands/debug.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkmBzD"}
@@ -58,7 +58,8 @@ function setupDebugCommands(program) {
58
58
  debugCommand
59
59
  .command('full-cycle')
60
60
  .description('Full debug cycle for customer issue troubleshooting')
61
- .action((0, command_wrapper_1.wrapCommand)(async () => {
61
+ .option('--local', 'Use local agent build from agent-v2/dist/ (development only)')
62
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
62
63
  if (!(0, sudo_checker_1.checkSudoPermissions)()) {
63
64
  console.log(chalk_1.default.redBright("Please run this command with administrator privileges (i.e. sudo)"));
64
65
  return;
@@ -120,10 +121,13 @@ function setupDebugCommands(program) {
120
121
  console.log(chalk_1.default.blue.bold('\n[Step 3/9] Installing Agent\n'));
121
122
  const platform = PlatformDetector_1.PlatformDetector.getPlatform();
122
123
  const installationType = platform === 'darwin' ? 'launchd' : 'systemd';
123
- await (0, install_1.handleAgentInstall)({ type: installationType, dev: false, local: false }, instances_1.logger, instances_1.configManager, instances_1.edgibleService, instances_1.authService, instances_1.localAgentManager);
124
+ if (options.local) {
125
+ console.log(chalk_1.default.cyan('Using local agent build from agent-v2/dist/\n'));
126
+ }
127
+ await (0, install_1.handleAgentInstall)({ type: installationType, dev: false, local: options.local || false }, instances_1.logger, instances_1.configManager, instances_1.edgibleService, instances_1.authService, instances_1.localAgentManager);
124
128
  debugSections.push({
125
129
  title: 'Agent Installation',
126
- content: `Agent installed successfully (${installationType} on ${platform})`
130
+ content: `Agent installed successfully (${installationType} on ${platform})${options.local ? ' [LOCAL BUILD]' : ''}`
127
131
  });
128
132
  // Step 4: Wait 2 minutes for startup
129
133
  console.log(chalk_1.default.blue.bold('\n[Step 4/9] Waiting 2 Minutes for Agent Startup\n'));
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Stack deploy command handler
3
+ */
4
+ import { DeployOptions } from '../../types/stack';
5
+ export declare function handleStackDeploy(options: DeployOptions): Promise<void>;
6
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/commands/stack/deploy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD7E"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * Stack deploy command handler
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleStackDeploy = handleStackDeploy;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const instances_1 = require("../../services/instances");
12
+ async function handleStackDeploy(options) {
13
+ const { stackService, logger } = (0, instances_1.getServiceInstances)();
14
+ try {
15
+ logger.info(`Deploying stack from: ${options.file}`);
16
+ if (options.dryRun) {
17
+ console.log(chalk_1.default.cyan('Running in dry-run mode (no changes will be made)\n'));
18
+ }
19
+ const result = await stackService.deployStack(options);
20
+ // Display results
21
+ console.log('\n' + chalk_1.default.bold('Deployment Results:'));
22
+ console.log(chalk_1.default.gray('─'.repeat(50)));
23
+ if (result.deployed.length > 0) {
24
+ console.log(chalk_1.default.green('\n✓ Successfully deployed:'));
25
+ for (const app of result.deployed) {
26
+ console.log(chalk_1.default.green(` - ${app.name}`));
27
+ if (app.urls && app.urls.length > 0) {
28
+ for (const url of app.urls) {
29
+ console.log(chalk_1.default.gray(` ${url}`));
30
+ }
31
+ }
32
+ }
33
+ }
34
+ if (result.failed.length > 0) {
35
+ console.log(chalk_1.default.red('\n✗ Failed to deploy:'));
36
+ for (const app of result.failed) {
37
+ console.log(chalk_1.default.red(` - ${app.name}: ${app.error}`));
38
+ }
39
+ }
40
+ if (result.skipped.length > 0) {
41
+ console.log(chalk_1.default.yellow('\n⊘ Skipped:'));
42
+ for (const appName of result.skipped) {
43
+ console.log(chalk_1.default.yellow(` - ${appName}`));
44
+ }
45
+ }
46
+ console.log(chalk_1.default.gray('\n' + '─'.repeat(50)));
47
+ console.log(chalk_1.default.bold(`Total: ${result.deployed.length} deployed, ${result.failed.length} failed, ${result.skipped.length} skipped`));
48
+ if (!result.success) {
49
+ process.exit(1);
50
+ }
51
+ }
52
+ catch (error) {
53
+ logger.error(`Deployment error: ${error instanceof Error ? error.message : 'Unknown error'}`);
54
+ console.log(chalk_1.default.red(`\n✗ Deployment failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
55
+ process.exit(1);
56
+ }
57
+ }
58
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Stack diff command handler
3
+ */
4
+ export declare function handleStackDiff(options: {
5
+ file: string;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/commands/stack/diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2D9E"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Stack diff command handler
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleStackDiff = handleStackDiff;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const instances_1 = require("../../services/instances");
12
+ async function handleStackDiff(options) {
13
+ const { stackService, logger } = (0, instances_1.getServiceInstances)();
14
+ try {
15
+ logger.info(`Computing diff for stack: ${options.file}`);
16
+ const diff = await stackService.diffStack(options.file);
17
+ console.log(chalk_1.default.bold('\nStack Differences:'));
18
+ console.log(chalk_1.default.gray('─'.repeat(50)));
19
+ let hasChanges = false;
20
+ if (diff.toCreate.length > 0) {
21
+ hasChanges = true;
22
+ console.log(chalk_1.default.green('\n+ Applications to create:'));
23
+ for (const app of diff.toCreate) {
24
+ console.log(chalk_1.default.green(` + ${app.name} (${app.subtype})`));
25
+ }
26
+ }
27
+ if (diff.toUpdate.length > 0) {
28
+ hasChanges = true;
29
+ console.log(chalk_1.default.yellow('\n~ Applications to update:'));
30
+ for (const app of diff.toUpdate) {
31
+ console.log(chalk_1.default.yellow(` ~ ${app.name}`));
32
+ for (const change of app.changes) {
33
+ console.log(chalk_1.default.gray(` ${change.field}: ${change.oldValue} → ${change.newValue}`));
34
+ }
35
+ }
36
+ }
37
+ if (diff.toDelete.length > 0) {
38
+ hasChanges = true;
39
+ console.log(chalk_1.default.red('\n- Applications to delete:'));
40
+ for (const app of diff.toDelete) {
41
+ console.log(chalk_1.default.red(` - ${app.name}`));
42
+ }
43
+ }
44
+ if (diff.unchanged.length > 0) {
45
+ console.log(chalk_1.default.gray('\n= Unchanged applications:'));
46
+ for (const appName of diff.unchanged) {
47
+ console.log(chalk_1.default.gray(` = ${appName}`));
48
+ }
49
+ }
50
+ console.log(chalk_1.default.gray('\n' + '─'.repeat(50)));
51
+ if (!hasChanges) {
52
+ console.log(chalk_1.default.green('No changes detected. Stack is up to date.'));
53
+ }
54
+ else {
55
+ console.log(chalk_1.default.bold(`Summary: ${diff.toCreate.length} to create, ${diff.toUpdate.length} to update, ${diff.toDelete.length} to delete`));
56
+ }
57
+ }
58
+ catch (error) {
59
+ logger.error(`Diff error: ${error instanceof Error ? error.message : 'Unknown error'}`);
60
+ console.log(chalk_1.default.red(`\n✗ Failed to compute diff: ${error instanceof Error ? error.message : 'Unknown error'}`));
61
+ process.exit(1);
62
+ }
63
+ }
64
+ //# sourceMappingURL=diff.js.map