@jacebenson/jsn 4.3.7-dev.22 → 4.3.7-dev.23

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacebenson/jsn",
3
- "version": "4.3.7-dev.22",
3
+ "version": "4.3.7-dev.23",
4
4
  "description": "A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3,7 +3,7 @@ import { confirmDelete, formatRecordForDisplay, getStringField, interactiveList,
3
3
  import { FormatAuto } from '../output.js';
4
4
  import { declareCapabilities } from '../capabilities.js';
5
5
  import { resolveRecord, unwrapSysId } from '../resolve-record.js';
6
- import { dockerComposeAvailable, installDockerMidServer, validateMidCredentials } from '../midserver-install.js';
6
+ import { detectDocker, installDockerMidServer, validateMidCredentials } from '../midserver-install.js';
7
7
 
8
8
  const AGENT_TABLE = 'ecc_agent';
9
9
  const QUEUE_TABLE = 'ecc_queue';
@@ -235,22 +235,31 @@ export function midserversCmd(wrap) {
235
235
  message: 'MID Server name:',
236
236
  validate: value => value.trim() ? true : 'MID Server name is required',
237
237
  })).trim();
238
- const dockerAvailable = dockerComposeAvailable();
238
+ const dockerStatus = detectDocker();
239
+ const dockerAvailable = dockerStatus.available;
239
240
  const installMethod = argv['install-method'] || await select({
240
241
  message: dockerAvailable
241
- ? 'Docker and Docker Compose detected. How should the MID Server be installed?'
242
- : 'Docker was not detected. How should the MID Server be installed?',
242
+ ? 'Docker and Docker Compose are ready. How should the MID Server be installed?'
243
+ : dockerStatus.installed && dockerStatus.compose
244
+ ? 'Docker is installed, but this user cannot access the Docker daemon. How should the MID Server be installed?'
245
+ : 'Docker was not detected. How should the MID Server be installed?',
243
246
  choices: dockerAvailable
244
247
  ? [
245
248
  { name: 'Docker (recommended)', value: 'docker' },
246
249
  { name: 'Direct install (not available yet)', value: 'direct' },
247
250
  ]
251
+ : dockerStatus.installed && dockerStatus.compose
252
+ ? [
253
+ { name: 'Fix Docker daemon access first', value: 'docker-unavailable' },
254
+ { name: 'Direct install (not available yet)', value: 'direct' },
255
+ ]
248
256
  : [
249
257
  { name: 'Install Docker first', value: 'install-docker' },
250
258
  { name: 'Direct install (not available yet)', value: 'direct' },
251
259
  ],
252
260
  });
253
261
  if (installMethod === 'direct') throw new Error('Direct MID Server installation is not implemented yet. Choose Docker.');
262
+ if (installMethod === 'docker-unavailable') throw new Error('Docker is installed, but this user cannot access the Docker daemon. Start Docker and grant this user access to /var/run/docker.sock, then run this command again.');
254
263
  if (installMethod === 'install-docker') throw new Error('Automatic Docker installation is not implemented yet. Install Docker and Compose, then run this command again.');
255
264
 
256
265
  const installation = await installDockerMidServer({
@@ -277,14 +286,36 @@ export function midserversCmd(wrap) {
277
286
  }),
278
287
  })
279
288
  .command({
280
- command: 'remove <identifier>',
289
+ command: 'remove [identifier]',
281
290
  aliases: ['delete'],
282
- describe: 'Remove a MID Server record',
291
+ describe: 'Remove a MID Server record (interactive when no identifier is given)',
283
292
  builder: (b) => b.option('force', { type: 'boolean', default: false, describe: 'Skip confirmation' }),
284
293
  handler: wrap(async (argv, app) => {
285
- const record = await resolveMidServer(app.sdk, argv.identifier);
294
+ let record;
295
+ if (argv.identifier) {
296
+ record = await resolveMidServer(app.sdk, argv.identifier);
297
+ } else {
298
+ if (!canPrompt() || app.output.getFormat() !== FormatAuto) {
299
+ throw new Error('An identifier is required outside an interactive terminal');
300
+ }
301
+ record = await interactiveList({
302
+ app,
303
+ table: AGENT_TABLE,
304
+ singular: 'MID Server',
305
+ columns: LIST_FIELDS,
306
+ limit: 50,
307
+ labelField: 'name',
308
+ message: 'Select a MID Server to remove',
309
+ formatLabel: (candidate) => {
310
+ const name = getStringField(candidate, 'name') || getStringField(candidate, 'sys_id');
311
+ const status = getStringField(candidate, 'status');
312
+ return status ? `${name} [${status}]` : name;
313
+ },
314
+ });
315
+ if (!record) return;
316
+ }
286
317
  const sysId = unwrapSysId(record);
287
- const name = getStringField(record, 'name') || argv.identifier;
318
+ const name = getStringField(record, 'name') || argv.identifier || sysId;
288
319
  await confirmDelete(app, argv, `Remove MID Server '${name}'`);
289
320
  await app.sdk.delete(AGENT_TABLE, sysId);
290
321
  app.ok({ name, sys_id: sysId, deleted: true }, { summary: `Removed MID Server '${name}'` });
@@ -63,14 +63,17 @@ export async function validateMidCredentials(instanceURL, username, password, fe
63
63
  return { releaseName };
64
64
  }
65
65
 
66
+ export function detectDocker(run = defaultRun) {
67
+ const status = { installed: false, compose: false, daemon: false, available: false };
68
+ try { run('docker', ['--version'], { stdio: 'ignore' }); status.installed = true; } catch { return status; }
69
+ try { run('docker', ['compose', 'version'], { stdio: 'ignore' }); status.compose = true; } catch { return status; }
70
+ try { run('docker', ['info'], { stdio: 'ignore' }); status.daemon = true; } catch { return status; }
71
+ status.available = true;
72
+ return status;
73
+ }
74
+
66
75
  export function dockerComposeAvailable(run = defaultRun) {
67
- try {
68
- run('docker', ['info'], { stdio: 'ignore' });
69
- run('docker', ['compose', 'version'], { stdio: 'ignore' });
70
- return true;
71
- } catch {
72
- return false;
73
- }
76
+ return detectDocker(run).available;
74
77
  }
75
78
 
76
79
  function composeFile({ serviceName }) {