@abhiseck/zssh 0.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Abhiseck Bhattacharya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # sshc - SSH Chain
2
+
3
+ **sshc** is a modern, cross-platform CLI tool to manage and connect to your SSH servers with encrypted local storage and cloud sync capabilities.
4
+
5
+ ## Features
6
+
7
+ - **Secure**: All configuration is encrypted using AES-256-GCM with a master password.
8
+ - **Cross-Platform**: Works on macOS, Windows, and Linux.
9
+ - **Cloud Sync**: Sync your connections across devices using GitHub Gists (Encrypted).
10
+ - **Shortcuts**: Connect to servers using short aliases or IDs.
11
+ - **Auto-Login**: Supports password auto-fill (requires `sshpass`) and private keys.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g sshc
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Add a Connection
22
+
23
+ ```bash
24
+ sshc add
25
+ ```
26
+
27
+ Follow the interactive prompts to save your server details.
28
+
29
+ ### List Connections
30
+
31
+ ```bash
32
+ sshc list
33
+ ```
34
+
35
+ Displays a table of all saved connections.
36
+
37
+ ### Connect
38
+
39
+ ```bash
40
+ sshc connect <alias_or_id>
41
+ # Example:
42
+ sshc connect my-server
43
+ ```
44
+
45
+ ### Remove a Connection
46
+
47
+ ```bash
48
+ sshc remove <alias_or_id>
49
+ ```
50
+
51
+ ### Cloud Sync
52
+
53
+ To enable cloud sync, you need a GitHub Personal Access Token (PAT) with `gist` scope.
54
+
55
+ **Save to Cloud:**
56
+
57
+ ```bash
58
+ sshc save
59
+ ```
60
+
61
+ **Sync from Cloud:**
62
+
63
+ ```bash
64
+ sshc sync
65
+ ```
66
+
67
+ ## Security
68
+
69
+ Your configuration is stored in `~/.sshc.json`. The entire content is encrypted. You will be prompted for your master password when running commands.
70
+
71
+ ## Requirements
72
+
73
+ - Node.js >= 14
74
+ - `sshpass` (Optional, for password auto-fill)
75
+ - macOS: `brew install sshpass`
76
+ - Ubuntu: `apt-get install sshpass`
77
+
78
+ ## License
79
+
80
+ ISC
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.addCommand = addCommand;
40
+ const chalk = __importStar(require("chalk"));
41
+ const inquirer_1 = __importDefault(require("inquirer"));
42
+ const uuid_1 = require("uuid");
43
+ async function addCommand(configManager) {
44
+ console.log(chalk.blue("Adding new SSH connection..."));
45
+ const answers = await inquirer_1.default.prompt([
46
+ {
47
+ type: "input",
48
+ name: "host",
49
+ message: "Host (IP or Domain):",
50
+ validate: (input) => (input ? true : "Host is required"),
51
+ },
52
+ {
53
+ type: "input",
54
+ name: "port",
55
+ message: "Port:",
56
+ default: "22",
57
+ validate: (input) => !isNaN(parseInt(input)) ? true : "Port must be a number",
58
+ },
59
+ {
60
+ type: "input",
61
+ name: "username",
62
+ message: "Username:",
63
+ validate: (input) => (input ? true : "Username is required"),
64
+ },
65
+ {
66
+ type: "list",
67
+ name: "authType",
68
+ message: "Authentication Method:",
69
+ choices: ["Password", "Private Key", "Agent (No Password/Key stored)"],
70
+ },
71
+ {
72
+ type: "password",
73
+ name: "password",
74
+ message: "Password:",
75
+ when: (answers) => answers.authType === "Password",
76
+ mask: "*",
77
+ },
78
+ {
79
+ type: "input",
80
+ name: "privateKeyPath",
81
+ message: "Private Key Path:",
82
+ when: (answers) => answers.authType === "Private Key",
83
+ default: "~/.ssh/id_rsa",
84
+ },
85
+ {
86
+ type: "input",
87
+ name: "alias",
88
+ message: "Alias (short name):",
89
+ },
90
+ {
91
+ type: "input",
92
+ name: "description",
93
+ message: "Description (optional):",
94
+ },
95
+ ]);
96
+ const connection = {
97
+ id: (0, uuid_1.v4)().split("-")[0], // Short ID
98
+ alias: answers.alias,
99
+ host: answers.host,
100
+ port: parseInt(answers.port),
101
+ username: answers.username,
102
+ password: answers.password,
103
+ privateKeyPath: answers.privateKeyPath,
104
+ description: answers.description,
105
+ createdAt: new Date().toISOString(),
106
+ };
107
+ configManager.addConnection(connection);
108
+ console.log(chalk.green(`\nConnection added successfully!`));
109
+ console.log(`ID: ${chalk.cyan(connection.id)}`);
110
+ if (connection.alias)
111
+ console.log(`Alias: ${chalk.cyan(connection.alias)}`);
112
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.connectCommand = connectCommand;
37
+ const chalk = __importStar(require("chalk"));
38
+ const child_process_1 = require("child_process");
39
+ async function isSshpassInstalled() {
40
+ return new Promise((resolve) => {
41
+ const check = (0, child_process_1.spawn)("command", ["-v", "sshpass"]);
42
+ check.on("close", (code) => {
43
+ resolve(code === 0);
44
+ });
45
+ });
46
+ }
47
+ async function connectCommand(configManager, idOrAlias) {
48
+ const conn = configManager.getConnection(idOrAlias);
49
+ if (!conn) {
50
+ console.log(chalk.red(`Connection not found: ${idOrAlias}`));
51
+ return;
52
+ }
53
+ console.log(chalk.blue(`Connecting to ${conn.alias || conn.id} (${conn.username}@${conn.host})...`));
54
+ const args = [];
55
+ // Port
56
+ if (conn.port) {
57
+ args.push("-p", conn.port.toString());
58
+ }
59
+ // Identity file
60
+ if (conn.privateKeyPath) {
61
+ args.push("-i", conn.privateKeyPath);
62
+ }
63
+ // Destination
64
+ args.push(`${conn.username}@${conn.host}`);
65
+ let command = "ssh";
66
+ let finalArgs = args;
67
+ const env = { ...process.env };
68
+ // Handle Password
69
+ if (conn.password) {
70
+ const hasSshpass = await isSshpassInstalled();
71
+ if (hasSshpass) {
72
+ command = "sshpass";
73
+ // options for sshpass
74
+ // -p password
75
+ // We can also use SSHPASS env var to avoid showing in process list (slightly safer)
76
+ env["SSHPASS"] = conn.password;
77
+ finalArgs = ["-e", "ssh", ...args]; // -e means take password from env
78
+ }
79
+ else {
80
+ console.log(chalk.yellow('Warning: "sshpass" is not installed.'));
81
+ console.log(chalk.yellow("Cannot auto-fill password. You will be prompted by SSH."));
82
+ console.log(chalk.dim('Install sshpass (e.g. "brew install sshpass" on Mac) to enable auto-login.'));
83
+ }
84
+ }
85
+ const child = (0, child_process_1.spawn)(command, finalArgs, {
86
+ stdio: "inherit",
87
+ env: env,
88
+ });
89
+ child.on("close", (code) => {
90
+ if (code !== 0) {
91
+ console.log(chalk.red(`\nSSH session ended with code ${code}`));
92
+ }
93
+ else {
94
+ console.log(chalk.green("\nDisconnected."));
95
+ }
96
+ });
97
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.listCommand = listCommand;
40
+ const chalk = __importStar(require("chalk"));
41
+ const cli_table3_1 = __importDefault(require("cli-table3"));
42
+ async function listCommand(configManager) {
43
+ const connections = configManager.getConnections();
44
+ if (connections.length === 0) {
45
+ console.log(chalk.yellow('No connections found. Use "sshc add" to add one.'));
46
+ return;
47
+ }
48
+ const table = new cli_table3_1.default({
49
+ head: [
50
+ chalk.cyan("ID"),
51
+ chalk.cyan("Alias"),
52
+ chalk.cyan("Host"),
53
+ chalk.cyan("User"),
54
+ chalk.cyan("Port"),
55
+ ],
56
+ style: { head: [], border: [] },
57
+ });
58
+ connections.forEach((conn) => {
59
+ table.push([
60
+ conn.id,
61
+ conn.alias || "",
62
+ conn.host,
63
+ conn.username,
64
+ conn.port,
65
+ ]);
66
+ });
67
+ console.log(table.toString());
68
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.removeCommand = removeCommand;
40
+ const chalk = __importStar(require("chalk"));
41
+ const inquirer_1 = __importDefault(require("inquirer"));
42
+ async function removeCommand(configManager, idOrAlias) {
43
+ const conn = configManager.getConnection(idOrAlias);
44
+ if (!conn) {
45
+ console.log(chalk.red(`Connection not found: ${idOrAlias}`));
46
+ return;
47
+ }
48
+ const { confirm } = await inquirer_1.default.prompt([
49
+ {
50
+ type: "confirm",
51
+ name: "confirm",
52
+ message: `Are you sure you want to delete ${conn.alias || conn.id} (${conn.username}@${conn.host})?`,
53
+ default: false,
54
+ },
55
+ ]);
56
+ if (confirm) {
57
+ configManager.removeConnection(idOrAlias);
58
+ console.log(chalk.green("Connection removed."));
59
+ }
60
+ }
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.saveCommand = saveCommand;
40
+ exports.syncCommand = syncCommand;
41
+ const axios_1 = __importDefault(require("axios"));
42
+ const chalk = __importStar(require("chalk"));
43
+ const inquirer_1 = __importDefault(require("inquirer"));
44
+ const GITHUB_API = "https://api.github.com";
45
+ async function getGithubToken(configManager) {
46
+ const config = configManager.getConfig();
47
+ if (config.githubToken) {
48
+ return config.githubToken;
49
+ }
50
+ const { token } = await inquirer_1.default.prompt([
51
+ {
52
+ type: "password", // or input? token is long.
53
+ name: "token",
54
+ message: "Enter GitHub Personal Access Token (with gist scope):",
55
+ mask: "*",
56
+ },
57
+ ]);
58
+ configManager.setGithubToken(token);
59
+ return token;
60
+ }
61
+ async function saveCommand(configManager) {
62
+ const token = await getGithubToken(configManager);
63
+ const config = configManager.getConfig();
64
+ const encryptedContent = configManager.getEncryptedContent(); // We need a way to get raw encrypted string
65
+ if (!encryptedContent) {
66
+ console.log(chalk.red("Error: Could not retrieve encrypted config."));
67
+ return;
68
+ }
69
+ const files = {
70
+ "sshc_config.lock": {
71
+ content: encryptedContent,
72
+ },
73
+ };
74
+ try {
75
+ if (config.gistId) {
76
+ // Update existing Gist
77
+ console.log(chalk.blue("Updating existing Gist..."));
78
+ await axios_1.default.patch(`${GITHUB_API}/gists/${config.gistId}`, { files }, {
79
+ headers: { Authorization: `token ${token}` },
80
+ });
81
+ console.log(chalk.green("Config saved to Gist successfully."));
82
+ }
83
+ else {
84
+ // Create new Gist
85
+ console.log(chalk.blue("Creating new Gist..."));
86
+ const response = await axios_1.default.post(`${GITHUB_API}/gists`, {
87
+ description: "SSHC Encrypted Config",
88
+ public: false,
89
+ files,
90
+ }, {
91
+ headers: { Authorization: `token ${token}` },
92
+ });
93
+ const gistId = response.data.id;
94
+ configManager.setGistId(gistId);
95
+ console.log(chalk.green(`Gist created with ID: ${gistId}`));
96
+ console.log(chalk.green("Config saved to Gist successfully."));
97
+ }
98
+ }
99
+ catch (error) {
100
+ console.error(chalk.red("Failed to save to Gist:"), error.response?.data?.message || error.message);
101
+ }
102
+ }
103
+ async function syncCommand(configManager) {
104
+ const token = await getGithubToken(configManager);
105
+ let { gistId } = configManager.getConfig();
106
+ if (!gistId) {
107
+ const answer = await inquirer_1.default.prompt([
108
+ {
109
+ type: "input",
110
+ name: "gistId",
111
+ message: "Enter Gist ID to sync with:",
112
+ },
113
+ ]);
114
+ gistId = answer.gistId;
115
+ configManager.setGistId(gistId);
116
+ }
117
+ try {
118
+ console.log(chalk.blue("Fetching Gist..."));
119
+ const response = await axios_1.default.get(`${GITHUB_API}/gists/${gistId}`, {
120
+ headers: { Authorization: `token ${token}` },
121
+ });
122
+ const file = response.data.files["sshc_config.lock"];
123
+ if (!file) {
124
+ console.log(chalk.red("Invalid Gist: sshc_config.lock not found."));
125
+ return;
126
+ }
127
+ const encryptedContent = file.content;
128
+ // Merge strategy:
129
+ // 1. Decrypt remote content
130
+ // 2. Merge connections (Remote adds to Local)
131
+ // 3. Save merged to Local
132
+ // 4. (Optional) Push back to Remote? No, `sync` in this context usually means "pull and apply".
133
+ // Use `save` to push.
134
+ const merged = configManager.mergeEncrypted(encryptedContent);
135
+ if (merged) {
136
+ console.log(chalk.green("Sync completed. Remote changes merged into local config."));
137
+ }
138
+ else {
139
+ console.log(chalk.yellow("Sync completed but no changes were made or merge failed."));
140
+ }
141
+ }
142
+ catch (error) {
143
+ console.error(chalk.red("Failed to sync with Gist:"), error.response?.data?.message || error.message);
144
+ }
145
+ }