@chatbotkit/cli 1.20.0 → 1.21.1

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 (42) hide show
  1. package/README.md +78 -20
  2. package/bin/cbk.js +7 -2
  3. package/dist/cjs/command/agent/index.cjs +100 -0
  4. package/dist/cjs/command/agent/index.d.ts +3 -0
  5. package/dist/cjs/command/api/conversation/index.cjs +13 -8
  6. package/dist/cjs/command/api/conversation/index.d.ts +0 -2
  7. package/dist/cjs/command/api/conversation/message/index.cjs +9 -4
  8. package/dist/cjs/command/api/dataset/index.cjs +9 -4
  9. package/dist/cjs/command/api/index.cjs +10 -5
  10. package/dist/cjs/command/api/index.d.ts +1 -0
  11. package/dist/cjs/command/api/partner/index.cjs +7 -2
  12. package/dist/cjs/command/api/partner/user/index.cjs +9 -4
  13. package/dist/cjs/command/api/skillset/index.cjs +9 -4
  14. package/dist/cjs/command/chat/index.cjs +34 -9
  15. package/dist/cjs/index.cjs +6 -4
  16. package/dist/cjs/output.cjs +4 -0
  17. package/dist/cjs/solution/index.cjs +3 -3
  18. package/dist/cjs/spinner.cjs +56 -0
  19. package/dist/cjs/spinner.d.ts +15 -0
  20. package/dist/cjs/tools.cjs +197 -0
  21. package/dist/cjs/tools.d.ts +9 -0
  22. package/dist/esm/command/agent/index.d.ts +3 -0
  23. package/dist/esm/command/agent/index.js +97 -0
  24. package/dist/esm/command/api/conversation/index.d.ts +0 -2
  25. package/dist/esm/command/api/conversation/index.js +12 -7
  26. package/dist/esm/command/api/conversation/message/index.js +9 -4
  27. package/dist/esm/command/api/dataset/index.js +9 -4
  28. package/dist/esm/command/api/index.d.ts +1 -0
  29. package/dist/esm/command/api/index.js +10 -5
  30. package/dist/esm/command/api/partner/index.js +7 -2
  31. package/dist/esm/command/api/partner/user/index.js +9 -4
  32. package/dist/esm/command/api/skillset/index.js +9 -4
  33. package/dist/esm/command/chat/index.js +34 -9
  34. package/dist/esm/index.js +2 -0
  35. package/dist/esm/output.js +4 -0
  36. package/dist/esm/spinner.d.ts +15 -0
  37. package/dist/esm/spinner.js +52 -0
  38. package/dist/esm/tools.d.ts +9 -0
  39. package/dist/esm/tools.js +192 -0
  40. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  41. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  42. package/package.json +76 -5
package/README.md CHANGED
@@ -7,37 +7,95 @@
7
7
 
8
8
  # ChatBotKit CLI
9
9
 
10
- The ChatBotKit CLI is a command-line interface for the ChatBotKit SDK. It provides a set of commands to help you manage your ChatBotKit projects.
10
+ A powerful command-line interface for ChatBotKit that provides both API management commands and an autonomous AI agent mode for interactive development tasks.
11
11
 
12
- ## Getting Started
12
+ ## Installation
13
13
 
14
- To begin using the ChatBotKit CLI, follow these steps:
14
+ Install globally via npm:
15
15
 
16
- 1. **Installation**: Add the SDK to your project using npm:
16
+ ```bash
17
+ npm install --global @chatbotkit/cli
18
+ ```
17
19
 
18
- ```bash
19
- npm install --global @chatbotkit/cli
20
- ```
20
+ ## Authentication
21
21
 
22
- 2. **Help**: Get help on the available commands:
22
+ Set your ChatBotKit API token as an environment variable:
23
23
 
24
- ```bash
25
- cbk --help
26
- ```
24
+ ```bash
25
+ export CHATBOTKIT_API_TOKEN=<your token here>
26
+ ```
27
27
 
28
- 3. **Usage**: Use the CLI to interact with ChatBotKit:
28
+ ### Environment Configuration
29
29
 
30
- Keep in mind that you will need to authenticate with your ChatBotKit token first.
30
+ The CLI automatically loads environment variables from the following locations (in order of precedence):
31
31
 
32
- ```bash
33
- export CHATBOTKIT_API_TOKEN=<your token here>
34
- ```
32
+ 1. `.env.local` - Project-specific local configuration (current directory)
33
+ 2. `.env` - Project configuration (current directory)
34
+ 3. `~/.cbk/env` - Global user configuration (home directory fallback)
35
35
 
36
- Then you can use the CLI to interact with ChatBotKit:
36
+ This allows you to store your API token globally in `~/.cbk/env` for convenience, while still being able to override it per-project using local `.env` files.
37
37
 
38
- ```bash
39
- cbk api conversation list
40
- ```
38
+ **Example `~/.cbk/env` file:**
39
+
40
+ ```bash
41
+ CHATBOTKIT_API_TOKEN=your_token_here
42
+ ```
43
+
44
+ ## Features
45
+
46
+ ### API Commands
47
+
48
+ Manage ChatBotKit resources directly from the command line:
49
+
50
+ ```bash
51
+ cbk api conversation list
52
+ cbk api bot list
53
+ ```
54
+
55
+ Use `cbk --help` to see all available commands.
56
+
57
+ ### Agent Mode
58
+
59
+ Run an autonomous AI agent that can execute tasks with local file system and command access, while leveraging the full power of the ChatBotKit platform.
60
+
61
+ ```bash
62
+ cbk agent -p "Create a new file and write hello world to it"
63
+ ```
64
+
65
+ **Local Tools:**
66
+
67
+ - `read` - Read file contents
68
+ - `write` - Write content to a file
69
+ - `edit` - Replace exact string occurrences (single match only)
70
+ - `find` - Search for files using glob patterns
71
+ - `exec` - Execute shell commands
72
+
73
+ **Platform Integration:**
74
+
75
+ The agent runs with complete ChatBotKit platform capabilities, including:
76
+
77
+ - Access to all configured integrations and 3rd-party services
78
+ - Authenticated sessions with external APIs
79
+ - Dataset connections and skillsets
80
+ - Custom abilities and functions
81
+
82
+ This means your agent can interact with your local development environment while seamlessly accessing any ChatBotKit resources you've configured.
83
+
84
+ **Agent Options:**
85
+
86
+ - `-p, --prompt <text>` - Task to execute
87
+ - `-t, --tools <names>` - Comma-separated list of tools to enable (defaults to all standard tools)
88
+ - `-m, --model <name>` - AI model to use
89
+
90
+ **Example:**
91
+
92
+ ```bash
93
+ # Run agent with specific tools only
94
+ cbk agent -t read,write -p "Read package.json and create a backup"
95
+
96
+ # Use custom timeout for long-running commands
97
+ cbk agent -p "Run tests with 60 second timeout" -m gpt-5
98
+ ```
41
99
 
42
100
  ## Documentation
43
101
 
package/bin/cbk.js CHANGED
@@ -4,9 +4,14 @@ import dotenv from 'dotenv'
4
4
  import cli from '@chatbotkit/cli'
5
5
  import { printError } from '@chatbotkit/cli/output'
6
6
 
7
+ import { homedir } from 'os'
8
+ import { join } from 'path'
9
+
7
10
  dotenv.config({
8
- // @ts-expect-error arrays are supported
9
- path: ['.env.local', '.env'],
11
+ path: ['.env.local', '.env', join(homedir(), '.cbk', 'env')],
10
12
  })
11
13
 
14
+ process.on('unhandledRejection', printError)
15
+ process.on('uncaughtException', printError)
16
+
12
17
  cli().catch(printError)
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const env_js_1 = require("../../env.cjs");
5
+ const output_js_1 = require("../../output.cjs");
6
+ const spinner_js_1 = require("../../spinner.cjs");
7
+ const tools_js_1 = require("../../tools.cjs");
8
+ const agent_1 = require("@chatbotkit/agent");
9
+ const sdk_1 = require("@chatbotkit/sdk");
10
+ const commander_1 = require("commander");
11
+ const fs_1 = require("fs");
12
+ const path_1 = require("path");
13
+ function getClient() {
14
+ return new sdk_1.ChatBotKit({
15
+ secret: (0, env_js_1.getSECRET)(),
16
+ runAsUserId: (0, env_js_1.getRUNAS_USERID)(),
17
+ });
18
+ }
19
+ exports.command = new commander_1.Command()
20
+ .name('agent')
21
+ .description('Run an agent as a background worker with a prompt')
22
+ .addOption(new commander_1.Option('-b, --bot <bot>', 'Bot id'))
23
+ .addOption(new commander_1.Option('-m, --model <model>', 'Model name'))
24
+ .addOption(new commander_1.Option('-p, --prompt <prompt>', 'The prompt to execute (or path to a file containing the prompt)').makeOptionMandatory())
25
+ .addOption(new commander_1.Option('-t, --tools <tools...>', 'Specific tools to enable').choices((0, tools_js_1.getToolNames)()))
26
+ .addOption(new commander_1.Option('-i, --max-iterations <maxIterations>', 'Maximum number of iterations')
27
+ .default(50)
28
+ .argParser((value) => parseInt(value, 10)))
29
+ .action(async (options) => {
30
+ const client = getClient();
31
+ const tools = (0, tools_js_1.getTools)(options.tools);
32
+ let prompt = options.prompt;
33
+ {
34
+ const filePath = (0, path_1.resolve)(process.cwd(), options.prompt);
35
+ if ((0, fs_1.existsSync)(filePath)) {
36
+ try {
37
+ prompt = (0, fs_1.readFileSync)(filePath, 'utf-8');
38
+ }
39
+ catch (error) {
40
+ (0, output_js_1.printError)(error);
41
+ }
42
+ }
43
+ }
44
+ const isInteractive = process.stdout.isTTY;
45
+ const spinner = isInteractive ? new spinner_js_1.Spinner() : null;
46
+ let exitResult = null;
47
+ let hasOutput = false;
48
+ for await (const { type, data } of (0, agent_1.execute)({
49
+ client,
50
+ botId: options.bot,
51
+ model: options.model,
52
+ messages: [{ type: 'user', text: prompt }],
53
+ tools,
54
+ maxIterations: options.maxIterations,
55
+ })) {
56
+ if (type === 'iteration') {
57
+ if (spinner) {
58
+ if (spinner.isSpinning) {
59
+ spinner.stop();
60
+ }
61
+ const iterationNum = data.iteration - 1;
62
+ console.log(`\n╭─ Iteration ${iterationNum} ─╮`);
63
+ spinner.start();
64
+ }
65
+ else {
66
+ (0, output_js_1.print)({ iteration: data.iteration - 1 });
67
+ }
68
+ hasOutput = false;
69
+ }
70
+ else if (type === 'token') {
71
+ if (spinner && spinner.isSpinning) {
72
+ spinner.stop();
73
+ }
74
+ if (!hasOutput && isInteractive) {
75
+ process.stdout.write('> ');
76
+ hasOutput = true;
77
+ }
78
+ process.stdout.write(data.token);
79
+ }
80
+ else if (type === 'exit') {
81
+ exitResult = data;
82
+ }
83
+ }
84
+ if (spinner && spinner.isSpinning) {
85
+ spinner.stop();
86
+ }
87
+ process.stdout.write('\n\n');
88
+ if (exitResult) {
89
+ (0, output_js_1.print)({
90
+ status: exitResult.code === 0 ? 'success' : 'failed',
91
+ exitCode: exitResult.code,
92
+ ...(exitResult.message && { message: exitResult.message }),
93
+ });
94
+ process.exit(exitResult.code);
95
+ }
96
+ else {
97
+ (0, output_js_1.printError)(new Error('Task ended without exit signal'));
98
+ }
99
+ });
100
+ exports.default = exports.command;
@@ -0,0 +1,3 @@
1
+ export const command: Command;
2
+ export default command;
3
+ import { Command } from 'commander';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.command = exports.conversationDelete = exports.conversationFetch = exports.conversationList = void 0;
3
+ exports.command = exports.conversationList = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const env_js_1 = require("../../../env.cjs");
6
6
  const output_js_1 = require("../../../output.cjs");
@@ -32,7 +32,7 @@ exports.conversationList = new commander_1.Command()
32
32
  }
33
33
  }
34
34
  });
35
- exports.conversationFetch = new commander_1.Command()
35
+ const conversationFetch = new commander_1.Command()
36
36
  .name('fetch')
37
37
  .description('Fetch conversation')
38
38
  .argument('<conversationId>', 'Conversation ID')
@@ -41,7 +41,7 @@ exports.conversationFetch = new commander_1.Command()
41
41
  const conversation = await client.fetch(conversationId);
42
42
  (0, output_js_1.print)(conversation);
43
43
  });
44
- exports.conversationDelete = new commander_1.Command()
44
+ const conversationDelete = new commander_1.Command()
45
45
  .name('delete')
46
46
  .description('Delete conversation')
47
47
  .argument('<conversationId>', 'Conversation ID')
@@ -49,11 +49,16 @@ exports.conversationDelete = new commander_1.Command()
49
49
  const client = getClient();
50
50
  await client.delete(conversationId);
51
51
  });
52
+ const commands = {
53
+ list: exports.conversationList,
54
+ fetch: conversationFetch,
55
+ delete: conversationDelete,
56
+ message: index_js_1.default,
57
+ };
52
58
  exports.command = new commander_1.Command()
53
59
  .name('conversation')
54
- .description('Conversation tools for ChatBotKit')
55
- .addCommand(exports.conversationList)
56
- .addCommand(exports.conversationFetch)
57
- .addCommand(exports.conversationDelete)
58
- .addCommand(index_js_1.default);
60
+ .description('Conversation tools for ChatBotKit');
61
+ for (const cmd of Object.values(commands)) {
62
+ exports.command.addCommand(cmd);
63
+ }
59
64
  exports.default = exports.command;
@@ -1,6 +1,4 @@
1
1
  export const conversationList: Command;
2
- export const conversationFetch: Command;
3
- export const conversationDelete: Command;
4
2
  export const command: Command;
5
3
  export default command;
6
4
  import { Command } from 'commander';
@@ -50,10 +50,15 @@ exports.messageDelete = new commander_1.Command()
50
50
  const client = getClient();
51
51
  await client.delete(conversationId, messageId);
52
52
  });
53
+ const commands = {
54
+ list: exports.messageList,
55
+ fetch: exports.messageFetch,
56
+ delete: exports.messageDelete,
57
+ };
53
58
  exports.command = new commander_1.Command()
54
59
  .name('message')
55
- .description('Message tools for ChatBotKit')
56
- .addCommand(exports.messageList)
57
- .addCommand(exports.messageFetch)
58
- .addCommand(exports.messageDelete);
60
+ .description('Message tools for ChatBotKit');
61
+ for (const cmd of Object.values(commands)) {
62
+ exports.command.addCommand(cmd);
63
+ }
59
64
  exports.default = exports.command;
@@ -47,10 +47,15 @@ exports.datasetDelete = new commander_1.Command()
47
47
  const client = getClient();
48
48
  await client.delete(datasetId);
49
49
  });
50
+ const commands = {
51
+ list: exports.datasetList,
52
+ fetch: exports.datasetFetch,
53
+ delete: exports.datasetDelete,
54
+ };
50
55
  exports.command = new commander_1.Command()
51
56
  .name('dataset')
52
- .description('Dataset tools for ChatBotKit')
53
- .addCommand(exports.datasetList)
54
- .addCommand(exports.datasetFetch)
55
- .addCommand(exports.datasetDelete);
57
+ .description('Dataset tools for ChatBotKit');
58
+ for (const cmd of Object.values(commands)) {
59
+ exports.command.addCommand(cmd);
60
+ }
56
61
  exports.default = exports.command;
@@ -8,13 +8,18 @@ const index_js_2 = tslib_1.__importDefault(require("./dataset/index.cjs"));
8
8
  const index_js_3 = tslib_1.__importDefault(require("./partner/index.cjs"));
9
9
  const index_js_4 = tslib_1.__importDefault(require("./skillset/index.cjs"));
10
10
  const commander_1 = require("commander");
11
+ const commands = {
12
+ conversation: index_js_1.default,
13
+ dataset: index_js_2.default,
14
+ skillset: index_js_4.default,
15
+ partner: index_js_3.default,
16
+ };
11
17
  exports.command = new commander_1.Command()
12
18
  .name('api')
13
- .description('API tools for ChatBotKit')
14
- .addCommand(index_js_2.default)
15
- .addCommand(index_js_4.default)
16
- .addCommand(index_js_1.default)
17
- .addCommand(index_js_3.default);
19
+ .description('API tools for ChatBotKit');
20
+ for (const cmd of Object.values(commands)) {
21
+ exports.command.addCommand(cmd);
22
+ }
18
23
  exports.command
19
24
  .addOption(new commander_1.Option('-o, --output <format>', 'Output format').choices([
20
25
  'yaml',
@@ -1,3 +1,4 @@
1
1
  export const command: Command;
2
2
  export default command;
3
+ export type ChatBotKitSDK = import("@chatbotkit/sdk").ChatBotKit;
3
4
  import { Command } from 'commander';
@@ -4,8 +4,13 @@ exports.command = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const index_js_1 = tslib_1.__importDefault(require("./user/index.cjs"));
6
6
  const commander_1 = require("commander");
7
+ const commands = {
8
+ user: index_js_1.default,
9
+ };
7
10
  exports.command = new commander_1.Command()
8
11
  .name('partner')
9
- .description('Partner tools for ChatBotKit')
10
- .addCommand(index_js_1.default);
12
+ .description('Partner tools for ChatBotKit');
13
+ for (const cmd of Object.values(commands)) {
14
+ exports.command.addCommand(cmd);
15
+ }
11
16
  exports.default = exports.command;
@@ -47,10 +47,15 @@ exports.userDelete = new commander_1.Command()
47
47
  const client = getClient();
48
48
  await client.delete(userId);
49
49
  });
50
+ const commands = {
51
+ list: exports.userList,
52
+ fetch: exports.userFetch,
53
+ delete: exports.userDelete,
54
+ };
50
55
  exports.command = new commander_1.Command()
51
56
  .name('user')
52
- .description('User tools for ChatBotKit')
53
- .addCommand(exports.userList)
54
- .addCommand(exports.userFetch)
55
- .addCommand(exports.userDelete);
57
+ .description('User tools for ChatBotKit');
58
+ for (const cmd of Object.values(commands)) {
59
+ exports.command.addCommand(cmd);
60
+ }
56
61
  exports.default = exports.command;
@@ -47,10 +47,15 @@ exports.skillsetDelete = new commander_1.Command()
47
47
  const client = getClient();
48
48
  await client.delete(skillsetId);
49
49
  });
50
+ const commands = {
51
+ list: exports.skillsetList,
52
+ fetch: exports.skillsetFetch,
53
+ delete: exports.skillsetDelete,
54
+ };
50
55
  exports.command = new commander_1.Command()
51
56
  .name('skillset')
52
- .description('Skillset tools for ChatBotKit')
53
- .addCommand(exports.skillsetList)
54
- .addCommand(exports.skillsetFetch)
55
- .addCommand(exports.skillsetDelete);
57
+ .description('Skillset tools for ChatBotKit');
58
+ for (const cmd of Object.values(commands)) {
59
+ exports.command.addCommand(cmd);
60
+ }
56
61
  exports.default = exports.command;
@@ -3,11 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.command = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const env_js_1 = require("../../env.cjs");
6
- const index_js_1 = require("@chatbotkit/sdk/conversation/index.js");
6
+ const spinner_js_1 = require("../../spinner.cjs");
7
+ const tools_js_1 = require("../../tools.cjs");
8
+ const agent_1 = require("@chatbotkit/agent");
9
+ const sdk_1 = require("@chatbotkit/sdk");
7
10
  const commander_1 = require("commander");
8
11
  const promises_1 = tslib_1.__importDefault(require("readline/promises"));
9
12
  function getClient() {
10
- return new index_js_1.ConversationClient({
13
+ return new sdk_1.ChatBotKit({
11
14
  secret: (0, env_js_1.getSECRET)(),
12
15
  runAsUserId: (0, env_js_1.getRUNAS_USERID)(),
13
16
  });
@@ -15,28 +18,50 @@ function getClient() {
15
18
  exports.command = new commander_1.Command()
16
19
  .name('chat')
17
20
  .description('Start a chat session')
18
- .addOption(new commander_1.Option('-m, --model <model>', 'Model name').default('gpt-4'))
19
- .action(async (_arg, options) => {
21
+ .addOption(new commander_1.Option('-b, --bot <bot>', 'Bot id'))
22
+ .addOption(new commander_1.Option('-m, --model <model>', 'Model name'))
23
+ .addOption(new commander_1.Option('-t, --tools <tools...>', 'Specific tools to enable').choices((0, tools_js_1.getToolNames)()))
24
+ .action(async (options) => {
20
25
  const client = getClient();
21
26
  const rl = promises_1.default.createInterface({
22
27
  input: process.stdin,
23
28
  output: process.stdout,
24
29
  });
25
30
  const messages = [];
31
+ const tools = (0, tools_js_1.getTools)(options.tools);
32
+ const colors = {
33
+ reset: '\x1b[0m',
34
+ bold: '\x1b[1m',
35
+ cyan: '\x1b[36m',
36
+ green: '\x1b[32m',
37
+ };
26
38
  for (;;) {
27
- const user = await rl.question('user: ');
39
+ process.stdout.write('\n');
40
+ const user = await rl.question(`${colors.cyan}●${colors.reset} ${colors.bold}You${colors.reset}\n\n> `);
28
41
  messages.push({ type: 'user', text: user });
29
- process.stdout.write('bot: ');
30
- for await (const { type, data } of client
31
- .complete(null, { model: options.model, messages })
32
- .stream()) {
42
+ process.stdout.write(`\n${colors.green}●${colors.reset} ${colors.bold}Assistant${colors.reset}\n\n `);
43
+ const spinner = new spinner_js_1.Spinner('');
44
+ spinner.start();
45
+ let firstToken = true;
46
+ for await (const { type, data } of (0, agent_1.complete)({
47
+ client,
48
+ botId: options.bot,
49
+ model: options.model,
50
+ messages,
51
+ tools,
52
+ })) {
33
53
  if (type === 'token') {
54
+ if (firstToken) {
55
+ spinner.stop();
56
+ firstToken = false;
57
+ }
34
58
  process.stdout.write(data.token);
35
59
  }
36
60
  else if (type === 'result') {
37
61
  messages.push({ type: 'bot', text: data.text });
38
62
  }
39
63
  }
64
+ spinner.stop();
40
65
  process.stdout.write('\n');
41
66
  }
42
67
  });
@@ -2,15 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = cbk;
4
4
  const tslib_1 = require("tslib");
5
- const index_js_1 = tslib_1.__importDefault(require("./command/api/index.cjs"));
6
- const index_js_2 = tslib_1.__importDefault(require("./command/chat/index.cjs"));
7
- const index_js_3 = tslib_1.__importDefault(require("./command/solution/index.cjs"));
5
+ const index_js_1 = tslib_1.__importDefault(require("./command/agent/index.cjs"));
6
+ const index_js_2 = tslib_1.__importDefault(require("./command/api/index.cjs"));
7
+ const index_js_3 = tslib_1.__importDefault(require("./command/chat/index.cjs"));
8
+ const index_js_4 = tslib_1.__importDefault(require("./command/solution/index.cjs"));
8
9
  const commander_1 = require("commander");
9
10
  async function cbk(argv = process.argv) {
10
11
  const program = new commander_1.Command();
11
12
  program.name('cbk').description('Command line tools for ChatBotKit');
12
- program.addCommand(index_js_1.default);
13
13
  program.addCommand(index_js_2.default);
14
+ program.addCommand(index_js_1.default);
14
15
  program.addCommand(index_js_3.default);
16
+ program.addCommand(index_js_4.default);
15
17
  program.parse(argv);
16
18
  }
@@ -33,10 +33,14 @@ function print(input) {
33
33
  }
34
34
  }
35
35
  function printError(error) {
36
+ if (error?.code === 'ABORT_ERR' || error?.name === 'AbortError') {
37
+ process.exit(130);
38
+ }
36
39
  if (error instanceof CommandError) {
37
40
  console.error(error.message);
38
41
  }
39
42
  else {
40
43
  console.error(error);
41
44
  }
45
+ process.exit(1);
42
46
  }
@@ -110,8 +110,8 @@ class Resource {
110
110
  return this.config.type;
111
111
  }
112
112
  get slug() {
113
- var _a;
114
- return ((_a = this.config.slug) !== null && _a !== void 0 ? _a : this.config.name.toLowerCase().replace(/\W/g, '_').replace(/_+/g, '_'));
113
+ return (this.config.slug ??
114
+ this.config.name.toLowerCase().replace(/\W/g, '_').replace(/_+/g, '_'));
115
115
  }
116
116
  get id() {
117
117
  return this.config.id;
@@ -310,7 +310,7 @@ class ArrayBackedObject {
310
310
  this.array = array;
311
311
  return new Proxy(this, {
312
312
  get: (target, property) => {
313
- const item = target.array.find((item) => { var _a; return ((_a = (item)) === null || _a === void 0 ? void 0 : _a.slug) === property; });
313
+ const item = target.array.find((item) => (item)?.slug === property);
314
314
  if (item) {
315
315
  return item;
316
316
  }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Spinner = void 0;
4
+ class Spinner {
5
+ constructor(text = '', options = {}) {
6
+ this.text = text;
7
+ this.frames = options.frames || [
8
+ '⠋',
9
+ '⠙',
10
+ '⠹',
11
+ '⠸',
12
+ '⠼',
13
+ '⠴',
14
+ '⠦',
15
+ '⠧',
16
+ '⠇',
17
+ '⠏',
18
+ ];
19
+ this.interval = options.interval || 80;
20
+ this.frameIndex = 0;
21
+ this.intervalId = null;
22
+ this.isSpinning = false;
23
+ }
24
+ start() {
25
+ if (this.isSpinning) {
26
+ return;
27
+ }
28
+ this.isSpinning = true;
29
+ this.frameIndex = 0;
30
+ this.intervalId = setInterval(() => {
31
+ const frame = this.frames[this.frameIndex];
32
+ process.stdout.write(`\r${this.text}${frame} `);
33
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
34
+ }, this.interval);
35
+ }
36
+ stop(keepText = true) {
37
+ if (!this.isSpinning) {
38
+ return;
39
+ }
40
+ this.isSpinning = false;
41
+ if (this.intervalId) {
42
+ clearInterval(this.intervalId);
43
+ this.intervalId = null;
44
+ }
45
+ if (keepText) {
46
+ process.stdout.write(`\r${this.text}`);
47
+ }
48
+ else {
49
+ process.stdout.write('\r' + ' '.repeat(this.text.length + 2) + '\r');
50
+ }
51
+ }
52
+ setText(text) {
53
+ this.text = text;
54
+ }
55
+ }
56
+ exports.Spinner = Spinner;
@@ -0,0 +1,15 @@
1
+ export class Spinner {
2
+ constructor(text?: string, options?: {
3
+ frames?: string[];
4
+ interval?: number;
5
+ });
6
+ text: string;
7
+ frames: string[];
8
+ interval: number;
9
+ frameIndex: number;
10
+ intervalId: NodeJS.Timeout;
11
+ isSpinning: boolean;
12
+ start(): void;
13
+ stop(keepText?: boolean): void;
14
+ setText(text: string): void;
15
+ }