movehat 0.1.1 → 0.1.2

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 (71) hide show
  1. package/dist/commands/compile.d.ts +13 -0
  2. package/dist/commands/compile.d.ts.map +1 -1
  3. package/dist/commands/compile.js +31 -11
  4. package/dist/commands/compile.js.map +1 -1
  5. package/dist/commands/fork/create.d.ts +20 -1
  6. package/dist/commands/fork/create.d.ts.map +1 -1
  7. package/dist/commands/fork/create.js +54 -20
  8. package/dist/commands/fork/create.js.map +1 -1
  9. package/dist/commands/fork/list.d.ts +12 -1
  10. package/dist/commands/fork/list.d.ts.map +1 -1
  11. package/dist/commands/fork/list.js +50 -22
  12. package/dist/commands/fork/list.js.map +1 -1
  13. package/dist/commands/init.d.ts +19 -0
  14. package/dist/commands/init.d.ts.map +1 -1
  15. package/dist/commands/init.js +64 -29
  16. package/dist/commands/init.js.map +1 -1
  17. package/dist/commands/update.d.ts +11 -1
  18. package/dist/commands/update.d.ts.map +1 -1
  19. package/dist/commands/update.js +44 -18
  20. package/dist/commands/update.js.map +1 -1
  21. package/dist/helpers/banner.d.ts +17 -0
  22. package/dist/helpers/banner.d.ts.map +1 -1
  23. package/dist/helpers/banner.js +38 -23
  24. package/dist/helpers/banner.js.map +1 -1
  25. package/dist/helpers/version-check.d.ts +12 -1
  26. package/dist/helpers/version-check.d.ts.map +1 -1
  27. package/dist/helpers/version-check.js +17 -7
  28. package/dist/helpers/version-check.js.map +1 -1
  29. package/dist/ui/colors.d.ts +77 -0
  30. package/dist/ui/colors.d.ts.map +1 -0
  31. package/dist/ui/colors.js +121 -0
  32. package/dist/ui/colors.js.map +1 -0
  33. package/dist/ui/formatters.d.ts +171 -0
  34. package/dist/ui/formatters.d.ts.map +1 -0
  35. package/dist/ui/formatters.js +186 -0
  36. package/dist/ui/formatters.js.map +1 -0
  37. package/dist/ui/index.d.ts +58 -0
  38. package/dist/ui/index.d.ts.map +1 -0
  39. package/dist/ui/index.js +60 -0
  40. package/dist/ui/index.js.map +1 -0
  41. package/dist/ui/logger.d.ts +160 -0
  42. package/dist/ui/logger.d.ts.map +1 -0
  43. package/dist/ui/logger.js +206 -0
  44. package/dist/ui/logger.js.map +1 -0
  45. package/dist/ui/spinner.d.ts +106 -0
  46. package/dist/ui/spinner.d.ts.map +1 -0
  47. package/dist/ui/spinner.js +120 -0
  48. package/dist/ui/spinner.js.map +1 -0
  49. package/dist/ui/symbols.d.ts +50 -0
  50. package/dist/ui/symbols.d.ts.map +1 -0
  51. package/dist/ui/symbols.js +64 -0
  52. package/dist/ui/symbols.js.map +1 -0
  53. package/dist/ui/table.d.ts +67 -0
  54. package/dist/ui/table.d.ts.map +1 -0
  55. package/dist/ui/table.js +143 -0
  56. package/dist/ui/table.js.map +1 -0
  57. package/package.json +8 -1
  58. package/src/commands/compile.ts +32 -11
  59. package/src/commands/fork/create.ts +59 -20
  60. package/src/commands/fork/list.ts +52 -22
  61. package/src/commands/init.ts +111 -74
  62. package/src/commands/update.ts +52 -19
  63. package/src/helpers/banner.ts +45 -29
  64. package/src/helpers/version-check.ts +20 -8
  65. package/src/ui/colors.ts +141 -0
  66. package/src/ui/formatters.ts +246 -0
  67. package/src/ui/index.ts +62 -0
  68. package/src/ui/logger.ts +226 -0
  69. package/src/ui/spinner.ts +171 -0
  70. package/src/ui/symbols.ts +74 -0
  71. package/src/ui/table.ts +191 -0
@@ -0,0 +1,143 @@
1
+ import Table from 'cli-table3';
2
+ import { shouldUseColor, colors } from './colors.js';
3
+ /**
4
+ * Get preset configuration for table styling
5
+ * Automatically respects color settings (NO_COLOR, TTY)
6
+ *
7
+ * @param preset - Preset name
8
+ * @returns Partial cli-table3 configuration
9
+ */
10
+ const getPresetConfig = (preset) => {
11
+ const hasColor = shouldUseColor();
12
+ const presets = {
13
+ /**
14
+ * Default preset - Full borders with colors
15
+ * Best for: Complex tables with multiple columns
16
+ */
17
+ default: {
18
+ chars: {
19
+ 'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐',
20
+ 'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '└', 'bottom-right': '┘',
21
+ 'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
22
+ 'right': '│', 'right-mid': '┤', 'middle': '│',
23
+ },
24
+ style: {
25
+ head: hasColor ? ['cyan'] : [],
26
+ border: hasColor ? ['gray'] : [],
27
+ },
28
+ },
29
+ /**
30
+ * Compact preset - Minimal borders, max readability
31
+ * Best for: Fork list and similar data displays
32
+ */
33
+ compact: {
34
+ chars: {
35
+ 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '',
36
+ 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '',
37
+ 'left': '', 'left-mid': '', 'mid': '', 'mid-mid': '',
38
+ 'right': '', 'right-mid': '', 'middle': ' │ ',
39
+ },
40
+ style: {
41
+ head: hasColor ? ['cyan', 'bold'] : [],
42
+ border: [],
43
+ },
44
+ },
45
+ /**
46
+ * Markdown preset - Markdown-compatible table format
47
+ * Best for: Copy-paste to documentation
48
+ */
49
+ markdown: {
50
+ chars: {
51
+ 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '',
52
+ 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '',
53
+ 'left': '|', 'left-mid': '', 'mid': '', 'mid-mid': '',
54
+ 'right': '|', 'right-mid': '', 'middle': '|',
55
+ },
56
+ style: {
57
+ head: hasColor ? ['cyan'] : [],
58
+ border: [],
59
+ },
60
+ },
61
+ /**
62
+ * Borderless preset - Clean, minimal appearance
63
+ * Best for: Key-value displays and metadata
64
+ */
65
+ borderless: {
66
+ chars: {
67
+ 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '',
68
+ 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '',
69
+ 'left': '', 'left-mid': '', 'mid': '', 'mid-mid': '',
70
+ 'right': '', 'right-mid': '', 'middle': ' ',
71
+ },
72
+ style: {
73
+ head: hasColor ? ['cyan', 'bold'] : [],
74
+ border: [],
75
+ },
76
+ },
77
+ };
78
+ return presets[preset];
79
+ };
80
+ /**
81
+ * Create a table with preset configuration
82
+ * Wrapper around cli-table3 with Movehat-specific styling
83
+ *
84
+ * @param config - Table configuration
85
+ * @returns cli-table3 Table instance
86
+ *
87
+ * @example
88
+ * const table = createTable({
89
+ * head: ['Name', 'Network', 'Chain ID', 'Accounts'],
90
+ * preset: 'compact'
91
+ * });
92
+ *
93
+ * table.push(['testnet-fork', 'testnet', '126', '5']);
94
+ * table.push(['mainnet-fork', 'mainnet', '1', '3']);
95
+ *
96
+ * console.log(table.toString());
97
+ */
98
+ export const createTable = (config = {}) => {
99
+ const { head, preset = 'default', colWidths, colAligns, style = {}, } = config;
100
+ const presetConfig = getPresetConfig(preset);
101
+ const tableConfig = {
102
+ ...presetConfig,
103
+ style: {
104
+ ...presetConfig.style,
105
+ ...style,
106
+ },
107
+ };
108
+ // Only add optional properties if they are defined
109
+ if (head)
110
+ tableConfig.head = head;
111
+ if (colWidths)
112
+ tableConfig.colWidths = colWidths;
113
+ if (colAligns)
114
+ tableConfig.colAligns = colAligns;
115
+ return new Table(tableConfig);
116
+ };
117
+ /**
118
+ * Create a simple key-value table
119
+ * Perfect for displaying metadata and configuration
120
+ *
121
+ * @param data - Object with key-value pairs
122
+ * @param preset - Table preset to use (default: 'borderless')
123
+ * @returns cli-table3 Table instance ready for display
124
+ *
125
+ * @example
126
+ * const metadata = {
127
+ * 'Chain ID': '126',
128
+ * 'Network': 'testnet',
129
+ * 'Ledger Version': '12345',
130
+ * 'Created At': new Date().toLocaleString()
131
+ * };
132
+ *
133
+ * const table = createKVTable(metadata);
134
+ * console.log(table.toString());
135
+ */
136
+ export const createKVTable = (data, preset = 'borderless') => {
137
+ const table = createTable({ preset });
138
+ for (const [key, value] of Object.entries(data)) {
139
+ table.push([colors.dim(key), String(value)]);
140
+ }
141
+ return table;
142
+ };
143
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/ui/table.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "movehat",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "Hardhat-like development framework for Movement L1 and Aptos Move smart contracts",
6
6
  "bin": {
@@ -49,11 +49,18 @@
49
49
  ],
50
50
  "author": "Gilberts Ahumada",
51
51
  "license": "MIT",
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ },
52
55
  "dependencies": {
53
56
  "@aptos-labs/ts-sdk": "^5.1.5",
57
+ "cli-table3": "^0.6.5",
54
58
  "commander": "^14.0.2",
55
59
  "dotenv": "^17.2.3",
60
+ "figures": "^6.1.0",
56
61
  "js-yaml": "^4.1.1",
62
+ "ora": "^9.0.0",
63
+ "picocolors": "^1.1.1",
57
64
  "prompts": "^2.4.2",
58
65
  "tsx": "^4.7.0"
59
66
  },
@@ -3,6 +3,7 @@ import path from "path";
3
3
  import { exec } from "child_process";
4
4
  import { loadUserConfig } from "../core/config.js";
5
5
  import { validateAndEscapePath, escapeShellArg } from "../core/shell.js";
6
+ import { logger } from "../ui/index.js";
6
7
 
7
8
  /**
8
9
  * Recursively find all .move files in a directory
@@ -84,18 +85,33 @@ function run(command: string, cwd: string) {
84
85
  });
85
86
  }
86
87
 
88
+ /**
89
+ * Compile Move smart contracts using the Movement CLI
90
+ *
91
+ * This command:
92
+ * - Detects named addresses used in Move modules
93
+ * - Merges auto-detected addresses with user-configured addresses
94
+ * - Auto-assigns development addresses (0xcafe) for missing addresses
95
+ * - Executes `movement move build` with proper named address mappings
96
+ *
97
+ * @example
98
+ * // Compile contracts in default ./move directory
99
+ * await compileCommand();
100
+ */
87
101
  export default async function compileCommand() {
88
102
  try {
89
103
  // Compile is network-independent - only uses global config
90
104
  const userConfig = await loadUserConfig();
91
105
 
92
- console.log("Compiling Move contracts...");
106
+ logger.newline();
107
+ logger.info('Compiling Move contracts...');
93
108
 
94
109
  const moveDir = path.resolve(process.cwd(), userConfig.moveDir || "./move");
95
110
  if (!fs.existsSync(moveDir)) {
96
- console.error(`Move directory not found: ${moveDir}`);
97
- console.error(` Update movehat.config.ts -> moveDir`);
98
- return;
111
+ logger.error(`Move directory not found: ${moveDir}`);
112
+ logger.plain(` Update movehat.config.ts -> moveDir`);
113
+ logger.newline();
114
+ process.exit(1);
99
115
  }
100
116
 
101
117
  // Validate and escape to prevent command injection
@@ -148,22 +164,27 @@ export default async function compileCommand() {
148
164
 
149
165
  const command = `movement move build --package-dir ${safeMoveDir} ${namedAddressesArg}`.trim();
150
166
 
151
- console.log(` Move directory: ${moveDir}`);
167
+ logger.kv('Move directory', moveDir, 2);
152
168
  if (detectedAddresses.size > 0) {
153
- console.log(` Detected addresses: ${Array.from(detectedAddresses).join(", ")}`);
169
+ logger.kv('Detected addresses', Array.from(detectedAddresses).join(", "), 2);
154
170
  }
155
171
  if (Object.keys(userConfig.namedAddresses ?? {}).length > 0) {
156
- console.log(` Configured addresses: ${Object.keys(userConfig.namedAddresses!).join(", ")}`);
172
+ logger.kv('Configured addresses', Object.keys(userConfig.namedAddresses!).join(", "), 2);
157
173
  }
158
174
  if (autoAssignedAddresses.length > 0) {
159
- console.log(` Auto-assigned dev address (0xcafe): ${autoAssignedAddresses.join(", ")}`);
175
+ logger.kv('Auto-assigned (0xcafe)', autoAssignedAddresses.join(", "), 2);
160
176
  }
161
- console.log();
177
+ logger.newline();
162
178
 
163
179
  await run(command, moveDir);
164
- console.log("Compilation finished successfully.");
180
+
181
+ logger.newline();
182
+ logger.success('Compilation finished successfully');
183
+ logger.newline();
165
184
  } catch (err: any) {
166
- console.error("Compilation failed:", err.message ?? err);
185
+ logger.newline();
186
+ logger.error(`Compilation failed: ${err.message ?? err}`);
187
+ logger.newline();
167
188
  process.exit(1);
168
189
  }
169
190
  }
@@ -3,6 +3,7 @@ import { existsSync } from 'fs';
3
3
  import prompts from 'prompts';
4
4
  import { loadUserConfig, resolveNetworkConfig } from '../../core/config.js';
5
5
  import { ForkManager } from '../../fork/manager.js';
6
+ import { logger, withSpinner, createKVTable, formatCommand } from '../../ui/index.js';
6
7
 
7
8
  interface ForkCreateOptions {
8
9
  network?: string;
@@ -11,7 +12,26 @@ interface ForkCreateOptions {
11
12
  }
12
13
 
13
14
  /**
14
- * Fork create command: Create a local fork of a Movement/Aptos network
15
+ * Create a local fork of a Movement/Aptos network
16
+ *
17
+ * This command:
18
+ * - Connects to the specified network RPC endpoint
19
+ * - Downloads blockchain state (accounts, modules, resources)
20
+ * - Creates a local fork database for testing
21
+ * - Displays fork metadata (chain ID, ledger version, block height, epoch)
22
+ *
23
+ * @param options - Fork creation options
24
+ * @param options.network - Network to fork from (e.g., 'testnet', 'mainnet')
25
+ * @param options.path - Custom path to store fork data
26
+ * @param options.name - Custom name for the fork
27
+ *
28
+ * @example
29
+ * // Fork testnet
30
+ * await forkCreateCommand({ network: 'testnet' });
31
+ *
32
+ * @example
33
+ * // Fork with custom name
34
+ * await forkCreateCommand({ network: 'testnet', name: 'my-fork' });
15
35
  */
16
36
  export default async function forkCreateCommand(options: ForkCreateOptions = {}) {
17
37
  try {
@@ -24,9 +44,11 @@ export default async function forkCreateCommand(options: ForkCreateOptions = {})
24
44
  const forkName = options.name || `${networkName}-fork`;
25
45
  const forkPath = options.path || join(process.cwd(), '.movehat', 'forks', forkName);
26
46
 
27
- console.log(`\n📦 Creating fork of ${networkName}`);
28
- console.log(` Network: ${networkConfig.rpc}`);
29
- console.log(` Fork path: ${forkPath}`);
47
+ logger.newline();
48
+ logger.info(`Creating fork of ${networkName}`);
49
+ logger.kv('Network', networkConfig.rpc, 2);
50
+ logger.kv('Fork path', forkPath, 2);
51
+ logger.newline();
30
52
 
31
53
  // Check if fork already exists
32
54
  if (existsSync(forkPath)) {
@@ -38,7 +60,7 @@ export default async function forkCreateCommand(options: ForkCreateOptions = {})
38
60
  });
39
61
 
40
62
  if (!overwrite) {
41
- console.log('Fork creation cancelled');
63
+ logger.warning('Fork creation cancelled');
42
64
  return;
43
65
  }
44
66
  }
@@ -46,25 +68,42 @@ export default async function forkCreateCommand(options: ForkCreateOptions = {})
46
68
  // Create fork manager
47
69
  const forkManager = new ForkManager(forkPath);
48
70
 
49
- // Initialize fork
50
- console.log(`\n⚙️ Initializing fork...`);
51
- await forkManager.initialize(networkConfig.rpc, networkName);
71
+ // Initialize fork with spinner
72
+ const metadata = await withSpinner(
73
+ 'Initializing fork...',
74
+ async () => {
75
+ await forkManager.initialize(networkConfig.rpc, networkName);
76
+ return forkManager.getMetadata();
77
+ },
78
+ 'Fork initialized successfully!'
79
+ );
52
80
 
53
- const metadata = forkManager.getMetadata();
81
+ // Show fork details
82
+ logger.newline();
83
+ logger.success('Fork created successfully!');
84
+ logger.newline();
54
85
 
55
- console.log(`\n✅ Fork created successfully!\n`);
56
- console.log(`Fork Details:`);
57
- console.log(` Chain ID: ${metadata.chainId}`);
58
- console.log(` Ledger Version: ${metadata.ledgerVersion}`);
59
- console.log(` Block Height: ${metadata.blockHeight}`);
60
- console.log(` Epoch: ${metadata.epoch}`);
61
- console.log(`\nUsage:`);
62
- console.log(` movehat fork view-resource --fork ${forkPath} --account <ADDRESS> --resource <TYPE>`);
63
- console.log(` movehat fork fund --fork ${forkPath} --account <ADDRESS> --amount <AMOUNT>`);
64
- console.log(` movehat fork list\n`);
86
+ logger.section('Fork Details');
87
+ const detailsTable = createKVTable({
88
+ 'Chain ID': metadata.chainId.toString(),
89
+ 'Ledger Version': metadata.ledgerVersion,
90
+ 'Block Height': metadata.blockHeight,
91
+ 'Epoch': metadata.epoch
92
+ });
93
+ console.log(detailsTable.toString());
94
+ logger.newline();
95
+
96
+ // Usage examples
97
+ logger.section('Usage');
98
+ logger.item(formatCommand(`movehat fork view-resource --fork ${forkPath} --account <ADDRESS> --resource <TYPE>`), 2);
99
+ logger.item(formatCommand(`movehat fork fund --fork ${forkPath} --account <ADDRESS> --amount <AMOUNT>`), 2);
100
+ logger.item(formatCommand('movehat fork list'), 2);
101
+ logger.newline();
65
102
 
66
103
  } catch (error: any) {
67
- console.error(`\n❌ Error: ${error.message}\n`);
104
+ logger.newline();
105
+ logger.error(`Error: ${error.message}`);
106
+ logger.newline();
68
107
  process.exit(1);
69
108
  }
70
109
  }
@@ -1,18 +1,33 @@
1
1
  import { join } from 'path';
2
2
  import { existsSync, readdirSync, statSync } from 'fs';
3
3
  import { ForkStorage } from '../../fork/storage.js';
4
+ import { logger, createTable, formatCommand } from '../../ui/index.js';
4
5
 
5
6
  /**
6
- * Fork list command: List all available forks
7
+ * List all available local forks
8
+ *
9
+ * Displays forks in a formatted table showing:
10
+ * - Fork name
11
+ * - Network (testnet, mainnet, etc.)
12
+ * - Chain ID
13
+ * - Number of accounts
14
+ * - Creation timestamp
15
+ *
16
+ * @example
17
+ * // List all forks
18
+ * await forkListCommand();
7
19
  */
8
20
  export default async function forkListCommand() {
9
21
  try {
10
22
  const forksDir = join(process.cwd(), '.movehat', 'forks');
11
23
 
12
24
  if (!existsSync(forksDir)) {
13
- console.log('\n📂 No forks found\n');
14
- console.log('Create a fork with:');
15
- console.log(' movehat fork create --network testnet\n');
25
+ logger.newline();
26
+ logger.info('No forks found');
27
+ logger.newline();
28
+ logger.plain('Create a fork with:');
29
+ logger.item(formatCommand('movehat fork create --network testnet'), 2);
30
+ logger.newline();
16
31
  return;
17
32
  }
18
33
 
@@ -23,11 +38,22 @@ export default async function forkListCommand() {
23
38
  });
24
39
 
25
40
  if (forkDirs.length === 0) {
26
- console.log('\n📂 No forks found\n');
41
+ logger.newline();
42
+ logger.info('No forks found');
43
+ logger.newline();
27
44
  return;
28
45
  }
29
46
 
30
- console.log(`\n📂 Found ${forkDirs.length} fork(s):\n`);
47
+ logger.newline();
48
+ logger.info(`Found ${forkDirs.length} fork(s)`);
49
+ logger.newline();
50
+
51
+ // Create table for forks
52
+ const table = createTable({
53
+ head: ['Name', 'Network', 'Chain ID', 'Accounts', 'Created'],
54
+ preset: 'default',
55
+ colWidths: [20, 15, 12, 12, 25]
56
+ });
31
57
 
32
58
  for (const forkDir of forkDirs) {
33
59
  const forkPath = join(forksDir, forkDir);
@@ -38,30 +64,34 @@ export default async function forkListCommand() {
38
64
  const metadata = storage.loadMetadata();
39
65
  const accounts = storage.listAccounts();
40
66
 
41
- console.log(` ${forkDir}`);
42
- console.log(` Path: ${forkPath}`);
43
- console.log(` Network: ${metadata.network}`);
44
- console.log(` Chain ID: ${metadata.chainId}`);
45
- console.log(` Ledger Version: ${metadata.ledgerVersion}`);
46
- console.log(` Cached Accounts: ${accounts.length}`);
47
- console.log(` Created: ${new Date(metadata.createdAt).toLocaleString()}`);
48
- console.log('');
67
+ table.push([
68
+ forkDir,
69
+ metadata.network,
70
+ metadata.chainId.toString(),
71
+ accounts.length.toString(),
72
+ new Date(metadata.createdAt).toLocaleString()
73
+ ]);
49
74
  } else {
50
- console.log(` ${forkDir} (invalid - missing metadata)`);
51
- console.log('');
75
+ table.push([forkDir, 'invalid', '-', '-', 'missing metadata']);
52
76
  }
53
77
  } catch (error) {
54
- console.log(` ${forkDir} (error reading metadata)`);
55
- console.log('');
78
+ table.push([forkDir, 'error', '-', '-', 'error reading']);
56
79
  }
57
80
  }
58
81
 
59
- console.log('Usage:');
60
- console.log(' movehat fork view-resource --fork <PATH> --account <ADDR> --resource <TYPE>');
61
- console.log(' movehat fork fund --fork <PATH> --account <ADDR> --amount <AMOUNT>\n');
82
+ console.log(table.toString());
83
+ logger.newline();
84
+
85
+ // Usage examples
86
+ logger.section('Usage');
87
+ logger.item(formatCommand('movehat fork view-resource --fork <PATH> --account <ADDR> --resource <TYPE>'), 2);
88
+ logger.item(formatCommand('movehat fork fund --fork <PATH> --account <ADDR> --amount <AMOUNT>'), 2);
89
+ logger.newline();
62
90
 
63
91
  } catch (error: any) {
64
- console.error(`\n❌ Error: ${error.message}\n`);
92
+ logger.newline();
93
+ logger.error(`Error: ${error.message}`);
94
+ logger.newline();
65
95
  process.exit(1);
66
96
  }
67
97
  }