gitshift 1.0.8 → 1.0.9
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/package.json +2 -1
- package/src/commands/scan.js +89 -0
- package/src/server.js +8 -0
- package/src/services/scan.js +36 -0
- package/src/services/ssh.js +19 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitshift",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "GitHub Account Switcher CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"commander": "^15.0.0",
|
|
29
29
|
"conf": "^15.1.0",
|
|
30
30
|
"execa": "^9.6.1",
|
|
31
|
+
"fast-glob": "^3.3.3",
|
|
31
32
|
"fs-extra": "^11.3.5",
|
|
32
33
|
"ora": "^9.4.0"
|
|
33
34
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
input,
|
|
5
|
+
select,
|
|
6
|
+
} from "@inquirer/prompts";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
findSSHKeys,
|
|
10
|
+
} from "../services/scan.js";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
getProfiles,
|
|
14
|
+
saveProfile,
|
|
15
|
+
} from "../services/profile.js";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
error,
|
|
19
|
+
info,
|
|
20
|
+
success,
|
|
21
|
+
} from "../utils/logger.js";
|
|
22
|
+
|
|
23
|
+
export async function scanCommand() {
|
|
24
|
+
try {
|
|
25
|
+
const keys = await findSSHKeys();
|
|
26
|
+
|
|
27
|
+
if (!keys.length) {
|
|
28
|
+
info("No SSH keys found");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const existing = getProfiles();
|
|
33
|
+
|
|
34
|
+
const importedPaths = existing.map((profile) => profile.sshKey);
|
|
35
|
+
|
|
36
|
+
const available = keys.filter((key) => !importedPaths.includes(key));
|
|
37
|
+
|
|
38
|
+
if (!available.length) {
|
|
39
|
+
info("All keys already imported");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const selected = await select({
|
|
44
|
+
message: "Select SSH Key",
|
|
45
|
+
choices: available.map((key) => ({
|
|
46
|
+
name: path.basename(key),
|
|
47
|
+
value: key,
|
|
48
|
+
})),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const profileName = await input({
|
|
52
|
+
message: "Profile Name",
|
|
53
|
+
default: path.basename(selected),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const username = await input({
|
|
57
|
+
message: "GitHub Username",
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const email = await input({
|
|
61
|
+
message: "Email",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
saveProfile({
|
|
66
|
+
name: profileName,
|
|
67
|
+
username,
|
|
68
|
+
email,
|
|
69
|
+
sshKey: selected,
|
|
70
|
+
source:
|
|
71
|
+
"imported",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
success(`Existing SSH Key Imported "${profileName}"`);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
error(err.message);
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (err && err.name === "ExitPromptError") {
|
|
80
|
+
// User canceled the prompt (Ctrl+C / SIGINT). Exit gracefully.
|
|
81
|
+
error("Existing SSH Key Import canceled by user.");
|
|
82
|
+
process.exitCode = 0;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
error(String(err));
|
|
87
|
+
process.exitCode = 1;
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import { currentCommand } from "./commands/current.js";
|
|
|
9
9
|
import { doctorCommand } from "./commands/doctor.js";
|
|
10
10
|
import { listCommand } from "./commands/list.js";
|
|
11
11
|
import { removeCommand } from "./commands/remove.js";
|
|
12
|
+
import { scanCommand } from "./commands/scan.js";
|
|
12
13
|
import { useCommand } from "./commands/use.js";
|
|
13
14
|
|
|
14
15
|
const require = createRequire(import.meta.url);
|
|
@@ -116,6 +117,13 @@ async function main() {
|
|
|
116
117
|
)
|
|
117
118
|
.action(removeCommand);
|
|
118
119
|
|
|
120
|
+
program
|
|
121
|
+
.command("scan")
|
|
122
|
+
.description(
|
|
123
|
+
"Import existing SSH keys"
|
|
124
|
+
)
|
|
125
|
+
.action(scanCommand);
|
|
126
|
+
|
|
119
127
|
program
|
|
120
128
|
.command("doctor")
|
|
121
129
|
.description(
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fg from "fast-glob";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
export async function findSSHKeys() {
|
|
7
|
+
const sshDir = path.join(os.homedir(), ".ssh");
|
|
8
|
+
|
|
9
|
+
const exists =
|
|
10
|
+
await fs.pathExists(sshDir);
|
|
11
|
+
|
|
12
|
+
if (!exists) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const files = await fg("*", {
|
|
17
|
+
cwd: sshDir,
|
|
18
|
+
absolute: true,
|
|
19
|
+
onlyFiles: true,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return files.filter((file) => {
|
|
23
|
+
const name = path.basename(file);
|
|
24
|
+
|
|
25
|
+
if (
|
|
26
|
+
name.endsWith(".pub") ||
|
|
27
|
+
name === "config" ||
|
|
28
|
+
name === "known_hosts" ||
|
|
29
|
+
name === "authorized_keys"
|
|
30
|
+
) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
});
|
|
36
|
+
}
|
package/src/services/ssh.js
CHANGED
|
@@ -51,4 +51,23 @@ export async function generateSSHKey(
|
|
|
51
51
|
]);
|
|
52
52
|
|
|
53
53
|
return keyPath;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function getPublicKey(
|
|
57
|
+
privateKeyPath
|
|
58
|
+
) {
|
|
59
|
+
const publicKey =
|
|
60
|
+
`${privateKeyPath}.pub`;
|
|
61
|
+
|
|
62
|
+
const exists =
|
|
63
|
+
await fs.pathExists(publicKey);
|
|
64
|
+
|
|
65
|
+
if (!exists) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return fs.readFile(
|
|
70
|
+
publicKey,
|
|
71
|
+
"utf8"
|
|
72
|
+
);
|
|
54
73
|
}
|