switchly 1.0.0
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 +116 -0
- package/dist/commands/add.d.ts +11 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +211 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/keys.d.ts +2 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +40 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +38 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +85 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +92 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/switch.d.ts +2 -0
- package/dist/commands/switch.d.ts.map +1 -0
- package/dist/commands/switch.js +108 -0
- package/dist/commands/switch.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/services/gh.d.ts +15 -0
- package/dist/services/gh.d.ts.map +1 -0
- package/dist/services/gh.js +89 -0
- package/dist/services/gh.js.map +1 -0
- package/dist/services/git.d.ts +23 -0
- package/dist/services/git.d.ts.map +1 -0
- package/dist/services/git.js +130 -0
- package/dist/services/git.js.map +1 -0
- package/dist/services/ssh.d.ts +16 -0
- package/dist/services/ssh.d.ts.map +1 -0
- package/dist/services/ssh.js +180 -0
- package/dist/services/ssh.js.map +1 -0
- package/dist/services/store.d.ts +12 -0
- package/dist/services/store.d.ts.map +1 -0
- package/dist/services/store.js +58 -0
- package/dist/services/store.js.map +1 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +18 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +23 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Switchly
|
|
2
|
+
|
|
3
|
+
A CLI tool to easily switch between multiple GitHub accounts. Manage SSH keys, Git configuration, and GitHub CLI authentication all in one place.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g switchly
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Profile Management**: Create and manage multiple GitHub profiles
|
|
14
|
+
- **SSH Key Generation**: Automatically generate and configure SSH keys per profile
|
|
15
|
+
- **Git Config Switching**: Seamlessly switch `user.name` and `user.email`
|
|
16
|
+
- **GitHub CLI Integration**: Switch `gh` CLI authentication between accounts
|
|
17
|
+
- **Commit Signing**: Configure different signing keys per profile (GPG/SSH)
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Add a new profile
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
switchly add
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This will interactively prompt you for:
|
|
28
|
+
- Profile name (e.g., "personal", "work")
|
|
29
|
+
- Git username and email
|
|
30
|
+
- SSH key generation (optional)
|
|
31
|
+
- GitHub CLI token (optional)
|
|
32
|
+
- Commit signing key (optional)
|
|
33
|
+
|
|
34
|
+
### List profiles
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
switchly list
|
|
38
|
+
# or
|
|
39
|
+
switchly ls
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Switch to a profile
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
switchly use personal
|
|
46
|
+
# or
|
|
47
|
+
switchly use # Interactive selection
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Check current status
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
switchly status
|
|
54
|
+
switchly status -v # Verbose, includes SSH test
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### List SSH keys
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
switchly keys
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Remove a profile
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
switchly remove personal
|
|
67
|
+
switchly rm personal -f # Skip confirmation
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## How It Works
|
|
71
|
+
|
|
72
|
+
### SSH Keys
|
|
73
|
+
|
|
74
|
+
When you add a profile, Switchly can generate a new SSH key and configure `~/.ssh/config` with a host alias:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Host github.com-personal
|
|
78
|
+
HostName github.com
|
|
79
|
+
User git
|
|
80
|
+
IdentityFile ~/.ssh/switchly_personal
|
|
81
|
+
IdentitiesOnly yes
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
When cloning repos with this profile, use:
|
|
85
|
+
```bash
|
|
86
|
+
git clone git@github.com-personal:username/repo.git
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Git Config
|
|
90
|
+
|
|
91
|
+
When switching profiles, Switchly updates your global Git configuration:
|
|
92
|
+
```bash
|
|
93
|
+
git config --global user.name "Your Name"
|
|
94
|
+
git config --global user.email "your@email.com"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Commit Signing
|
|
98
|
+
|
|
99
|
+
Switchly can configure different signing keys per profile:
|
|
100
|
+
- SSH signing (recommended for GitHub)
|
|
101
|
+
- GPG signing
|
|
102
|
+
|
|
103
|
+
### GitHub CLI
|
|
104
|
+
|
|
105
|
+
If you provide a Personal Access Token, Switchly will switch `gh` CLI authentication when you switch profiles.
|
|
106
|
+
|
|
107
|
+
## Requirements
|
|
108
|
+
|
|
109
|
+
- Node.js >= 18
|
|
110
|
+
- Git
|
|
111
|
+
- SSH (for key generation)
|
|
112
|
+
- GitHub CLI (optional, for `gh` auth switching)
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface AddOptions {
|
|
2
|
+
name?: string;
|
|
3
|
+
email?: string;
|
|
4
|
+
gitName?: string;
|
|
5
|
+
skipSsh?: boolean;
|
|
6
|
+
skipGh?: boolean;
|
|
7
|
+
skipSigning?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function addCommand(options: AddOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAUA,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA8MnE"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { log } from "../utils/logger.js";
|
|
5
|
+
import { addProfile, profileExists } from "../services/store.js";
|
|
6
|
+
import { generateSSHKey, addSSHHostConfig, sshKeyExists, getSSHKeyPath } from "../services/ssh.js";
|
|
7
|
+
import { validateToken } from "../services/gh.js";
|
|
8
|
+
import { listGPGKeys, listSSHKeys } from "../services/git.js";
|
|
9
|
+
export async function addCommand(options) {
|
|
10
|
+
log.title("Add New GitHub Profile");
|
|
11
|
+
// Interactive prompts for missing options
|
|
12
|
+
const answers = await inquirer.prompt([
|
|
13
|
+
{
|
|
14
|
+
type: "input",
|
|
15
|
+
name: "name",
|
|
16
|
+
message: "Profile name (e.g., personal, work):",
|
|
17
|
+
default: options.name,
|
|
18
|
+
validate: (input) => {
|
|
19
|
+
if (!input.trim())
|
|
20
|
+
return "Profile name is required";
|
|
21
|
+
if (!/^[a-z0-9-_]+$/i.test(input)) {
|
|
22
|
+
return "Profile name can only contain letters, numbers, hyphens, and underscores";
|
|
23
|
+
}
|
|
24
|
+
if (profileExists(input)) {
|
|
25
|
+
return `Profile "${input}" already exists`;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: "input",
|
|
32
|
+
name: "gitName",
|
|
33
|
+
message: "Git username (user.name):",
|
|
34
|
+
default: options.gitName,
|
|
35
|
+
validate: (input) => (input.trim() ? true : "Git name is required"),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: "input",
|
|
39
|
+
name: "gitEmail",
|
|
40
|
+
message: "Git email (user.email):",
|
|
41
|
+
default: options.email,
|
|
42
|
+
validate: (input) => {
|
|
43
|
+
if (!input.trim())
|
|
44
|
+
return "Email is required";
|
|
45
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input)) {
|
|
46
|
+
return "Please enter a valid email address";
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: "confirm",
|
|
53
|
+
name: "generateSsh",
|
|
54
|
+
message: "Generate new SSH key for this profile?",
|
|
55
|
+
default: !options.skipSsh,
|
|
56
|
+
when: !options.skipSsh,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: "confirm",
|
|
60
|
+
name: "addGhToken",
|
|
61
|
+
message: "Add GitHub CLI (gh) token for this profile?",
|
|
62
|
+
default: !options.skipGh,
|
|
63
|
+
when: !options.skipGh,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: "password",
|
|
67
|
+
name: "ghToken",
|
|
68
|
+
message: "Enter GitHub Personal Access Token:",
|
|
69
|
+
mask: "*",
|
|
70
|
+
when: (ans) => ans.addGhToken,
|
|
71
|
+
validate: async (input) => {
|
|
72
|
+
if (!input.trim())
|
|
73
|
+
return "Token is required";
|
|
74
|
+
const spinner = ora("Validating token...").start();
|
|
75
|
+
const result = await validateToken(input);
|
|
76
|
+
spinner.stop();
|
|
77
|
+
if (!result.valid) {
|
|
78
|
+
return "Invalid token. Please check and try again.";
|
|
79
|
+
}
|
|
80
|
+
console.log(chalk.dim(` Token valid for user: ${result.user}`));
|
|
81
|
+
return true;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
type: "confirm",
|
|
86
|
+
name: "setupSigning",
|
|
87
|
+
message: "Configure commit signing for this profile?",
|
|
88
|
+
default: false,
|
|
89
|
+
when: !options.skipSigning,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: "list",
|
|
93
|
+
name: "signingFormat",
|
|
94
|
+
message: "Signing format:",
|
|
95
|
+
choices: [
|
|
96
|
+
{ name: "SSH (recommended for GitHub)", value: "ssh" },
|
|
97
|
+
{ name: "GPG", value: "gpg" },
|
|
98
|
+
],
|
|
99
|
+
when: (ans) => ans.setupSigning,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
type: "list",
|
|
103
|
+
name: "signingKeyChoice",
|
|
104
|
+
message: "Select signing key:",
|
|
105
|
+
choices: async (ans) => {
|
|
106
|
+
const choices = [];
|
|
107
|
+
if (ans.signingFormat === "ssh") {
|
|
108
|
+
const sshKeys = await listSSHKeys();
|
|
109
|
+
sshKeys.forEach((key) => {
|
|
110
|
+
choices.push({ name: key.replace(/^.*\//, ""), value: key });
|
|
111
|
+
});
|
|
112
|
+
if (ans.generateSsh) {
|
|
113
|
+
choices.unshift({
|
|
114
|
+
name: "(Use the SSH key generated above)",
|
|
115
|
+
value: "__generated__"
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const gpgKeys = await listGPGKeys();
|
|
121
|
+
gpgKeys.forEach((key) => {
|
|
122
|
+
choices.push({ name: key, value: key });
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
choices.push({ name: "Enter manually", value: "__manual__" });
|
|
126
|
+
return choices;
|
|
127
|
+
},
|
|
128
|
+
when: (ans) => ans.setupSigning,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
type: "input",
|
|
132
|
+
name: "signingKeyManual",
|
|
133
|
+
message: "Enter signing key (GPG key ID or SSH key path):",
|
|
134
|
+
when: (ans) => ans.signingKeyChoice === "__manual__",
|
|
135
|
+
validate: (input) => (input.trim() ? true : "Signing key is required"),
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
const profileName = answers.name.toLowerCase();
|
|
139
|
+
let sshKeyPath = "";
|
|
140
|
+
let sshHost = "";
|
|
141
|
+
let publicKey = "";
|
|
142
|
+
// Generate SSH key if requested
|
|
143
|
+
if (answers.generateSsh) {
|
|
144
|
+
const spinner = ora("Generating SSH key...").start();
|
|
145
|
+
try {
|
|
146
|
+
// Check if key already exists
|
|
147
|
+
if (await sshKeyExists(profileName)) {
|
|
148
|
+
spinner.warn("SSH key already exists for this profile name");
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const result = await generateSSHKey(answers.gitEmail, profileName);
|
|
152
|
+
sshKeyPath = result.privateKey;
|
|
153
|
+
publicKey = result.publicKey;
|
|
154
|
+
spinner.succeed("SSH key generated");
|
|
155
|
+
}
|
|
156
|
+
// Add SSH config
|
|
157
|
+
const configSpinner = ora("Updating SSH config...").start();
|
|
158
|
+
sshHost = await addSSHHostConfig(profileName, sshKeyPath || `~/.ssh/switchly_${profileName}`);
|
|
159
|
+
configSpinner.succeed("SSH config updated");
|
|
160
|
+
// Show public key
|
|
161
|
+
if (publicKey) {
|
|
162
|
+
console.log("\n" + chalk.yellow("Add this public key to your GitHub account:"));
|
|
163
|
+
console.log(chalk.cyan("https://github.com/settings/ssh/new"));
|
|
164
|
+
console.log("\n" + chalk.dim("─".repeat(60)));
|
|
165
|
+
console.log(publicKey);
|
|
166
|
+
console.log(chalk.dim("─".repeat(60)) + "\n");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
spinner.fail("Failed to generate SSH key");
|
|
171
|
+
log.error(error.message);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Determine signing key
|
|
176
|
+
let signingKey;
|
|
177
|
+
if (answers.setupSigning) {
|
|
178
|
+
if (answers.signingKeyChoice === "__generated__") {
|
|
179
|
+
// Use the SSH key generated above
|
|
180
|
+
signingKey = sshKeyPath || getSSHKeyPath(profileName);
|
|
181
|
+
}
|
|
182
|
+
else if (answers.signingKeyChoice === "__manual__") {
|
|
183
|
+
signingKey = answers.signingKeyManual;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
signingKey = answers.signingKeyChoice;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Create profile
|
|
190
|
+
const profile = {
|
|
191
|
+
name: profileName,
|
|
192
|
+
gitName: answers.gitName,
|
|
193
|
+
gitEmail: answers.gitEmail,
|
|
194
|
+
sshKeyPath: sshKeyPath || "",
|
|
195
|
+
sshHost: sshHost || `github.com-${profileName}`,
|
|
196
|
+
ghToken: answers.ghToken,
|
|
197
|
+
signingKey,
|
|
198
|
+
signingFormat: answers.signingFormat,
|
|
199
|
+
signCommits: answers.setupSigning || false,
|
|
200
|
+
createdAt: new Date().toISOString(),
|
|
201
|
+
};
|
|
202
|
+
addProfile(profile);
|
|
203
|
+
log.success(`Profile "${profileName}" created successfully!`);
|
|
204
|
+
console.log("\n" + chalk.dim("To switch to this profile, run:"));
|
|
205
|
+
console.log(chalk.cyan(` switchly use ${profileName}`));
|
|
206
|
+
if (sshHost) {
|
|
207
|
+
console.log("\n" + chalk.dim("When cloning repos with this profile, use:"));
|
|
208
|
+
console.log(chalk.cyan(` git clone git@${sshHost}:username/repo.git`));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwCjD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { log } from "../utils/logger.js";
|
|
3
|
+
import { listSSHKeys } from "../services/git.js";
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
|
+
export async function keysCommand() {
|
|
6
|
+
log.title("SSH Keys");
|
|
7
|
+
const keys = await listSSHKeys();
|
|
8
|
+
if (keys.length === 0) {
|
|
9
|
+
log.info("No SSH keys found in ~/.ssh/");
|
|
10
|
+
console.log(chalk.dim("\nGenerate one with: ssh-keygen -t ed25519"));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
for (const keyPath of keys) {
|
|
14
|
+
const keyName = keyPath.split("/").pop() || keyPath;
|
|
15
|
+
const isGhswitch = keyName.startsWith("switchly_");
|
|
16
|
+
// Read the public key content
|
|
17
|
+
try {
|
|
18
|
+
const content = await readFile(keyPath, "utf-8");
|
|
19
|
+
const parts = content.trim().split(" ");
|
|
20
|
+
const keyType = parts[0] || "unknown";
|
|
21
|
+
const comment = parts[2] || "";
|
|
22
|
+
const indicator = isGhswitch ? chalk.green("● ") : chalk.dim("○ ");
|
|
23
|
+
const nameStr = isGhswitch ? chalk.green(keyName) : chalk.white(keyName);
|
|
24
|
+
console.log(`${indicator}${nameStr}`);
|
|
25
|
+
console.log(chalk.dim(` Type: ${keyType}`));
|
|
26
|
+
if (comment) {
|
|
27
|
+
console.log(chalk.dim(` Comment: ${comment}`));
|
|
28
|
+
}
|
|
29
|
+
console.log(chalk.dim(` Path: ${keyPath}`));
|
|
30
|
+
console.log();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
console.log(chalk.dim(`○ ${keyName}`));
|
|
34
|
+
console.log(chalk.dim(` Path: ${keyPath}`));
|
|
35
|
+
console.log();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log(chalk.dim(`${keys.length} key(s) found`));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAEtB,MAAM,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC;IAEjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC;QACpD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAEnD,8BAA8B;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;YACtC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAE/B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAEzE,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC,CAAC;YAClD,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,OAAO,EAAE,CAAC,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,eAAe,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA0CjD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { log } from "../utils/logger.js";
|
|
3
|
+
import { getProfiles, getActiveProfileName } from "../services/store.js";
|
|
4
|
+
export async function listCommand() {
|
|
5
|
+
const profiles = getProfiles();
|
|
6
|
+
const activeProfileName = getActiveProfileName();
|
|
7
|
+
if (profiles.length === 0) {
|
|
8
|
+
log.info("No profiles configured yet.");
|
|
9
|
+
console.log(chalk.dim("\nRun `switchly add` to create your first profile."));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
log.title("GitHub Profiles");
|
|
13
|
+
for (const profile of profiles) {
|
|
14
|
+
const isActive = profile.name === activeProfileName;
|
|
15
|
+
const indicator = isActive ? chalk.green("● ") : chalk.dim("○ ");
|
|
16
|
+
const nameStr = isActive
|
|
17
|
+
? chalk.bold.green(profile.name)
|
|
18
|
+
: chalk.white(profile.name);
|
|
19
|
+
console.log(`${indicator}${nameStr}`);
|
|
20
|
+
console.log(chalk.dim(` Name: ${profile.gitName}`));
|
|
21
|
+
console.log(chalk.dim(` Email: ${profile.gitEmail}`));
|
|
22
|
+
if (profile.sshHost) {
|
|
23
|
+
console.log(chalk.dim(` SSH: ${profile.sshHost}`));
|
|
24
|
+
}
|
|
25
|
+
if (profile.ghToken) {
|
|
26
|
+
console.log(chalk.dim(` GH: ✓ Token configured`));
|
|
27
|
+
}
|
|
28
|
+
if (profile.signCommits && profile.signingKey) {
|
|
29
|
+
const keyName = profile.signingKey.split("/").pop();
|
|
30
|
+
console.log(chalk.dim(` Sign: ✓ ${profile.signingFormat?.toUpperCase()} (${keyName})`));
|
|
31
|
+
}
|
|
32
|
+
console.log();
|
|
33
|
+
}
|
|
34
|
+
if (!activeProfileName) {
|
|
35
|
+
console.log(chalk.yellow("No active profile. Run `switchly use <profile>` to activate one."));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC;IAEjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;QAC7E,OAAO;IACT,CAAC;IAED,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAE7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAC;QACpD,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,QAAQ;YACtB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE9B,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAEzD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,OAAO,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC;QAC9F,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kEAAkE,CAAC,CAAC,CAAC;IAChG,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAaA,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,aAAa,CACjC,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAuFf"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { unlink } from "fs/promises";
|
|
5
|
+
import { log } from "../utils/logger.js";
|
|
6
|
+
import { getProfiles, getProfile, removeProfile, getActiveProfileName, } from "../services/store.js";
|
|
7
|
+
import { removeSSHHostConfig, getSSHKeyPath } from "../services/ssh.js";
|
|
8
|
+
export async function removeCommand(profileName, options = {}) {
|
|
9
|
+
const profiles = getProfiles();
|
|
10
|
+
if (profiles.length === 0) {
|
|
11
|
+
log.info("No profiles to remove.");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
// If no profile specified, prompt for selection
|
|
15
|
+
if (!profileName) {
|
|
16
|
+
const choices = profiles.map((p) => ({
|
|
17
|
+
name: p.name,
|
|
18
|
+
value: p.name,
|
|
19
|
+
}));
|
|
20
|
+
const answer = await inquirer.prompt([
|
|
21
|
+
{
|
|
22
|
+
type: "list",
|
|
23
|
+
name: "profile",
|
|
24
|
+
message: "Select a profile to remove:",
|
|
25
|
+
choices,
|
|
26
|
+
},
|
|
27
|
+
]);
|
|
28
|
+
profileName = answer.profile;
|
|
29
|
+
}
|
|
30
|
+
const profile = getProfile(profileName);
|
|
31
|
+
if (!profile) {
|
|
32
|
+
log.error(`Profile "${profileName}" not found.`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Confirm removal unless --force
|
|
36
|
+
if (!options.force) {
|
|
37
|
+
const { confirm } = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: "confirm",
|
|
40
|
+
name: "confirm",
|
|
41
|
+
message: `Are you sure you want to remove profile "${profileName}"?`,
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
if (!confirm) {
|
|
46
|
+
log.info("Removal cancelled.");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const isActive = getActiveProfileName() === profileName;
|
|
51
|
+
// Remove SSH key and config if not --keep-ssh
|
|
52
|
+
if (!options.keepSsh && profile.sshKeyPath) {
|
|
53
|
+
const sshSpinner = ora("Removing SSH configuration...").start();
|
|
54
|
+
try {
|
|
55
|
+
// Remove SSH config entry
|
|
56
|
+
await removeSSHHostConfig(profileName);
|
|
57
|
+
// Remove SSH key files
|
|
58
|
+
const keyPath = profile.sshKeyPath || getSSHKeyPath(profileName);
|
|
59
|
+
try {
|
|
60
|
+
await unlink(keyPath);
|
|
61
|
+
await unlink(`${keyPath}.pub`);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Key files might not exist
|
|
65
|
+
}
|
|
66
|
+
sshSpinner.succeed("SSH configuration removed");
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
sshSpinner.warn("Could not fully remove SSH configuration");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Remove profile from store
|
|
73
|
+
const removed = removeProfile(profileName);
|
|
74
|
+
if (removed) {
|
|
75
|
+
log.success(`Profile "${profileName}" removed.`);
|
|
76
|
+
if (isActive) {
|
|
77
|
+
console.log(chalk.yellow("\nThis was your active profile."));
|
|
78
|
+
console.log(chalk.dim("Run `switchly use <profile>` to activate another profile."));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
log.error("Failed to remove profile.");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAQA,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+F9E"}
|