@travetto/cli 3.0.0-rc.1 → 3.0.0-rc.10

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
- <!-- Please modify https://github.com/travetto/travetto/tree/main/module/cli/doc.ts and execute "npx trv doc" to rebuild -->
2
+ <!-- Please modify https://github.com/travetto/travetto/tree/main/module/cli/DOC.ts and execute "npx trv doc" to rebuild -->
3
3
  # Command Line Interface
4
4
  ## CLI infrastructure for travetto framework
5
5
 
@@ -10,7 +10,7 @@ npm install @travetto/cli
10
10
 
11
11
  The cli is the primary structure for interacting with the external requirements of the framework. This can range from running tests, to running applications, to generating email templates. The main executable can be installed globally or locally. If installed globally and locally, it will defer to the local installation for execution.
12
12
 
13
- As is the custom, modules are able to register their own cli extensions as scripts, whose name starts with `cli-`. These scripts are then picked up at runtime and all available options are provided when viewing the help documentation. The following are all the supported cli operations and the various settings they allow.
13
+ As is the custom, modules are able to register their own cli extensions as scripts, whose name starts with `cli.`. These scripts are then picked up at runtime and all available options are provided when viewing the help documentation. The following are all the supported cli operations and the various settings they allow.
14
14
 
15
15
  ## General
16
16
 
@@ -21,17 +21,12 @@ $ trv --help
21
21
  Usage: [options] [command]
22
22
 
23
23
  Options:
24
- -V, --version output the version number
25
- -h, --help display help for command
24
+ -V, --version output the version number
25
+ -h, --help display help for command
26
26
 
27
27
  Commands:
28
- build [options]
29
- clean [options]
30
- doc [options]
31
28
  echo [options] [args...]
32
- run [options] [application] [args...]
33
- test [options] [regexes...]
34
- help [command] display help for command
29
+ help [command] display help for command
35
30
  ```
36
31
 
37
32
  This will show all the available options/choices that are exposed given the currently installed modules.
@@ -42,8 +37,7 @@ Extending the `cli` is fairly straightforward. It is built upon [commander](htt
42
37
 
43
38
  **Code: Echo Command**
44
39
  ```typescript
45
- import '@travetto/base';
46
- import { CliCommand } from '@travetto/cli/src/command';
40
+ import { CliCommand } from '@travetto/cli';
47
41
 
48
42
  /**
49
43
  * `npx trv echo`
@@ -54,7 +48,7 @@ export class CliEchoCommand extends CliCommand {
54
48
  name = 'echo';
55
49
 
56
50
  getOptions() {
57
- return { uppercase: this.boolOption({ desc: 'Upper case', def: false }) };
51
+ return { uppercase: this.boolOption({ desc: 'Upper case' }) };
58
52
  }
59
53
 
60
54
  getArgs() {
@@ -65,7 +59,7 @@ export class CliEchoCommand extends CliCommand {
65
59
  if (this.cmd.uppercase) {
66
60
  args = args.map(x => x.toUpperCase());
67
61
  }
68
- console.log(args);
62
+ console.log!(args);
69
63
  }
70
64
  }
71
65
  ```
@@ -79,7 +73,7 @@ $ trv echo --help
79
73
  Usage: echo [options] [args...]
80
74
 
81
75
  Options:
82
- -u, --uppercase Upper case (default: false)
76
+ -u, --uppercase Upper case
83
77
  -h, --help display help for command
84
78
  ```
85
79
 
@@ -89,5 +83,5 @@ And actually using it:
89
83
  ```bash
90
84
  $ trv echo -u bOb rOb DRoP
91
85
 
92
- [ 'bOb', 'rOb', 'DRoP' ]
86
+ [ 'BOB', 'ROB', 'DROP' ]
93
87
  ```
package/__index__.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './src/command';
2
+ export * from './src/command-manager';
3
+ export * from './src/execute';
4
+ export * from './src/help';
5
+ export * from './src/color';
6
+ export * from './src/module';
7
+ export * from './src/scm';
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "displayName": "Command Line Interface",
4
- "version": "3.0.0-rc.1",
3
+ "version": "3.0.0-rc.10",
5
4
  "description": "CLI infrastructure for travetto framework",
6
5
  "keywords": [
7
6
  "cli",
@@ -15,23 +14,25 @@
15
14
  "name": "Travetto Framework"
16
15
  },
17
16
  "files": [
17
+ "__index__.ts",
18
18
  "src",
19
+ "support",
19
20
  "bin"
20
21
  ],
21
- "main": "bin/trv.js",
22
- "bin": {
23
- "trv": "bin/trv.js"
24
- },
22
+ "bin": "trv.js",
23
+ "main": "__index__.ts",
25
24
  "repository": {
26
25
  "url": "https://github.com/travetto/travetto.git",
27
26
  "directory": "module/cli"
28
27
  },
29
28
  "dependencies": {
30
- "@travetto/base": "^3.0.0-rc.1",
31
- "commander": "^9.4.0"
29
+ "@travetto/base": "^3.0.0-rc.9",
30
+ "@travetto/terminal": "^3.0.0-rc.6",
31
+ "@travetto/worker": "^3.0.0-rc.9",
32
+ "commander": "^10.0.0"
32
33
  },
33
- "docDependencies": {
34
- "@travetto/app": true
34
+ "travetto": {
35
+ "displayName": "Command Line Interface"
35
36
  },
36
37
  "publishConfig": {
37
38
  "access": "public"
package/src/color.ts CHANGED
@@ -1,29 +1,19 @@
1
- import { ColorUtil } from '@travetto/boot/src/color';
1
+ import { Util } from '@travetto/base';
2
+ import { GlobalTerminal } from '@travetto/terminal';
2
3
 
3
- const colorSet = {
4
- input: ColorUtil.makeColorer('yellow'),
5
- output: ColorUtil.makeColorer('magenta'),
6
- path: ColorUtil.makeColorer('cyan'),
7
- success: ColorUtil.makeColorer('green', 'bold'),
8
- failure: ColorUtil.makeColorer('red', 'bold'),
9
- param: ColorUtil.makeColorer('green'),
10
- type: ColorUtil.makeColorer('cyan'),
11
- description: ColorUtil.makeColorer('white', 'faint', 'bold'),
12
- title: ColorUtil.makeColorer('white', 'bold'),
13
- identifier: ColorUtil.makeColorer('blue', 'bold'),
14
- subtitle: ColorUtil.makeColorer('white'),
15
- subsubtitle: ColorUtil.makeColorer('white', 'faint')
16
- } as const;
4
+ const tplFn = GlobalTerminal.templateFunction({
5
+ input: 'oliveDrab',
6
+ output: 'pink',
7
+ path: 'teal',
8
+ success: 'green',
9
+ failure: 'red',
10
+ param: 'yellow',
11
+ type: 'cyan',
12
+ description: 'white',
13
+ title: 'brightWhite',
14
+ identifier: 'dodgerBlue',
15
+ subtitle: 'lightGray',
16
+ subsubtitle: 'darkGray'
17
+ });
17
18
 
18
- /**
19
- * Colorize a string, as a string interpolation
20
- *
21
- * @example
22
- * ```
23
- * color`${{title: 'Main Title'}} is ${{subtitle: 'Sub Title}}`
24
- * ```
25
- */
26
- export const color = ColorUtil.makeTemplate(colorSet);
27
-
28
-
29
- export type ColoredElement = keyof typeof colorSet;
19
+ export const cliTpl = Util.makeTemplate(tplFn);
@@ -1,13 +1,13 @@
1
- import { SourceIndex } from '@travetto/boot/src/internal/source';
1
+ import { ShutdownManager } from '@travetto/base';
2
+ import { RootIndex } from '@travetto/manifest';
2
3
 
3
- import { color } from './color';
4
+ import { cliTpl } from './color';
4
5
  import { CliCommand } from './command';
5
6
 
6
7
  const COMMAND_PACKAGE = [
7
8
  [/^run$/, 'app', true],
8
- [/^compile$/, 'compiler', true],
9
9
  [/^test$/, 'test', false],
10
- [/^command:service$/, 'command', true],
10
+ [/^service$/, 'command', true],
11
11
  [/^model:(install|export)$/, 'model', true],
12
12
  [/^openapi:(spec|client)$/, 'openapi', true],
13
13
  [/^email:(compile|dev)$/, 'email-template', false],
@@ -24,8 +24,8 @@ export class CliCommandManager {
24
24
  */
25
25
  static getCommandMapping(): Map<string, string> {
26
26
  const all = new Map<string, string>();
27
- for (const { file } of SourceIndex.find({ folder: 'bin', filter: /bin\/cli-/ })) {
28
- all.set(file.replace(/^.*\/bin\/.+?-(.*?)[.][^.]*$/, (_, f) => f), file);
27
+ for (const { outputFile: output, import: imp } of RootIndex.findSupport({ filter: /\/cli[.]/, checkProfile: false })) {
28
+ all.set(output.replace(/^.*\/cli[.](.*?)[.][^.]+$/, (_, f) => f), imp);
29
29
  }
30
30
  return all;
31
31
  }
@@ -33,43 +33,64 @@ export class CliCommandManager {
33
33
  /**
34
34
  * Load command
35
35
  */
36
- static async loadCommand(cmd: string, op?: (p: CliCommand) => unknown): Promise<CliCommand> {
36
+ static async loadCommand(
37
+ cmd: string,
38
+ cfg: {
39
+ filter?: (p: CliCommand) => boolean;
40
+ failOnMissing?: boolean;
41
+ } = {}
42
+ ): Promise<CliCommand | undefined> {
37
43
  const command = cmd.replace(/:/g, '_');
38
- const f = this.getCommandMapping().get(command)!;
39
- if (!f) {
40
- const cfg = COMMAND_PACKAGE.find(([re]) => re.test(cmd));
41
- if (cfg) {
42
- const [, pkg, prod] = cfg;
43
- console.error(color`
44
+ const found = this.getCommandMapping().get(command)!;
45
+ if (!found) {
46
+ const matchedCfg = COMMAND_PACKAGE.find(([re]) => re.test(cmd));
47
+ if (matchedCfg) {
48
+ const [, pkg, prod] = matchedCfg;
49
+ console.error!(cliTpl`
44
50
  ${{ title: 'Missing Package' }}\n${'-'.repeat(20)}\nTo use ${{ input: cmd }} please run:\n
45
- ${{ identifier: `npm i ${prod ? '' : '--save-dev '}@travetto/${pkg}` }}`);
46
- process.exit(1);
51
+ ${{ identifier: `npm i ${prod ? '' : '--save-dev '}@travetto/${pkg}` }}
52
+ `);
53
+ await ShutdownManager.exit(1);
47
54
  }
48
55
  throw new Error(`Unknown command: ${cmd}`);
49
56
  }
50
- const values = Object.values<{ new(...args: unknown[]): unknown }>(await import(f));
51
- for (const v of values) {
52
- try {
53
- const inst = new v();
54
- if (inst instanceof CliCommand) {
55
- if (op) {
56
- await op(inst);
57
+ try {
58
+ const values = Object.values<{ new(...args: unknown[]): unknown }>(await import(found));
59
+ for (const v of values) {
60
+ try {
61
+ const inst = new v();
62
+ if (inst instanceof CliCommand && (!cfg.filter || cfg.filter(inst))) {
63
+ return inst;
57
64
  }
58
- return inst;
59
- }
60
- } catch { }
65
+ } catch { }
66
+ }
67
+ } catch (importErr) {
68
+ console.error(`Import error: ${cmd}`, importErr);
69
+ }
70
+ if (cfg.failOnMissing ?? false) {
71
+ throw new Error(`Not a valid command: ${cmd}`);
61
72
  }
62
- throw new Error(`Not a valid command: ${cmd}`);
63
73
  }
64
74
 
65
75
  /**
66
76
  * Load all available commands
67
77
  */
68
78
  static async loadAllCommands(op?: (p: CliCommand) => unknown | Promise<unknown>): Promise<CliCommand[]> {
69
- return Promise.all(
79
+ const commands = await Promise.all(
70
80
  [...this.getCommandMapping().keys()]
71
- .sort((a, b) => a.localeCompare(b))
72
- .map(k => this.loadCommand(k, op))
81
+ .map(k => this.loadCommand(k, {
82
+ filter(cmd: CliCommand) {
83
+ return RootIndex.getFunctionMetadata(cmd.constructor)?.abstract !== true && cmd.isActive?.() !== false;
84
+ }
85
+ }))
73
86
  );
87
+
88
+ return await Promise.all(commands
89
+ .filter((x): x is Exclude<typeof x, undefined> => !!x)
90
+ .sort((a, b) => a.name.localeCompare(b.name))
91
+ .map(async x => {
92
+ await op?.(x);
93
+ return x;
94
+ }));
74
95
  }
75
96
  }
package/src/command.ts CHANGED
@@ -1,11 +1,10 @@
1
- import { appendFile } from 'fs/promises';
2
- import * as commander from 'commander';
1
+ import { appendFile, mkdir } from 'fs/promises';
2
+ import type commander from 'commander';
3
3
 
4
- import { CompletionConfig } from './types';
5
- import { HelpUtil } from './help';
6
- import { CliUtil } from './util';
4
+ import { path } from '@travetto/manifest';
5
+ import { ConsoleManager, DataUtil, defineGlobalEnv, GlobalEnvConfig, ShutdownManager } from '@travetto/base';
7
6
 
8
- type Completion = Record<string, string[]>;
7
+ import { HelpUtil } from './help';
9
8
 
10
9
  type OptionPrimitive = string | number | boolean;
11
10
 
@@ -29,10 +28,16 @@ export type ListOptionConfig<K extends OptionPrimitive = OptionPrimitive> = Core
29
28
  type AllOptionConfig<K extends OptionPrimitive = OptionPrimitive> = OptionConfig<K> | ListOptionConfig<K>;
30
29
 
31
30
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
- type OptionMap<T = any> = { [key in keyof T]: T[key] extends OptionPrimitive ? AllOptionConfig<T[key]> : never };
31
+ export type OptionMap<T = any> = { [key in keyof T]: T[key] extends OptionPrimitive ? AllOptionConfig<T[key]> : never };
33
32
 
34
33
  type Shape<M extends OptionMap> = { [k in keyof M]: Exclude<M[k]['def'], undefined> };
35
34
 
35
+ function clamp(v: number, l?: number, u?: number): number | undefined {
36
+ if (l !== undefined && v < l) { return; }
37
+ if (u !== undefined && v > u) { return; }
38
+ return v;
39
+ }
40
+
36
41
  /**
37
42
  * Base command
38
43
  */
@@ -61,7 +66,7 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
61
66
  /**
62
67
  * Setup environment before command runs
63
68
  */
64
- envInit?(): Promise<void> | void;
69
+ envInit?(): Promise<GlobalEnvConfig> | GlobalEnvConfig;
65
70
  /**
66
71
  * Get Options for commander
67
72
  */
@@ -69,7 +74,7 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
69
74
  /**
70
75
  * Get args
71
76
  */
72
- getArgs?(): string;
77
+ getArgs?(): string | undefined;
73
78
  /**
74
79
  * Initialization code for adding options
75
80
  */
@@ -82,7 +87,10 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
82
87
  * Supports JSON IPC?
83
88
  */
84
89
  jsonIpc?(...args: unknown[]): Promise<unknown>;
85
-
90
+ /**
91
+ * Is the command active/eligible for usage
92
+ */
93
+ isActive?(): boolean;
86
94
  /**
87
95
  * Define option
88
96
  */
@@ -127,7 +135,8 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
127
135
  boolOption(cfg: OptionConfig<boolean>): OptionConfig<boolean> {
128
136
  return {
129
137
  type: Boolean,
130
- combine: CliUtil.toBool.bind(CliUtil),
138
+ combine: (val, curr): boolean =>
139
+ (val !== undefined ? DataUtil.coerceType(val, Boolean, false) : undefined) ?? curr,
131
140
  completion: true,
132
141
  ...cfg
133
142
  };
@@ -139,19 +148,11 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
139
148
  intOption({ lower, upper, ...cfg }: OptionConfig<number> & { lower?: number, upper?: number }): OptionConfig<number> {
140
149
  return {
141
150
  type: Number,
142
- combine: CliUtil.toInt.bind(CliUtil, lower, upper),
151
+ combine: (val, curr): number => clamp(DataUtil.coerceType(val, Number, false), lower, upper) ?? curr,
143
152
  ...cfg
144
153
  };
145
154
  }
146
155
 
147
- /**
148
- * Pre-compile on every cli execution
149
- */
150
- async build(): Promise<void> {
151
- await (await import('@travetto/base/bin/lib/'))
152
- .BuildUtil.build();
153
- }
154
-
155
156
  /**
156
157
  * Expose configuration as constrained typed object
157
158
  */
@@ -166,14 +167,21 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
166
167
  return this.#cmd.args;
167
168
  }
168
169
 
170
+ exit(code = 0): Promise<void> {
171
+ return ShutdownManager.exit(code);
172
+ }
173
+
169
174
  /**
170
175
  * Render help with additional message or extra text
171
176
  */
172
- async showHelp(err?: string | Error, extra?: string): Promise<never> {
177
+ async showHelp(err?: string | Error, extra?: string, exitOnError = true): Promise<void> {
173
178
  if (err && typeof err !== 'string') {
174
179
  err = err.message;
175
180
  }
176
181
  HelpUtil.showHelp(this.#cmd, err, extra || (await this.help?.()) || '');
182
+ if (exitOnError) {
183
+ return this.exit(err ? 1 : 0);
184
+ }
177
185
  }
178
186
 
179
187
  /**
@@ -209,19 +217,27 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
209
217
  if (this.init) {
210
218
  cmd = await this.init?.(cmd);
211
219
  }
212
- if (this.getArgs) {
213
- cmd = cmd.arguments(this.getArgs?.());
220
+ const args = this.getArgs?.();
221
+ if (args) {
222
+ cmd = cmd.arguments(args);
214
223
  }
215
224
  for (const cfg of await this.finalizeOptions()) {
216
- let key = `${cfg.short ? `-${cfg.short}, ` : ''}--${cfg.name}`;
217
- if (cfg.type !== Boolean || cfg.def) {
218
- key = `${key} <${cfg.name}>`;
225
+ const pre = cfg.short ? `-${cfg.short}, ` : '';
226
+ if (cfg.type === Boolean) {
227
+ if (cfg.def) {
228
+ cmd.option(`${pre}--no-${cfg.name}`, `Disables: ${cfg.desc}`);
229
+ } else {
230
+ cmd.option(`${pre}--${cfg.name}`, cfg.desc);
231
+ }
232
+ } else {
233
+ const key = `${pre}--${cfg.name} <${cfg.name}>`;
234
+ // @ts-expect-error
235
+ cmd = cmd.option(key, cfg.desc, cfg.combine ?? ((cur, acc): unknown => cur), cfg.def);
219
236
  }
220
- // @ts-expect-error
221
- cmd = cfg.combine ? cmd.option(key, cfg.desc, cfg.combine, cfg.def) : cmd.option(key, cfg.desc, (cur, acc) => cur, cfg.def);
222
237
  }
223
238
 
224
239
  cmd = cmd.action(this.runAction.bind(this));
240
+
225
241
  return this.#cmd = cmd;
226
242
  }
227
243
 
@@ -229,46 +245,20 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
229
245
  * Runs the action at execution time
230
246
  */
231
247
  async runAction(...args: unknown[]): Promise<void> {
232
- await this.envInit?.();
233
- await this.build();
234
- if (process.env.TRV_CLI_JSON_IPC && this.jsonIpc) {
248
+ if (this.envInit) {
249
+ defineGlobalEnv(await this.envInit());
250
+ ConsoleManager.setDebugFromEnv();
251
+ }
252
+
253
+ if (process.env.TRV_CLI_IPC && this.jsonIpc) {
235
254
  const data = await this.jsonIpc(...args);
236
255
  if (data !== undefined) {
237
256
  const payload = JSON.stringify({ type: this.name, data });
238
- await appendFile(process.env.TRV_CLI_JSON_IPC, `${payload}\n`);
257
+ await mkdir(path.dirname(process.env.TRV_CLI_IPC), { recursive: true });
258
+ await appendFile(process.env.TRV_CLI_IPC, `${payload}\n`);
239
259
  return;
240
260
  }
241
261
  }
242
262
  return await this.action(...args);
243
263
  }
244
-
245
- /**
246
- * Collection tab completion information
247
- */
248
- async setupCompletion(config: CompletionConfig): Promise<void> {
249
- const task = await this.complete();
250
- config.all = [...config.all, this.name];
251
- if (task) {
252
- config.task[this.name] = task;
253
- }
254
- }
255
-
256
- /**
257
- * Return tab completion information
258
- */
259
- async complete(): Promise<Completion | void> {
260
- const out: Completion = { '': [] };
261
- for (const el of await this.finalizeOptions()) {
262
- if (el.completion) {
263
- out[''] = [...out['']!, `--${el.name} `];
264
- if ('choices' in el && el.choices) {
265
- out[`--${el.name} `] = el.choices.map(x => `${x}`);
266
- if (el.short) {
267
- out[`- ${el.short} `] = el.choices.map(x => `${x}`);
268
- }
269
- }
270
- }
271
- }
272
- return out;
273
- }
274
264
  }
package/src/execute.ts CHANGED
@@ -1,38 +1,27 @@
1
+ import fs from 'fs/promises';
1
2
  import { program as commander } from 'commander';
2
3
 
3
- import { CliUtil } from './util';
4
- import { CompletionConfig } from './types';
4
+ import { PackageUtil, path, RootIndex } from '@travetto/manifest';
5
+ import { GlobalTerminal } from '@travetto/terminal';
6
+ import { ShutdownManager } from '@travetto/base';
7
+
5
8
  import { CliCommandManager } from './command-manager';
6
9
  import { HelpUtil } from './help';
7
- import { version } from '../package.json';
8
10
 
9
11
  /**
10
12
  * Execution manager
11
13
  */
12
14
  export class ExecutionManager {
13
15
 
14
- /**
15
- * Run tab completion given the full args list
16
- */
17
- static async runCompletion(args: string[]): Promise<void> {
18
- const cfg: CompletionConfig = { all: [], task: {} };
19
- await CliCommandManager.loadAllCommands(x => x.setupCompletion(cfg));
20
- const res = await CliUtil.getCompletion(cfg, args.slice(3));
21
- console.log(res.join(' '));
22
- return;
23
- }
24
-
25
16
  /**
26
17
  * Run command
27
18
  */
28
- static async runCommand(args: string[]): Promise<void> {
29
- const cmd = args[2];
30
-
19
+ static async runCommand(cmd: string, args: string[]): Promise<void> {
31
20
  let command;
32
21
 
33
22
  try {
34
23
  // Load a single command
35
- command = await CliCommandManager.loadCommand(cmd);
24
+ command = (await CliCommandManager.loadCommand(cmd, { failOnMissing: true }))!;
36
25
  await command.setup(commander);
37
26
  } catch (err) {
38
27
  return HelpUtil.showHelp(commander, `Unknown command ${cmd}`);
@@ -42,38 +31,63 @@ export class ExecutionManager {
42
31
  if (args.includes('-h') || args.includes('--help')) {
43
32
  return command.showHelp();
44
33
  } else {
45
- commander.parse(args);
34
+ await commander.parseAsync([process.argv[0], process.argv[1], cmd, ...args]);
46
35
  }
47
36
  } catch (err) {
48
37
  if (!(err instanceof Error)) {
49
38
  throw err;
39
+ } else {
40
+ console.error(err);
50
41
  }
51
42
  return command.showHelp(err);
52
43
  }
53
44
  }
54
45
 
46
+ /**
47
+ * Run file expecting a main method
48
+ */
49
+ static async runMain(file: string, args: string[]): Promise<void> {
50
+ try {
51
+ // If referenced file exists
52
+ if (await (fs.stat(path.resolve(file)).then(() => true, () => false))) {
53
+ file = path.join(RootIndex.manifest.mainModule, file);
54
+ }
55
+
56
+ const imp = RootIndex.getFromImport(file)?.import;
57
+ if (!imp) {
58
+ throw new Error(`Unknown file: ${file}`);
59
+ }
60
+
61
+ const mod = await import(imp);
62
+ await ShutdownManager.exitWithResponse(await mod.main(...args));
63
+ } catch (err) {
64
+ await ShutdownManager.exitWithResponse(err, true);
65
+ }
66
+ }
67
+
55
68
  /**
56
69
  * Execute the command line
57
70
  * @param args
58
71
  */
59
- static async run(args: string[]): Promise<void> {
60
- const width = +(process.env.TRV_CONSOLE_WIDTH ?? process.stdout.columns ?? 120);
72
+ static async run(argv: string[]): Promise<void> {
73
+ const { init } = await import('@travetto/base/support/init.js');
74
+ await init();
75
+
76
+ const width = GlobalTerminal.width;
61
77
  commander
62
- .version(version)
78
+ .version(PackageUtil.getFrameworkVersion())
63
79
  .configureOutput({ getOutHelpWidth: () => width, getErrHelpWidth: () => width });
64
80
 
65
- const cmd = args[2];
66
-
67
- if (cmd === 'complete') {
68
- await this.runCompletion(args);
81
+ const [, , cmd, ...args] = argv;
82
+ if (cmd === 'main') {
83
+ const [file, ...rest] = args;
84
+ await this.runMain(file, rest);
85
+ } else if (cmd && !cmd.startsWith('-')) {
86
+ await this.runCommand(cmd, args);
69
87
  } else {
70
- if (cmd && !cmd.startsWith('-')) {
71
- await this.runCommand(args);
72
- } else {
73
- // Load all commands
74
- await CliCommandManager.loadAllCommands(x => x.setup(commander));
75
- HelpUtil.showHelp(commander);
76
- }
88
+ // Load all commands
89
+ await CliCommandManager.loadAllCommands(x => x.setup(commander));
90
+ HelpUtil.showHelp(commander);
77
91
  }
78
92
  }
79
93
  }