@boltic/cli 1.0.41 → 1.0.42

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
@@ -112,7 +112,11 @@ Boltic CLI uses a secure OAuth 2.0 flow with browser-based authentication for en
112
112
  ### Initial Login
113
113
 
114
114
  ```bash
115
+ # Interactive browser login
115
116
  boltic login
117
+
118
+ # Login with Permanent Access Token (PAT)
119
+ boltic login --token YOUR_PAT_TOKEN --account-id YOUR_ACCOUNT_ID
116
120
  ```
117
121
 
118
122
  The authentication process follows these steps:
@@ -401,6 +405,48 @@ boltic serverless status
401
405
 
402
406
  # Check status by name
403
407
  boltic serverless status --name my-function
408
+
409
+ # Watch status until running/failed/degraded
410
+ boltic serverless status --name my-function --watch
411
+ ```
412
+
413
+ ### Viewing Builds
414
+
415
+ ```bash
416
+ # List all builds for a serverless function
417
+ boltic serverless builds
418
+
419
+ # List builds by name
420
+ boltic serverless builds --name my-function
421
+ ```
422
+
423
+ ### Viewing Logs
424
+
425
+ ```bash
426
+ # View runtime logs (interactive selection)
427
+ boltic serverless logs
428
+
429
+ # View logs by name
430
+ boltic serverless logs --name my-function
431
+
432
+ # Follow logs in real-time
433
+ boltic serverless logs --name my-function --follow
434
+
435
+ # Limit number of lines
436
+ boltic serverless logs --name my-function --lines 50
437
+ ```
438
+
439
+ ### Viewing Build Logs
440
+
441
+ ```bash
442
+ # View build logs (interactive selection)
443
+ boltic serverless build logs
444
+
445
+ # View build logs by name (will prompt for build selection)
446
+ boltic serverless build logs --name my-function
447
+
448
+ # View specific build logs
449
+ boltic serverless build logs --name my-function --build BUILD_ID
404
450
  ```
405
451
 
406
452
  ---
@@ -409,12 +455,12 @@ boltic serverless status --name my-function
409
455
 
410
456
  ### Core Commands
411
457
 
412
- | Command | Description | Options |
413
- | ---------------- | --------------------------------- | ------- |
414
- | `boltic login` | Authenticate with Boltic platform | |
415
- | `boltic logout` | Clear stored credentials | |
416
- | `boltic version` | Display CLI version | |
417
- | `boltic help` | Show comprehensive help | |
458
+ | Command | Description | Options |
459
+ | ---------------- | --------------------------------- | ---------------------------------------- |
460
+ | `boltic login` | Authenticate with Boltic platform | `--token` `--account-id` |
461
+ | `boltic logout` | Clear stored credentials | |
462
+ | `boltic version` | Display CLI version | |
463
+ | `boltic help` | Show comprehensive help | |
418
464
 
419
465
  ### Integration Commands
420
466
 
@@ -437,15 +483,18 @@ boltic serverless status --name my-function
437
483
 
438
484
  ### Serverless Commands
439
485
 
440
- | Command | Description | Options |
441
- | ---------------------------- | ------------------------------------ | ---------------------------------------------------- |
442
- | `boltic serverless create` | Create a new serverless function | `--type, -t` `--name, -n` `--language, -l` `--directory, -d` |
443
- | `boltic serverless test` | Test serverless function locally | `--port, -p` `--language, -l` `--directory, -d` |
444
- | `boltic serverless publish` | Publish/deploy serverless function | `--directory, -d` |
445
- | `boltic serverless pull` | Pull existing serverless function | `--path` |
446
- | `boltic serverless list` | List all serverless functions | |
447
- | `boltic serverless status` | Show status of a serverless function | `--name, -n` |
448
- | `boltic serverless help` | Show help for serverless commands | |
486
+ | Command | Description | Options |
487
+ | ------------------------------- | ------------------------------------ | ---------------------------------------------------- |
488
+ | `boltic serverless create` | Create a new serverless function | `--type, -t` `--name, -n` `--language, -l` `--directory, -d` |
489
+ | `boltic serverless test` | Test serverless function locally | `--port, -p` `--language, -l` `--directory, -d` |
490
+ | `boltic serverless publish` | Publish/deploy serverless function | `--directory, -d` |
491
+ | `boltic serverless pull` | Pull existing serverless function | `--path` |
492
+ | `boltic serverless list` | List all serverless functions | |
493
+ | `boltic serverless status` | Show status of a serverless function | `--name, -n` `--watch, -w` |
494
+ | `boltic serverless builds` | List builds for a serverless | `--name, -n` |
495
+ | `boltic serverless logs` | Show runtime logs | `--name, -n` `--follow, -f` `--lines, -l` |
496
+ | `boltic serverless build logs` | Show logs for a specific build | `--name, -n` `--build, -b` |
497
+ | `boltic serverless help` | Show help for serverless commands | |
449
498
 
450
499
  ### Help and Documentation
451
500
 
package/api/serverless.js CHANGED
@@ -3,7 +3,7 @@ import FormData from "form-data";
3
3
  import fs from "fs";
4
4
  import https from "https";
5
5
  import { handleError } from "../helper/error.js";
6
- import { logApi } from "../helper/verbose.js";
6
+ import { logApi, logApiRequest, logApiResponse } from "../helper/verbose.js";
7
7
 
8
8
  const getHttpsAgentForUrl = (baseUrl) => {
9
9
  try {
@@ -62,8 +62,12 @@ const listAllServerless = async (
62
62
  httpsAgent: getHttpsAgentForUrl(apiUrl),
63
63
  };
64
64
 
65
+ logApiRequest(
66
+ axiosOptions.method,
67
+ `${axiosOptions.url}?${new URLSearchParams(params).toString()}`
68
+ );
65
69
  const response = await axios(axiosOptions);
66
- logApi(axiosOptions.method, axiosOptions.url, response.status);
70
+ logApiResponse(response.status, response.data);
67
71
  return response.data.data;
68
72
  } catch (error) {
69
73
  handleError(error);
@@ -80,9 +84,11 @@ const pullServerless = async (apiUrl, token, accountId, session, id) => {
80
84
  process.exit(1); // Exit the CLI with an error code
81
85
  }
82
86
  try {
87
+ const url = `${apiUrl}/service/panel/serverless/v1.0/apps/${id}`;
88
+ logApiRequest("get", url);
83
89
  const response = await axios({
84
90
  method: "get",
85
- url: `${apiUrl}/service/panel/serverless/v1.0/apps/${id}`,
91
+ url,
86
92
  headers: {
87
93
  "Content-Type": "application/json",
88
94
  Authorization: `Bearer ${token}`,
@@ -90,6 +96,7 @@ const pullServerless = async (apiUrl, token, accountId, session, id) => {
90
96
  },
91
97
  httpsAgent: getHttpsAgentForUrl(apiUrl),
92
98
  });
99
+ logApiResponse(response.status, response?.data);
93
100
  return response?.data;
94
101
  } catch (error) {
95
102
  handleError(error);
@@ -166,9 +173,147 @@ const updateServerless = async (
166
173
  }
167
174
  };
168
175
 
176
+ const getServerlessBuilds = async (
177
+ apiUrl,
178
+ token,
179
+ accountId,
180
+ session,
181
+ serverlessId,
182
+ options = {}
183
+ ) => {
184
+ if (!token || !session || !accountId) {
185
+ console.error(
186
+ "\x1b[31mError:\x1b[0m Authentication credentials are required."
187
+ );
188
+ console.log("\n🔹 Please log in first using:");
189
+ console.log("\x1b[32m$ boltic login\x1b[0m\n");
190
+ process.exit(1);
191
+ }
192
+ try {
193
+ const axiosOptions = {
194
+ method: "get",
195
+ url: `${apiUrl}/service/panel/serverless/v1.0/apps/${serverlessId}/builds`,
196
+ params: {
197
+ page: options.page || 1,
198
+ limit: options.limit || 20,
199
+ sortBy: "CreatedAt",
200
+ sortOrder: "desc",
201
+ },
202
+ headers: {
203
+ "Content-Type": "application/json",
204
+ Authorization: `Bearer ${token}`,
205
+ Cookie: session,
206
+ },
207
+ httpsAgent: getHttpsAgentForUrl(apiUrl),
208
+ };
209
+
210
+ const response = await axios(axiosOptions);
211
+ logApi(axiosOptions.method, axiosOptions.url, response.status);
212
+ return response.data;
213
+ } catch (error) {
214
+ handleError(error);
215
+ }
216
+ };
217
+
218
+ const getServerlessLogs = async (
219
+ apiUrl,
220
+ token,
221
+ accountId,
222
+ session,
223
+ serverlessId,
224
+ options = {}
225
+ ) => {
226
+ if (!token || !session || !accountId) {
227
+ console.error(
228
+ "\x1b[31mError:\x1b[0m Authentication credentials are required."
229
+ );
230
+ console.log("\n🔹 Please log in first using:");
231
+ console.log("\x1b[32m$ boltic login\x1b[0m\n");
232
+ process.exit(1);
233
+ }
234
+ try {
235
+ // Calculate timestamp range (default: last 24 hours)
236
+ const now = Math.floor(Date.now() / 1000);
237
+ const defaultStart = now - 24 * 60 * 60; // 24 hours ago
238
+
239
+ const params = {
240
+ page: options.page || 1,
241
+ limit: options.limit || 50,
242
+ sortBy: "Timestamp",
243
+ sortOrder: options.sortOrder || "DESC",
244
+ timestampStart: options.timestampStart || defaultStart,
245
+ timestampEnd: options.timestampEnd || now,
246
+ metric_interval: 60,
247
+ };
248
+
249
+ const axiosOptions = {
250
+ method: "get",
251
+ url: `${apiUrl}/service/panel/serverless/v1.0/apps/${serverlessId}/logs`,
252
+ params,
253
+ headers: {
254
+ "Content-Type": "application/json",
255
+ Authorization: `Bearer ${token}`,
256
+ Cookie: session,
257
+ },
258
+ httpsAgent: getHttpsAgentForUrl(apiUrl),
259
+ };
260
+
261
+ const response = await axios(axiosOptions);
262
+ logApi(axiosOptions.method, axiosOptions.url, response.status);
263
+ return response.data;
264
+ } catch (error) {
265
+ handleError(error);
266
+ }
267
+ };
268
+
269
+ const getBuildLogs = async (
270
+ apiUrl,
271
+ token,
272
+ accountId,
273
+ session,
274
+ serverlessId,
275
+ buildId
276
+ ) => {
277
+ if (!token || !session || !accountId) {
278
+ console.error(
279
+ "\x1b[31mError:\x1b[0m Authentication credentials are required."
280
+ );
281
+ console.log("\n🔹 Please log in first using:");
282
+ console.log("\x1b[32m$ boltic login\x1b[0m\n");
283
+ process.exit(1);
284
+ }
285
+ try {
286
+ const axiosOptions = {
287
+ method: "get",
288
+ url: `${apiUrl}/service/panel/serverless/v1.0/apps/${serverlessId}/builds/${buildId}/logs`,
289
+ params: {
290
+ limit: -1,
291
+ tail: false,
292
+ sortOrder: "asc",
293
+ sortBy: "Timestamp",
294
+ },
295
+ headers: {
296
+ "Content-Type": "application/json",
297
+ Authorization: `Bearer ${token}`,
298
+ Cookie: session,
299
+ },
300
+ httpsAgent: getHttpsAgentForUrl(apiUrl),
301
+ };
302
+
303
+ const response = await axios(axiosOptions);
304
+ logApi(axiosOptions.method, axiosOptions.url, response.status);
305
+ return response.data;
306
+ } catch (error) {
307
+ handleError(error);
308
+ }
309
+ };
310
+
169
311
  export {
170
312
  listAllServerless,
171
313
  pullServerless,
172
314
  publishServerless,
173
315
  updateServerless,
316
+ getServerlessBuilds,
317
+ getServerlessLogs,
318
+ getBuildLogs,
174
319
  };
package/cli.js CHANGED
@@ -19,67 +19,74 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
19
19
  description: "Authenticate the user and save access token",
20
20
  action: async (args) => {
21
21
  // Support PAT-based login via flags, e.g.:
22
- // boltic login --pat XXXXX --account_id YYYYYY
23
- // boltic login --pat=XXXXX --account-id=YYYYYY
24
- let patFromArg;
25
- let accountIdFromArg;
26
- let hasPatFlag = false;
27
- let hasAccountIdFlag = false;
22
+ // boltic login --token XXXXX --account-id YYYYYY
23
+ // boltic login --token=XXXXX --acc-id=YYYYYY
24
+ let tokenFromArg;
25
+ let orgIdFromArg;
26
+ let hasTokenFlag = false;
27
+ let hasOrgIdFlag = false;
28
28
 
29
29
  for (let i = 0; i < args.length; i++) {
30
30
  const arg = args[i];
31
31
 
32
- if (arg === "--pat") {
33
- hasPatFlag = true;
32
+ if (arg === "--token") {
33
+ hasTokenFlag = true;
34
34
  if (
35
35
  i + 1 < args.length &&
36
36
  !args[i + 1].startsWith("--")
37
37
  ) {
38
- patFromArg = args[i + 1];
38
+ tokenFromArg = args[i + 1];
39
39
  i++;
40
40
  }
41
41
  continue;
42
42
  }
43
43
 
44
- if (arg === "--account_id" || arg === "--account-id") {
45
- hasAccountIdFlag = true;
44
+ if (
45
+ arg === "--account_id" ||
46
+ arg === "--account-id" ||
47
+ arg === "--acc_id" ||
48
+ arg === "--acc-id"
49
+ ) {
50
+ hasOrgIdFlag = true;
46
51
  if (
47
52
  i + 1 < args.length &&
48
53
  !args[i + 1].startsWith("--")
49
54
  ) {
50
- accountIdFromArg = args[i + 1];
55
+ orgIdFromArg = args[i + 1];
51
56
  i++;
52
57
  }
53
58
  continue;
54
59
  }
55
60
 
56
- if (arg.startsWith("--pat=")) {
57
- hasPatFlag = true;
58
- patFromArg = arg.split("=")[1];
61
+ if (arg.startsWith("--token=")) {
62
+ hasTokenFlag = true;
63
+ tokenFromArg = arg.split("=")[1];
59
64
  continue;
60
65
  }
61
66
 
62
67
  if (
63
68
  arg.startsWith("--account_id=") ||
64
- arg.startsWith("--account-id=")
69
+ arg.startsWith("--account-id=") ||
70
+ arg.startsWith("--acc_id=") ||
71
+ arg.startsWith("--acc-id=")
65
72
  ) {
66
- hasAccountIdFlag = true;
67
- accountIdFromArg = arg.split("=")[1];
73
+ hasOrgIdFlag = true;
74
+ orgIdFromArg = arg.split("=")[1];
68
75
  continue;
69
76
  }
70
77
  }
71
78
 
72
- // If any PAT-related flag is present, delegate to PAT login handler.
79
+ // If any token-related flag is present, delegate to PAT login handler.
73
80
  // `handlePatLogin` will decide whether to prompt based on which values are provided.
74
81
  if (
75
- hasPatFlag ||
76
- hasAccountIdFlag ||
77
- patFromArg ||
78
- accountIdFromArg
82
+ hasTokenFlag ||
83
+ hasOrgIdFlag ||
84
+ tokenFromArg ||
85
+ orgIdFromArg
79
86
  ) {
80
87
  await AuthCommands.handlePatLogin(
81
- patFromArg,
82
- accountIdFromArg
88
+ tokenFromArg,
89
+ orgIdFromArg
83
90
  );
84
91
  return;
85
92
  }
@@ -128,13 +135,15 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
128
135
  }
129
136
 
130
137
  const command = args[2];
131
- const subCommand = args.length >= 3 ? args[3] : undefined;
132
138
 
133
- if (!command) {
139
+ // Show global help only if no command or command is --help/-h
140
+ if (!command || command === "--help" || command === "-h") {
134
141
  showHelp(commands);
135
142
  return;
136
143
  }
137
144
 
145
+ const subCommand = args.length >= 3 ? args[3] : undefined;
146
+
138
147
  if (!commands[command]) {
139
148
  console.log(
140
149
  chalk.bgRed.white("\n ❌ Error ") +
@@ -217,15 +226,41 @@ async function showHelp(commands) {
217
226
  }
218
227
 
219
228
  console.log(chalk.bold.yellow(`\nBoltic CLI Version: ${version}\n`));
220
- console.log("\nUsage: boltic [command]\n");
221
- console.log("Available commands:");
229
+ console.log(chalk.cyan("Usage:") + " boltic [command] [options]\n");
230
+
231
+ console.log(chalk.cyan("Commands:"));
222
232
  Object.keys(commands).forEach((cmd) => {
223
- console.log(` ${cmd} - ${commands[cmd].description}`);
233
+ console.log(
234
+ chalk.bold(` ${cmd.padEnd(15)}`) + commands[cmd].description
235
+ );
224
236
  });
225
- console.log("\nExamples:");
226
- console.log(" boltic login");
227
- console.log(" boltic integration create");
228
- console.log(" boltic help\n");
237
+
238
+ console.log(chalk.cyan("\nGlobal Options:"));
239
+ console.log(
240
+ chalk.bold(" --help, -h".padEnd(18)) + "Show help for a command"
241
+ );
242
+ console.log(chalk.bold(" --verbose".padEnd(18)) + "Enable verbose output");
243
+
244
+ console.log(chalk.cyan("\nLogin Options:"));
245
+ console.log(
246
+ chalk.bold(" --token <token>".padEnd(18)) + "Personal access token"
247
+ );
248
+ console.log(
249
+ chalk.bold(" --account-id <id>".padEnd(18)) +
250
+ "Account ID (alias: --acc-id)"
251
+ );
252
+
253
+ console.log(chalk.cyan("\nExamples:"));
254
+ console.log(chalk.dim(" # Interactive browser login"));
255
+ console.log(" boltic login\n");
256
+ console.log(chalk.dim(" # Login with PAT token"));
257
+ console.log(
258
+ " boltic login --token YOUR_TOKEN --account-id YOUR_ACCOUNT_ID\n"
259
+ );
260
+ console.log(chalk.dim(" # Get help for serverless commands"));
261
+ console.log(" boltic serverless --help\n");
262
+ console.log(chalk.dim(" # Create an integration"));
263
+ console.log(" boltic integration create\n");
229
264
  }
230
265
 
231
266
  async function handleIntegration(args) {
package/commands/env.js CHANGED
@@ -23,13 +23,22 @@ const commands = {
23
23
  const execute = async (args) => {
24
24
  const subCommand = args[0];
25
25
 
26
- if (!subCommand) {
26
+ // Handle help flags
27
+ if (
28
+ !subCommand ||
29
+ subCommand === "--help" ||
30
+ subCommand === "-h" ||
31
+ args.includes("--help") ||
32
+ args.includes("-h")
33
+ ) {
27
34
  showHelp();
28
35
  return;
29
36
  }
30
37
 
31
38
  if (!commands[subCommand]) {
32
- console.log(chalk.red("Unknown or missing environment sub-command.\n"));
39
+ console.log(
40
+ chalk.red(`Unknown environment command: "${subCommand}"\n`)
41
+ );
33
42
  showHelp();
34
43
  return;
35
44
  }
@@ -456,13 +456,22 @@ async function handlePublish(args) {
456
456
  const execute = async (args) => {
457
457
  const subCommand = args[0];
458
458
 
459
- if (!subCommand) {
459
+ // Handle help flags
460
+ if (
461
+ !subCommand ||
462
+ subCommand === "--help" ||
463
+ subCommand === "-h" ||
464
+ args.includes("--help") ||
465
+ args.includes("-h")
466
+ ) {
460
467
  showHelp();
461
468
  return;
462
469
  }
463
470
 
464
471
  if (!commands[subCommand]) {
465
- console.log(chalk.red("Unknown or missing integration sub-command.\n"));
472
+ console.log(
473
+ chalk.red(`Unknown integration command: "${subCommand}"\n`)
474
+ );
466
475
  showHelp();
467
476
  return;
468
477
  }
package/commands/mcp.js CHANGED
@@ -22,13 +22,20 @@ const commands = {
22
22
  const execute = async (args) => {
23
23
  const subCommand = args[0];
24
24
 
25
- if (!subCommand) {
25
+ // Handle help flags
26
+ if (
27
+ !subCommand ||
28
+ subCommand === "--help" ||
29
+ subCommand === "-h" ||
30
+ args.includes("--help") ||
31
+ args.includes("-h")
32
+ ) {
26
33
  showHelp();
27
34
  return;
28
35
  }
29
36
 
30
37
  if (!commands[subCommand]) {
31
- console.log(chalk.red("Unknown or missing mcp sub-command.\n"));
38
+ console.log(chalk.red(`Unknown mcp command: "${subCommand}"\n`));
32
39
  showHelp();
33
40
  return;
34
41
  }