Interactive Subshell

This example demonstrates how to create an interactive subshell using cli-forge. The subshell is a simple REPL that can execute commands or shell commands. To launch the subshell, run the script with no arguments, or a command that contains subcommands and no handler. The subshell presents a prompt that includes the current command chain, and executes the command when the user presses enter. If the command is not recognized, it is executed as a shell command. Notably, the subshell is very basic. It does not currently support command history, tab completion, or other advanced features.

All Example Files

FILE EXPLORER
interactive-subshell.ts
1import cliForge from 'cli-forge';
2
3const state = {
4  defaultHost: 'example.com',
5  auth: {} as Record<string, { user: string; pass?: string }>,
6};
7
8const cli = cliForge('interactive-subshell')
9  // Enables launching an interactive subshell.
10  // For this example, the subshell would be launched if the user
11  // runs either:
12  // - `node ./interactive-subshell.ts`
13  // - `node ./interactive-subshell.ts foo`
14  .enableInteractiveShell()
15  .command('auth', {
16    builder: (args) =>
17      args
18        .option('host', { type: 'string', default: state.defaultHost })
19        .command('login', {
20          builder: (args) => {
21            return args
22              .positional('user', { type: 'string', required: true })
23              .option('pass', { type: 'string' });
24          },
25          handler: (args) => {
26            state.auth ??= {};
27            state.auth[args.host] = {
28              user: args.user,
29              pass: args.pass,
30            };
31            console.log('Logged in to', args.host, 'as', args.user);
32          },
33        })
34        .command('logout', {
35          handler: (args) => {
36            delete state.auth[args.host];
37            console.log('Logged out of', args.host);
38          },
39        }),
40  })
41  .command('lorem', {
42    handler: (args) => {
43      console.log('lorem ipsum');
44    },
45  });
46
47// We export the CLI for a few reasons:
48// - Testing
49// - Composition (a CLI can be a subcommand of another CLI)
50// - Docs generation
51export default cli;
52