unitup 0.1.4 → 0.2.0

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,7 +1,7 @@
1
1
  {
2
2
  "name": "unitup",
3
- "version": "0.1.4",
4
- "description": "Minimal, zero-dependency systemd-native service manager for any runtime, script, or executable",
3
+ "version": "0.2.0",
4
+ "description": "Minimal, zero-dependency cross-platform native service manager (systemd, launchd, Windows Services) for any runtime, script, or executable",
5
5
  "main": "src/index.js",
6
6
  "types": "./index.d.ts",
7
7
  "type": "module",
@@ -9,7 +9,7 @@
9
9
  "unitup": "bin/unitup.js"
10
10
  },
11
11
  "scripts": {
12
- "test": "node --test test/*.test.js",
12
+ "test": "node --test",
13
13
  "lint": "biome check .",
14
14
  "format": "biome format --write .",
15
15
  "check": "biome check ."
@@ -20,9 +20,15 @@
20
20
  },
21
21
  "keywords": [
22
22
  "systemd",
23
+ "launchd",
24
+ "windows-service",
25
+ "macos",
26
+ "windows",
27
+ "cross-platform",
23
28
  "service",
24
29
  "user-service",
25
30
  "systemctl",
31
+ "launchctl",
26
32
  "process-manager",
27
33
  "daemon-less",
28
34
  "multi-runtime",
package/src/cli.js CHANGED
@@ -1,46 +1,48 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs';
2
+ import path from 'node:path';
3
3
  import readline from 'node:readline';
4
4
  import { runDoctor } from './doctor.js';
5
+ import { getAdapter } from './platform/index.js';
6
+ import {
7
+ createSchedule,
8
+ disableSchedule,
9
+ enableSchedule,
10
+ getScheduleStatus,
11
+ listSchedules,
12
+ removeSchedule,
13
+ runSchedule
14
+ } from './schedule.js';
15
+ import { defaultManager } from './service/manager.js';
5
16
  import {
6
17
  addService,
7
- startService,
8
- stopService,
9
- restartService,
10
- removeService,
18
+ executeJournalctlMaintenance,
19
+ findNodeExecutable,
20
+ getAllServicesMemoryUsage,
21
+ getServiceFailures,
22
+ getServiceMemoryUsage,
11
23
  getServiceStatus,
12
24
  getServiceStatusRaw,
13
- listServices,
14
- runJournalctlLogs,
15
- isLinux,
16
- isSystemctlAvailable,
17
- findNodeExecutable,
18
25
  getServicesByGroup,
19
26
  inspectService,
20
- getServiceFailures,
27
+ isLinux,
28
+ isSystemctlAvailable,
29
+ listServices,
30
+ removeService,
31
+ restartService,
32
+ runJournalctlLogs,
21
33
  setServiceLimits,
22
- executeJournalctlMaintenance,
23
- getServiceMemoryUsage,
24
- getAllServicesMemoryUsage
34
+ startService,
35
+ stopService
25
36
  } from './systemd.js';
26
37
  import {
27
- createSchedule,
28
- listSchedules,
29
- getScheduleStatus,
30
- runSchedule,
31
- enableSchedule,
32
- disableSchedule,
33
- removeSchedule
34
- } from './schedule.js';
35
- import {
36
- sanitizeServiceName,
38
+ findProjectConfig,
37
39
  formatTable,
38
40
  readGlobalConfig,
39
- saveGlobalConfig,
40
- validateMemorySize,
41
- findProjectConfig,
42
41
  readProjectConfig,
43
- saveProjectConfig
42
+ sanitizeServiceName,
43
+ saveGlobalConfig,
44
+ saveProjectConfig,
45
+ validateMemorySize
44
46
  } from './utils.js';
45
47
 
46
48
  /**
@@ -75,6 +77,8 @@ export function parseArgs(argv) {
75
77
  help: false,
76
78
  version: false,
77
79
  force: false,
80
+ system: false,
81
+ verbose: false,
78
82
  memoryHigh: '',
79
83
  memoryMax: '',
80
84
  memorySwapMax: '',
@@ -112,6 +116,12 @@ export function parseArgs(argv) {
112
116
  } else if (arg === '-v' || arg === '--version') {
113
117
  result.flags.version = true;
114
118
  i++;
119
+ } else if (arg === '--verbose') {
120
+ result.flags.verbose = true;
121
+ i++;
122
+ } else if (arg === '--system') {
123
+ result.flags.system = true;
124
+ i++;
115
125
  } else if (arg === '--runtime') {
116
126
  result.flags.runtime = argv[i + 1] || '';
117
127
  i += 2;
@@ -191,10 +201,10 @@ export function parseArgs(argv) {
191
201
  result.flags.args.push(arg.slice(7));
192
202
  i++;
193
203
  } else if (arg === '--lines' || arg === '-n') {
194
- result.flags.lines = parseInt(argv[i + 1] || '100', 10);
204
+ result.flags.lines = Number.parseInt(argv[i + 1] || '100', 10);
195
205
  i += 2;
196
206
  } else if (arg.startsWith('--lines=')) {
197
- result.flags.lines = parseInt(arg.slice(8), 10);
207
+ result.flags.lines = Number.parseInt(arg.slice(8), 10);
198
208
  i++;
199
209
  } else if (arg === '--start') {
200
210
  result.flags.start = true;
@@ -352,7 +362,6 @@ export function parseArgs(argv) {
352
362
  }
353
363
  i++;
354
364
  } else {
355
- // Unknown flag, treat as positional or ignore
356
365
  i++;
357
366
  }
358
367
  }
@@ -362,29 +371,33 @@ export function parseArgs(argv) {
362
371
 
363
372
  export function printHelp() {
364
373
  console.log(`
365
- unitup - Minimal systemd user service wrapper for any executable & runtime
374
+ unitup - Minimal systemd user service wrapper & cross-platform service manager (Linux, macOS, Windows)
366
375
 
367
376
  Usage:
368
377
  unitup doctor Run system readiness and runtime check
369
378
  unitup init [script] Create local project config file (unitup.config.json)
370
- unitup add <script> [options] Add script or executable as systemd user service
379
+ unitup install / add <script> Install script or executable as native service (--dry-run)
371
380
  unitup start <name|@group> Start a service (--enable to enable on boot)
372
381
  unitup stop <name|@group> Stop a service
373
382
  unitup restart <name|@group> Restart a service
374
- unitup status <name|@group> Show status summary (--raw for full status)
375
- unitup logs <name|@group> Show journalctl logs (-f/--follow, -n/--lines N, -c/--cat)
383
+ unitup status <name|@group> Show status summary (--raw, --verbose)
384
+ unitup enable <name> Enable service on startup/boot
385
+ unitup disable <name> Disable service on startup/boot
386
+ unitup logs <name|@group> Show service logs (-f/--follow, -n/--lines N, -c/--cat)
376
387
  unitup inspect <name> View detailed app configuration and status
377
388
  unitup failures List all failed services with exit code & restarts
378
- unitup remove <name|@group> Stop, disable and delete a service
389
+ unitup uninstall / remove Stop, disable and delete a service (--force)
379
390
  unitup list / unitup ls List all services (--group <group>)
380
391
  unitup memory / unitup top Show memory usage for all apps or a specific app
381
392
  unitup config Manage global configuration (--default-memory 1G)
382
393
 
383
394
  Config Options:
384
395
  --config <path> Path to custom project config file (defaults to unitup.config.json)
396
+ --system Install as system-wide service (LaunchDaemons on macOS / root systemd)
397
+ --dry-run Display generated service configuration without installing
385
398
 
386
- Schedule Commands:
387
- unitup schedule <script> [options] Create a systemd timer schedule
399
+ Schedule Commands (systemd):
400
+ unitup schedule <script> [options] Create a timer schedule
388
401
  unitup schedules / unitup timers List all schedule timers
389
402
  unitup schedule-status <name> Show detailed schedule timer status
390
403
  unitup schedule-run <name> Manually run schedule service unit once
@@ -398,21 +411,13 @@ Memory Options:
398
411
  --memory-max <size> Hard memory limit (e.g. 512M, 1G)
399
412
  --default-memory [sz] Apply default memory limit (defaults to 1G)
400
413
 
401
- Schedule Options:
402
- --every <duration> Execution interval (e.g., 30s, 10m, 2h, 1d)
403
- --calendar <expr> Calendar expression (e.g., daily, "Mon..Fri 09:00")
404
- --on-boot <duration> Delay relative to system boot (e.g., 5m)
405
- --on-active <duration> Delay relative to timer activation
406
- --random-delay <dur> Random delay to prevent stampedes (e.g., 10m)
407
- --persistent Run immediately if a scheduled run was missed
408
- --start Enable and start timer immediately after creation
409
-
410
414
  Examples:
411
- unitup add server.js --runtime node --default-memory 1G
412
- unitup config --default-memory 1G
413
- unitup schedule cleanup.js --every 30m --default-memory --start
414
- unitup schedule backup.py --calendar daily --random-delay 10m --start
415
- unitup schedule report.js --calendar "Mon..Fri 09:00" --start
415
+ unitup install server.js --name api --start
416
+ unitup install ./app.js --dry-run
417
+ unitup start api
418
+ unitup status api --verbose
419
+ unitup logs api --follow
420
+ unitup uninstall api
416
421
  `);
417
422
  }
418
423
 
@@ -468,12 +473,12 @@ export async function runCli(argv = process.argv.slice(2)) {
468
473
  if (fs.existsSync(targetConfigPath) && !flags.force) {
469
474
  throw new Error(
470
475
  `Configuration file "${path.basename(targetConfigPath)}" already exists at ${targetConfigPath}.\n` +
471
- `Use --force (-f) to overwrite.`
476
+ `Use --force (-f) to overwrite.`
472
477
  );
473
478
  }
474
479
 
475
480
  const scriptArg = positionals[0];
476
- let scriptPath = scriptArg || '';
481
+ const scriptPath = scriptArg || '';
477
482
  let name = flags.name;
478
483
  if (!name) {
479
484
  if (scriptPath) {
@@ -521,6 +526,7 @@ export async function runCli(argv = process.argv.slice(2)) {
521
526
  break;
522
527
  }
523
528
 
529
+ case 'install':
524
530
  case 'add': {
525
531
  const targetCwd = flags.cwd ? path.resolve(process.cwd(), flags.cwd) : process.cwd();
526
532
  const configPath = flags.config ? path.resolve(targetCwd, flags.config) : findProjectConfig(targetCwd);
@@ -528,18 +534,23 @@ export async function runCli(argv = process.argv.slice(2)) {
528
534
 
529
535
  const scriptArg = positionals[0] || (projectCfg ? projectCfg.script : undefined);
530
536
  let name = flags.name || (projectCfg ? projectCfg.name : undefined);
531
- let cmdFlag = flags.command || (projectCfg ? projectCfg.command : undefined);
532
- let runtimeFlag = flags.runtime || (projectCfg ? projectCfg.runtime : undefined);
533
- let groupFlag = flags.group || (projectCfg ? projectCfg.group : undefined) || 'default';
534
- let restartFlag = flags.restart !== 'on-failure' ? flags.restart : ((projectCfg && projectCfg.restart) || 'on-failure');
535
- let envFileFlag = flags.envFile || (projectCfg ? projectCfg.envFile : undefined);
536
- let argsFlag = (flags.args && flags.args.length > 0) ? flags.args : ((projectCfg && projectCfg.args) || []);
537
- let runtimeArgsFlag = (flags.runtimeArgs && flags.runtimeArgs.length > 0) ? flags.runtimeArgs : ((projectCfg && projectCfg.runtimeArgs) || []);
538
- let memoryHighFlag = flags.memoryHigh || (projectCfg?.resources?.memoryHigh || projectCfg?.memoryHigh || '');
539
- let memoryMaxFlag = flags.memoryMax || (projectCfg?.resources?.memoryMax || projectCfg?.memoryMax || '');
540
- let memorySwapMaxFlag = flags.memorySwapMax || (projectCfg?.resources?.memorySwapMax || projectCfg?.memorySwapMax || '');
541
-
542
- let absScriptPath = scriptArg ? path.resolve(targetCwd, scriptArg) : undefined;
537
+ const cmdFlag = flags.command || (projectCfg ? projectCfg.command : undefined);
538
+ const runtimeFlag = flags.runtime || (projectCfg ? projectCfg.runtime : undefined);
539
+ const groupFlag = flags.group || (projectCfg ? projectCfg.group : undefined) || 'default';
540
+ const restartFlag =
541
+ flags.restart !== 'on-failure' ? flags.restart : (projectCfg && projectCfg.restart) || 'on-failure';
542
+ const envFileFlag = flags.envFile || (projectCfg ? projectCfg.envFile : undefined);
543
+ const argsFlag = flags.args && flags.args.length > 0 ? flags.args : (projectCfg && projectCfg.args) || [];
544
+ const runtimeArgsFlag =
545
+ flags.runtimeArgs && flags.runtimeArgs.length > 0
546
+ ? flags.runtimeArgs
547
+ : (projectCfg && projectCfg.runtimeArgs) || [];
548
+ const memoryHighFlag = flags.memoryHigh || projectCfg?.resources?.memoryHigh || projectCfg?.memoryHigh || '';
549
+ const memoryMaxFlag = flags.memoryMax || projectCfg?.resources?.memoryMax || projectCfg?.memoryMax || '';
550
+ const memorySwapMaxFlag =
551
+ flags.memorySwapMax || projectCfg?.resources?.memorySwapMax || projectCfg?.memorySwapMax || '';
552
+
553
+ const absScriptPath = scriptArg ? path.resolve(targetCwd, scriptArg) : undefined;
543
554
 
544
555
  if (flags.node) {
545
556
  const resolvedNode = await findNodeExecutable(flags.node);
@@ -573,7 +584,7 @@ export async function runCli(argv = process.argv.slice(2)) {
573
584
  }
574
585
  }
575
586
 
576
- const envObj = (projectCfg && projectCfg.env && typeof projectCfg.env === 'object') ? { ...projectCfg.env } : {};
587
+ const envObj = projectCfg && projectCfg.env && typeof projectCfg.env === 'object' ? { ...projectCfg.env } : {};
577
588
  for (const e of flags.env) {
578
589
  const idx = e.indexOf('=');
579
590
  if (idx !== -1) {
@@ -583,7 +594,7 @@ export async function runCli(argv = process.argv.slice(2)) {
583
594
  }
584
595
  }
585
596
 
586
- const res = await addService({
597
+ const installOptions = {
587
598
  name,
588
599
  group: groupFlag,
589
600
  script: absScriptPath,
@@ -597,14 +608,27 @@ export async function runCli(argv = process.argv.slice(2)) {
597
608
  restart: restartFlag,
598
609
  args: argsFlag,
599
610
  start: flags.start,
611
+ system: flags.system,
600
612
  memoryHigh: memoryHighFlag,
601
613
  memoryMax: memoryMaxFlag,
602
614
  memorySwapMax: memorySwapMaxFlag,
603
615
  defaultMemory: flags.defaultMemory,
604
616
  force: flags.force
605
- });
617
+ };
618
+
619
+ if (flags.dryRun) {
620
+ const generated = await defaultManager.generate(installOptions);
621
+ if (typeof generated === 'string') {
622
+ console.log(generated);
623
+ } else {
624
+ console.log(JSON.stringify(generated, null, 2));
625
+ }
626
+ break;
627
+ }
628
+
629
+ const res = await defaultManager.install(installOptions);
606
630
 
607
- console.log(`✓ Service "${res.name}" created at ${res.unitPath}`);
631
+ console.log(`✓ Service "${res.name}" created at ${res.unitPath || res.serviceName || res.name}`);
608
632
  if (flags.start) {
609
633
  console.log(`✓ Service "${res.name}" enabled and started.`);
610
634
  } else {
@@ -638,7 +662,7 @@ export async function runCli(argv = process.argv.slice(2)) {
638
662
  }
639
663
  const targetNames = await resolveTargetNames(nameArg);
640
664
  for (const name of targetNames) {
641
- await startService(name, flags.enable);
665
+ await defaultManager.start(name, { enable: flags.enable, system: flags.system });
642
666
  console.log(`✓ Service "${sanitizeServiceName(name)}" ${flags.enable ? 'enabled & ' : ''}started.`);
643
667
  }
644
668
  break;
@@ -651,7 +675,7 @@ export async function runCli(argv = process.argv.slice(2)) {
651
675
  }
652
676
  const targetNames = await resolveTargetNames(nameArg);
653
677
  for (const name of targetNames) {
654
- await stopService(name);
678
+ await defaultManager.stop(name, { system: flags.system });
655
679
  console.log(`✓ Service "${sanitizeServiceName(name)}" stopped.`);
656
680
  }
657
681
  break;
@@ -660,20 +684,51 @@ export async function runCli(argv = process.argv.slice(2)) {
660
684
  case 'restart': {
661
685
  const nameArg = positionals[0];
662
686
  if (!nameArg) {
663
- throw new Error('Service name or @group is required.\nExample: unitup restart api or unitup restart @myproject');
687
+ throw new Error(
688
+ 'Service name or @group is required.\nExample: unitup restart api or unitup restart @myproject'
689
+ );
664
690
  }
665
691
  const targetNames = await resolveTargetNames(nameArg);
666
692
  for (const name of targetNames) {
667
- await restartService(name);
693
+ await defaultManager.restart(name, { system: flags.system });
668
694
  console.log(`✓ Service "${sanitizeServiceName(name)}" restarted.`);
669
695
  }
670
696
  break;
671
697
  }
672
698
 
699
+ case 'enable': {
700
+ const nameArg = positionals[0];
701
+ if (!nameArg) {
702
+ throw new Error('Service name or @group is required.\nExample: unitup enable api');
703
+ }
704
+ const targetNames = await resolveTargetNames(nameArg);
705
+ for (const name of targetNames) {
706
+ await defaultManager.enable(name, { system: flags.system });
707
+ console.log(`✓ Service "${sanitizeServiceName(name)}" enabled on startup.`);
708
+ }
709
+ break;
710
+ }
711
+
712
+ case 'disable': {
713
+ const nameArg = positionals[0];
714
+ if (!nameArg) {
715
+ throw new Error('Service name or @group is required.\nExample: unitup disable api');
716
+ }
717
+ const targetNames = await resolveTargetNames(nameArg);
718
+ for (const name of targetNames) {
719
+ await defaultManager.disable(name, { system: flags.system });
720
+ console.log(`✓ Service "${sanitizeServiceName(name)}" disabled on startup.`);
721
+ }
722
+ break;
723
+ }
724
+
725
+ case 'ps':
673
726
  case 'status': {
674
727
  const nameArg = positionals[0];
675
728
  if (!nameArg) {
676
- throw new Error('Service name or @group is required.\nExample: unitup status api or unitup status @myproject');
729
+ throw new Error(
730
+ 'Service name or @group is required.\nExample: unitup status api or unitup status @myproject'
731
+ );
677
732
  }
678
733
 
679
734
  const targetNames = await resolveTargetNames(nameArg);
@@ -682,25 +737,31 @@ export async function runCli(argv = process.argv.slice(2)) {
682
737
  const raw = await getServiceStatusRaw(name);
683
738
  console.log(raw);
684
739
  } else {
685
- const status = await getServiceStatus(name);
740
+ const status = await defaultManager.status(name, { system: flags.system });
686
741
  console.log(`${status.name}\n`);
687
- console.log(`Status: ${status.status}`);
742
+ console.log(`Status: ${status.status || status.state}`);
688
743
  console.log(`PID: ${status.pid}`);
689
744
  console.log(`Started: ${status.started}`);
690
745
  console.log(`Restarts: ${status.restarts}`);
691
746
  console.log(`Command: ${status.command}`);
692
747
  console.log(`Arguments: ${status.arguments}`);
693
748
  console.log(`Working directory: ${status.cwd}`);
694
- console.log(`Memory: ${status.memory}`);
695
- console.log(`Memory Peak: ${status.memoryPeak}`);
696
- console.log(`Memory High: ${status.memoryHigh}`);
697
- console.log(`Memory Max: ${status.memoryMax}`);
698
- console.log(`Swap Max: ${status.memorySwapMax}`);
749
+ if (status.memory) console.log(`Memory: ${status.memory}`);
750
+ if (status.memoryPeak) console.log(`Memory Peak: ${status.memoryPeak}`);
751
+ if (status.memoryHigh) console.log(`Memory High: ${status.memoryHigh}`);
752
+ if (status.memoryMax) console.log(`Memory Max: ${status.memoryMax}`);
753
+ if (status.memorySwapMax) console.log(`Swap Max: ${status.memorySwapMax}`);
754
+ if (flags.verbose) {
755
+ console.log(`Platform: ${status.platform}`);
756
+ console.log(`Manager: ${status.manager}`);
757
+ if (status.unitPath) console.log(`Unit Path: ${status.unitPath}`);
758
+ }
699
759
  }
700
760
  }
701
761
  break;
702
762
  }
703
763
 
764
+ case 'log':
704
765
  case 'logs': {
705
766
  const nameArg = positionals[0];
706
767
  if (!nameArg) {
@@ -712,7 +773,7 @@ export async function runCli(argv = process.argv.slice(2)) {
712
773
  if (targetNames.length > 1) {
713
774
  console.log(`=== Logs for ${name} ===`);
714
775
  }
715
- const output = await runJournalctlLogs(name, {
776
+ const output = await defaultManager.logs(name, {
716
777
  follow: flags.follow,
717
778
  lines: flags.lines,
718
779
  cat: flags.cat,
@@ -723,9 +784,24 @@ export async function runCli(argv = process.argv.slice(2)) {
723
784
  grep: flags.grep,
724
785
  boot: flags.boot,
725
786
  json: flags.json,
726
- diskUsage: flags.diskUsage
787
+ diskUsage: flags.diskUsage,
788
+ system: flags.system
727
789
  });
728
- if (typeof output === 'string') {
790
+ if (output && typeof output.on === 'function') {
791
+ await new Promise((resolve) => {
792
+ const cleanup = () => {
793
+ if (output.stop) output.stop();
794
+ resolve();
795
+ };
796
+ process.on('SIGINT', cleanup);
797
+ process.on('SIGTERM', cleanup);
798
+ output.on('close', resolve);
799
+ output.on('error', (err) => {
800
+ console.error(err.message);
801
+ cleanup();
802
+ });
803
+ });
804
+ } else if (typeof output === 'string') {
729
805
  console.log(output);
730
806
  }
731
807
  }
@@ -735,16 +811,21 @@ export async function runCli(argv = process.argv.slice(2)) {
735
811
  case 'journal': {
736
812
  const action = positionals[0];
737
813
  if (!action) {
738
- throw new Error('Journal action is required (disk-usage, rotate, vacuum).\nExample: unitup journal vacuum --size 500M');
814
+ throw new Error(
815
+ 'Journal action is required (disk-usage, rotate, vacuum).\nExample: unitup journal vacuum --size 500M'
816
+ );
739
817
  }
740
818
 
741
819
  if (action === 'vacuum' && !flags.yes && !flags.dryRun) {
742
820
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
743
821
  const answer = await new Promise((resolve) => {
744
- rl.question('This operation affects archived journal logs system-wide,\nnot only services managed by unitup.\n\nContinue? [y/N] ', (ans) => {
745
- rl.close();
746
- resolve(ans.trim());
747
- });
822
+ rl.question(
823
+ 'This operation affects archived journal logs system-wide,\nnot only services managed by unitup.\n\nContinue? [y/N] ',
824
+ (ans) => {
825
+ rl.close();
826
+ resolve(ans.trim());
827
+ }
828
+ );
748
829
  });
749
830
  if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
750
831
  console.log('Aborted.');
@@ -763,14 +844,19 @@ export async function runCli(argv = process.argv.slice(2)) {
763
844
  break;
764
845
  }
765
846
 
847
+ case 'uninstall':
848
+ case 'rm':
849
+ case 'delete':
766
850
  case 'remove': {
767
851
  const nameArg = positionals[0];
768
852
  if (!nameArg) {
769
- throw new Error('Service name or @group is required.\nExample: unitup remove api or unitup remove @myproject');
853
+ throw new Error(
854
+ 'Service name or @group is required.\nExample: unitup remove api or unitup remove @myproject'
855
+ );
770
856
  }
771
857
  const targetNames = await resolveTargetNames(nameArg);
772
858
  for (const name of targetNames) {
773
- await removeService(name, { force: flags.force });
859
+ await defaultManager.uninstall(name, { force: flags.force, system: flags.system });
774
860
  console.log(`✓ Service "${sanitizeServiceName(name)}" removed.`);
775
861
  }
776
862
  break;
@@ -778,7 +864,7 @@ export async function runCli(argv = process.argv.slice(2)) {
778
864
 
779
865
  case 'ls':
780
866
  case 'list': {
781
- const services = await listServices({ group: flags.group });
867
+ const services = await defaultManager.list({ group: flags.group });
782
868
  if (services.length === 0) {
783
869
  if (flags.group) {
784
870
  console.log(`No services found in group "${flags.group}".`);
@@ -804,7 +890,7 @@ export async function runCli(argv = process.argv.slice(2)) {
804
890
  if (!nameArg) {
805
891
  throw new Error('Service name is required.\nExample: unitup inspect api');
806
892
  }
807
- const info = await inspectService(nameArg);
893
+ const info = await defaultManager.inspect(nameArg, { system: flags.system });
808
894
  console.log(`Name: ${info.name}`);
809
895
  console.log(`Runtime: ${info.runtime}`);
810
896
  console.log(`Group: ${info.group}`);
@@ -812,17 +898,17 @@ export async function runCli(argv = process.argv.slice(2)) {
812
898
  console.log(`Command: ${info.command}`);
813
899
  console.log(`Arguments: ${info.arguments}`);
814
900
  console.log(`Working directory: ${info.cwd}`);
815
- console.log(`Unit: ${info.unit}`);
816
- console.log(`Memory: ${info.memory}`);
817
- console.log(`Memory Peak: ${info.memoryPeak}`);
818
- console.log(`Memory High: ${info.memoryHigh}`);
819
- console.log(`Memory Max: ${info.memoryMax}`);
820
- console.log(`Swap Max: ${info.memorySwapMax}`);
901
+ if (info.unit || info.unitFile) console.log(`Unit: ${info.unit || info.unitFile}`);
902
+ if (info.memory) console.log(`Memory: ${info.memory}`);
903
+ if (info.memoryPeak) console.log(`Memory Peak: ${info.memoryPeak}`);
904
+ if (info.memoryHigh) console.log(`Memory High: ${info.memoryHigh}`);
905
+ if (info.memoryMax) console.log(`Memory Max: ${info.memoryMax}`);
906
+ if (info.memorySwapMax) console.log(`Swap Max: ${info.memorySwapMax}`);
821
907
  break;
822
908
  }
823
909
 
824
910
  case 'failures': {
825
- const failures = await getServiceFailures();
911
+ const failures = await defaultManager.failures();
826
912
  if (failures.length === 0) {
827
913
  console.log('✓ No failed services.');
828
914
  break;