@boltic/cli 1.0.38 → 1.0.40
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 +123 -5
- package/api/serverless.js +174 -0
- package/cli.js +71 -3
- package/commands/login.js +77 -8
- package/commands/serverless.js +1942 -0
- package/helper/serverless.js +1932 -0
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ⚡ Boltic CLI
|
|
2
2
|
|
|
3
|
-
> **Professional CLI for interacting with the Boltic platform — create, manage, and publish integrations, workflows, MCPs, and more with enterprise-grade features and a seamless developer experience.**
|
|
3
|
+
> **Professional CLI for interacting with the Boltic platform — create, manage, and publish integrations, serverless functions, workflows, MCPs, and more with enterprise-grade features and a seamless developer experience.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@boltic/cli)
|
|
6
6
|
[](https://github.com/bolticio/cli)
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
- [🔐 Authentication](#-authentication)
|
|
30
30
|
- [🧩 Integration Management](#-integration-management)
|
|
31
31
|
- [🧠 MCP](#-mcp-model-context-protocol)
|
|
32
|
+
- [⚡ Serverless Functions](#-serverless-functions)
|
|
32
33
|
- [📚 Command Reference](#-command-reference)
|
|
33
34
|
- [🛠️ Development Workflow](#️-development-workflow)
|
|
34
35
|
- [🔧 Configuration](#-configuration)
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
|
|
45
46
|
- 🔐 **Secure Authentication** - Enterprise-grade token management with secure storage
|
|
46
47
|
- 🚀 **Rapid Development** - Create workflows, integrations, and more in minutes, not hours
|
|
48
|
+
- ⚡ **Serverless Functions** - Deploy functions in Node.js, Python, Golang, or Java with local testing
|
|
47
49
|
- 📦 **Smart Project Management** - Automated folder structure and configuration
|
|
48
50
|
- 🔄 **Real-time Synchronization** - Instant sync with Boltic Cloud platform
|
|
49
51
|
- 🎯 **Type-safe Development** - Support for Workflow Activities and Triggers
|
|
@@ -69,11 +71,14 @@ boltic login
|
|
|
69
71
|
# Create your first integration
|
|
70
72
|
boltic integration create
|
|
71
73
|
|
|
72
|
-
#
|
|
73
|
-
boltic
|
|
74
|
+
# Or create a serverless function
|
|
75
|
+
boltic serverless create --type blueprint --name my-api --language nodejs
|
|
74
76
|
|
|
75
|
-
#
|
|
76
|
-
boltic
|
|
77
|
+
# Test locally
|
|
78
|
+
boltic serverless test
|
|
79
|
+
|
|
80
|
+
# Deploy to Boltic Cloud
|
|
81
|
+
boltic serverless publish
|
|
77
82
|
```
|
|
78
83
|
|
|
79
84
|
---
|
|
@@ -299,6 +304,107 @@ boltic mcp setup https://mcp.boltic.io/sse my-boltic --client claude
|
|
|
299
304
|
|
|
300
305
|
---
|
|
301
306
|
|
|
307
|
+
## ⚡ Serverless Functions
|
|
308
|
+
|
|
309
|
+
Create, test, and deploy serverless functions on the Boltic platform with support for multiple languages and deployment types.
|
|
310
|
+
|
|
311
|
+
### Supported Languages
|
|
312
|
+
|
|
313
|
+
| Language | Version | Handler |
|
|
314
|
+
|----------|---------|---------|
|
|
315
|
+
| Node.js | 20 | `handler.handler` |
|
|
316
|
+
| Python | 3 | `index.handler` |
|
|
317
|
+
| Golang | 1.22 | `Handler` |
|
|
318
|
+
| Java | 17 | `Handler` |
|
|
319
|
+
|
|
320
|
+
### Deployment Types
|
|
321
|
+
|
|
322
|
+
| Type | Description |
|
|
323
|
+
|------|-------------|
|
|
324
|
+
| **Blueprint** | Write code directly in the CLI-generated project |
|
|
325
|
+
| **Git** | Deploy from a Git repository |
|
|
326
|
+
| **Container** | Deploy a Docker container |
|
|
327
|
+
|
|
328
|
+
### Creating Serverless Functions
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Interactive mode (prompts for all options)
|
|
332
|
+
boltic serverless create
|
|
333
|
+
|
|
334
|
+
# Create a blueprint serverless function
|
|
335
|
+
boltic serverless create --type blueprint --name my-api --language nodejs
|
|
336
|
+
|
|
337
|
+
# Create a git-based serverless function
|
|
338
|
+
boltic serverless create --type git --name my-git-func --language python
|
|
339
|
+
|
|
340
|
+
# Create a container-based serverless function
|
|
341
|
+
boltic serverless create --type container --name my-container
|
|
342
|
+
|
|
343
|
+
# Specify custom directory
|
|
344
|
+
boltic serverless create --type blueprint --name my-function --language python --directory ./projects
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
#### Generated Project Structure
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
my-serverless/
|
|
351
|
+
├── boltic.yaml # Configuration file with serverless settings
|
|
352
|
+
├── handler.js # Handler file (Node.js) or index.py (Python), etc.
|
|
353
|
+
└── package.json # Dependencies (for Node.js projects)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Testing Locally
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Auto-detect language and run on default port (8080)
|
|
360
|
+
boltic serverless test
|
|
361
|
+
|
|
362
|
+
# Specify custom port
|
|
363
|
+
boltic serverless test --port 3000
|
|
364
|
+
|
|
365
|
+
# Test from specific directory
|
|
366
|
+
boltic serverless test --directory ./my-function
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Publishing
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# Publish from current directory
|
|
373
|
+
boltic serverless publish
|
|
374
|
+
|
|
375
|
+
# Publish from specific directory
|
|
376
|
+
boltic serverless publish --directory ./my-function
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Pulling Existing Functions
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
# Pull a serverless function (interactive selection)
|
|
383
|
+
boltic serverless pull
|
|
384
|
+
|
|
385
|
+
# Pull to a specific path
|
|
386
|
+
boltic serverless pull --path ./projects
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Listing Functions
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# List all serverless functions
|
|
393
|
+
boltic serverless list
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Checking Status
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Check status (interactive selection)
|
|
400
|
+
boltic serverless status
|
|
401
|
+
|
|
402
|
+
# Check status by name
|
|
403
|
+
boltic serverless status --name my-function
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
302
408
|
## 📚 Command Reference
|
|
303
409
|
|
|
304
410
|
### Core Commands
|
|
@@ -329,6 +435,18 @@ boltic mcp setup https://mcp.boltic.io/sse my-boltic --client claude
|
|
|
329
435
|
| `boltic mcp help` | Show help for MCP sub-commands | |
|
|
330
436
|
| `boltic mcp setup` | Configure an MCP server for a specific client| `--client <name>` `--name <alias>`|
|
|
331
437
|
|
|
438
|
+
### Serverless Commands
|
|
439
|
+
|
|
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 | |
|
|
449
|
+
|
|
332
450
|
### Help and Documentation
|
|
333
451
|
|
|
334
452
|
```bash
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import FormData from "form-data";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import https from "https";
|
|
5
|
+
import { handleError } from "../helper/error.js";
|
|
6
|
+
import { logApi } from "../helper/verbose.js";
|
|
7
|
+
|
|
8
|
+
const getHttpsAgentForUrl = (baseUrl) => {
|
|
9
|
+
try {
|
|
10
|
+
const host = new URL(baseUrl).hostname;
|
|
11
|
+
if (
|
|
12
|
+
host.endsWith("fcz0.de") ||
|
|
13
|
+
host.endsWith("uat.fcz0.de") ||
|
|
14
|
+
host.endsWith("fyndx1.de") ||
|
|
15
|
+
process.env.BOLTCI_INSECURE_TLS === "true"
|
|
16
|
+
) {
|
|
17
|
+
return new https.Agent({ rejectUnauthorized: false });
|
|
18
|
+
}
|
|
19
|
+
} catch (_) {
|
|
20
|
+
// ignore URL parse errors and fall back to default agent
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const listAllServerless = async (
|
|
26
|
+
apiUrl,
|
|
27
|
+
token,
|
|
28
|
+
accountId,
|
|
29
|
+
session,
|
|
30
|
+
query = null
|
|
31
|
+
) => {
|
|
32
|
+
if (!token || !session || !accountId) {
|
|
33
|
+
console.error(
|
|
34
|
+
"\x1b[31mError:\x1b[0m Authentication credentials are required."
|
|
35
|
+
);
|
|
36
|
+
console.log("\n🔹 Please log in first using:");
|
|
37
|
+
console.log("\x1b[32m$ boltic login\x1b[0m\n");
|
|
38
|
+
process.exit(1); // Exit the CLI with an error code
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const params = {
|
|
42
|
+
page: 1,
|
|
43
|
+
limit: 999,
|
|
44
|
+
sortBy: "CreatedAt",
|
|
45
|
+
sortOrder: "desc",
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Add query parameter if provided
|
|
49
|
+
if (query) {
|
|
50
|
+
params.q = query;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const axiosOptions = {
|
|
54
|
+
method: "get",
|
|
55
|
+
url: `${apiUrl}/service/panel/serverless/v1.0/apps`,
|
|
56
|
+
params,
|
|
57
|
+
headers: {
|
|
58
|
+
"Content-Type": "application/json",
|
|
59
|
+
Authorization: `Bearer ${token}`,
|
|
60
|
+
Cookie: session,
|
|
61
|
+
},
|
|
62
|
+
httpsAgent: getHttpsAgentForUrl(apiUrl),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const response = await axios(axiosOptions);
|
|
66
|
+
logApi(axiosOptions.method, axiosOptions.url, response.status);
|
|
67
|
+
return response.data.data;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
handleError(error);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const pullServerless = async (apiUrl, token, accountId, session, id) => {
|
|
74
|
+
if (!token || !session || !accountId) {
|
|
75
|
+
console.error(
|
|
76
|
+
"\x1b[31mError:\x1b[0m Authentication credentials are required."
|
|
77
|
+
);
|
|
78
|
+
console.log("\n🔹 Please log in first using:");
|
|
79
|
+
console.log("\x1b[32m$ boltic login\x1b[0m\n");
|
|
80
|
+
process.exit(1); // Exit the CLI with an error code
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const response = await axios({
|
|
84
|
+
method: "get",
|
|
85
|
+
url: `${apiUrl}/service/panel/serverless/v1.0/apps/${id}`,
|
|
86
|
+
headers: {
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
Authorization: `Bearer ${token}`,
|
|
89
|
+
Cookie: session,
|
|
90
|
+
},
|
|
91
|
+
httpsAgent: getHttpsAgentForUrl(apiUrl),
|
|
92
|
+
});
|
|
93
|
+
return response?.data;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
handleError(error);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const publishServerless = async (apiUrl, token, session, payload) => {
|
|
100
|
+
if (!token || !session) {
|
|
101
|
+
console.error(
|
|
102
|
+
"\x1b[31mError:\x1b[0m Authentication credentials are required."
|
|
103
|
+
);
|
|
104
|
+
console.log("\n🔹 Please log in first using:");
|
|
105
|
+
console.log("\x1b[32m$ boltic login\x1b[0m\n");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const axiosOptions = {
|
|
111
|
+
method: "post",
|
|
112
|
+
url: `https://asia-south1.api.boltic.io/service/panel/serverless/v1.0/apps`,
|
|
113
|
+
headers: {
|
|
114
|
+
"Content-Type": "application/json",
|
|
115
|
+
Authorization: `Bearer ${token}`,
|
|
116
|
+
Cookie: session,
|
|
117
|
+
},
|
|
118
|
+
data: payload,
|
|
119
|
+
httpsAgent: getHttpsAgentForUrl(apiUrl),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const response = await axios(axiosOptions);
|
|
123
|
+
logApi(axiosOptions.method, axiosOptions.url, response.status);
|
|
124
|
+
return response.data;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
handleError(error);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const updateServerless = async (
|
|
132
|
+
apiUrl,
|
|
133
|
+
token,
|
|
134
|
+
session,
|
|
135
|
+
serverlessId,
|
|
136
|
+
payload
|
|
137
|
+
) => {
|
|
138
|
+
if (!token || !session) {
|
|
139
|
+
console.error(
|
|
140
|
+
"\x1b[31mError:\x1b[0m Authentication credentials are required."
|
|
141
|
+
);
|
|
142
|
+
console.log("\n🔹 Please log in first using:");
|
|
143
|
+
console.log("\x1b[32m$ boltic login\x1b[0m\n");
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const axiosOptions = {
|
|
149
|
+
method: "put",
|
|
150
|
+
url: `https://asia-south1.api.boltic.io/service/panel/serverless/v1.0/apps/${serverlessId}`,
|
|
151
|
+
headers: {
|
|
152
|
+
"Content-Type": "application/json",
|
|
153
|
+
Authorization: `Bearer ${token}`,
|
|
154
|
+
Cookie: session,
|
|
155
|
+
},
|
|
156
|
+
data: payload,
|
|
157
|
+
httpsAgent: getHttpsAgentForUrl(apiUrl),
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const response = await axios(axiosOptions);
|
|
161
|
+
logApi(axiosOptions.method, axiosOptions.url, response.status);
|
|
162
|
+
return response.data;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
handleError(error);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
listAllServerless,
|
|
171
|
+
pullServerless,
|
|
172
|
+
publishServerless,
|
|
173
|
+
updateServerless,
|
|
174
|
+
};
|
package/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import EnvironmentCommands from "./commands/env.js";
|
|
|
6
6
|
import IntegrationCommands from "./commands/integration.js";
|
|
7
7
|
import AuthCommands from "./commands/login.js";
|
|
8
8
|
import McpCommands from "./commands/mcp.js";
|
|
9
|
+
import ServerlessCommands from "./commands/serverless.js";
|
|
9
10
|
|
|
10
11
|
// Create a CLI module with functional approach
|
|
11
12
|
import { findSimilarCommands } from "./helper/command-suggestions.js";
|
|
@@ -17,9 +18,69 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
|
|
|
17
18
|
login: {
|
|
18
19
|
description: "Authenticate the user and save access token",
|
|
19
20
|
action: async (args) => {
|
|
20
|
-
// Support PAT-based login via
|
|
21
|
-
|
|
22
|
-
|
|
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;
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < args.length; i++) {
|
|
30
|
+
const arg = args[i];
|
|
31
|
+
|
|
32
|
+
if (arg === "--pat") {
|
|
33
|
+
hasPatFlag = true;
|
|
34
|
+
if (
|
|
35
|
+
i + 1 < args.length &&
|
|
36
|
+
!args[i + 1].startsWith("--")
|
|
37
|
+
) {
|
|
38
|
+
patFromArg = args[i + 1];
|
|
39
|
+
i++;
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (arg === "--account_id" || arg === "--account-id") {
|
|
45
|
+
hasAccountIdFlag = true;
|
|
46
|
+
if (
|
|
47
|
+
i + 1 < args.length &&
|
|
48
|
+
!args[i + 1].startsWith("--")
|
|
49
|
+
) {
|
|
50
|
+
accountIdFromArg = args[i + 1];
|
|
51
|
+
i++;
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (arg.startsWith("--pat=")) {
|
|
57
|
+
hasPatFlag = true;
|
|
58
|
+
patFromArg = arg.split("=")[1];
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
arg.startsWith("--account_id=") ||
|
|
64
|
+
arg.startsWith("--account-id=")
|
|
65
|
+
) {
|
|
66
|
+
hasAccountIdFlag = true;
|
|
67
|
+
accountIdFromArg = arg.split("=")[1];
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// If any PAT-related flag is present, delegate to PAT login handler.
|
|
73
|
+
// `handlePatLogin` will decide whether to prompt based on which values are provided.
|
|
74
|
+
if (
|
|
75
|
+
hasPatFlag ||
|
|
76
|
+
hasAccountIdFlag ||
|
|
77
|
+
patFromArg ||
|
|
78
|
+
accountIdFromArg
|
|
79
|
+
) {
|
|
80
|
+
await AuthCommands.handlePatLogin(
|
|
81
|
+
patFromArg,
|
|
82
|
+
accountIdFromArg
|
|
83
|
+
);
|
|
23
84
|
return;
|
|
24
85
|
}
|
|
25
86
|
|
|
@@ -50,6 +111,10 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
|
|
|
50
111
|
description: "Display the version of the CLI.",
|
|
51
112
|
action: () => showVersion(),
|
|
52
113
|
},
|
|
114
|
+
serverless: {
|
|
115
|
+
description: "Manage serverless (create, list, test)",
|
|
116
|
+
action: (args) => handleServerless(args),
|
|
117
|
+
},
|
|
53
118
|
};
|
|
54
119
|
|
|
55
120
|
return {
|
|
@@ -175,6 +240,9 @@ async function handleMcp(args) {
|
|
|
175
240
|
await McpCommands.execute(args);
|
|
176
241
|
}
|
|
177
242
|
|
|
243
|
+
async function handleServerless(args) {
|
|
244
|
+
await ServerlessCommands.execute(args);
|
|
245
|
+
}
|
|
178
246
|
async function showVersion() {
|
|
179
247
|
let version = "1.0.0";
|
|
180
248
|
try {
|
package/commands/login.js
CHANGED
|
@@ -29,6 +29,55 @@ const execute = async (args) => {
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// Special handling for `boltic login` to support PAT-based login via flags:
|
|
33
|
+
// boltic login --pat XXXXX --account_id YYYYYY
|
|
34
|
+
if (subCommand === "login") {
|
|
35
|
+
const options = args.slice(1);
|
|
36
|
+
let patFromArg;
|
|
37
|
+
let accountIdFromArg;
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < options.length; i++) {
|
|
40
|
+
const arg = options[i];
|
|
41
|
+
|
|
42
|
+
if (arg === "--pat" && i + 1 < options.length) {
|
|
43
|
+
patFromArg = options[i + 1];
|
|
44
|
+
i++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
(arg === "--account_id" || arg === "--account-id") &&
|
|
50
|
+
i + 1 < options.length
|
|
51
|
+
) {
|
|
52
|
+
accountIdFromArg = options[i + 1];
|
|
53
|
+
i++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (arg.startsWith("--pat=")) {
|
|
58
|
+
patFromArg = arg.split("=")[1];
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
arg.startsWith("--account_id=") ||
|
|
64
|
+
arg.startsWith("--account-id=")
|
|
65
|
+
) {
|
|
66
|
+
accountIdFromArg = arg.split("=")[1];
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// If PAT flags are provided, use PAT-based login. Otherwise, fall back to browser-based login.
|
|
72
|
+
if (patFromArg || accountIdFromArg) {
|
|
73
|
+
await handlePatLogin(patFromArg, accountIdFromArg);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await handleLogin();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
32
81
|
await commands[subCommand].action(args.slice(1));
|
|
33
82
|
};
|
|
34
83
|
|
|
@@ -179,31 +228,51 @@ async function handleLogin() {
|
|
|
179
228
|
|
|
180
229
|
// Handle PAT-based login command
|
|
181
230
|
async function handlePatLogin(patFromArg, accountIdFromArg) {
|
|
182
|
-
let pat = patFromArg;
|
|
183
|
-
let accountId = accountIdFromArg;
|
|
231
|
+
let pat = patFromArg && patFromArg.trim();
|
|
232
|
+
let accountId = accountIdFromArg && accountIdFromArg.trim();
|
|
233
|
+
|
|
234
|
+
// If both values are provided via CLI flags, do not prompt at all.
|
|
235
|
+
if (pat && accountId) {
|
|
236
|
+
try {
|
|
237
|
+
await storeSecret("pat", pat);
|
|
238
|
+
await storeSecret("account_id", accountId);
|
|
239
|
+
console.log(
|
|
240
|
+
chalk.green(
|
|
241
|
+
"\n✅ PAT token and Account ID stored securely. They will be used for future organization-related requests.\n"
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error(
|
|
246
|
+
chalk.red(
|
|
247
|
+
`\n❌ Failed to store PAT credentials: ${error.message || error}\n`
|
|
248
|
+
)
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
184
253
|
|
|
185
254
|
if (!pat) {
|
|
186
255
|
console.log(chalk.cyan("\n🔐 Personal Access Token (PAT) login\n"));
|
|
187
|
-
pat = await askQuestion("Enter your PAT token: ");
|
|
256
|
+
pat = (await askQuestion("Enter your PAT token: ")).trim();
|
|
188
257
|
}
|
|
189
258
|
|
|
190
|
-
if (!pat
|
|
259
|
+
if (!pat) {
|
|
191
260
|
console.log(chalk.red("\n❌ PAT token cannot be empty.\n"));
|
|
192
261
|
return;
|
|
193
262
|
}
|
|
194
263
|
|
|
195
264
|
if (!accountId) {
|
|
196
|
-
accountId = await askQuestion("Enter your Account ID: ");
|
|
265
|
+
accountId = (await askQuestion("Enter your Account ID: ")).trim();
|
|
197
266
|
}
|
|
198
267
|
|
|
199
|
-
if (!accountId
|
|
268
|
+
if (!accountId) {
|
|
200
269
|
console.log(chalk.red("\n❌ Account ID cannot be empty.\n"));
|
|
201
270
|
return;
|
|
202
271
|
}
|
|
203
272
|
|
|
204
273
|
try {
|
|
205
|
-
await storeSecret("pat", pat
|
|
206
|
-
await storeSecret("account_id", accountId
|
|
274
|
+
await storeSecret("pat", pat);
|
|
275
|
+
await storeSecret("account_id", accountId);
|
|
207
276
|
console.log(
|
|
208
277
|
chalk.green(
|
|
209
278
|
"\n✅ PAT token and Account ID stored securely. They will be used for future organization-related requests.\n"
|