gitshift 1.0.7 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitshift",
3
- "version": "1.0.7",
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
  }
@@ -26,9 +26,7 @@ export async function addCommand() {
26
26
  });
27
27
 
28
28
  if (getProfile(name)) {
29
- error(
30
- `Profile "${name}" already exists`
31
- );
29
+ error(`Profile "${name}" already exists`);
32
30
 
33
31
  process.exitCode = 1;
34
32
  return;
@@ -43,35 +41,23 @@ export async function addCommand() {
43
41
  });
44
42
 
45
43
  const createSSH = await confirm({
46
- message:
47
- "Generate SSH key automatically?",
44
+ message: "Generate SSH key automatically?",
48
45
  default: true,
49
46
  });
50
47
 
51
48
  let sshKey = null;
52
49
 
53
50
  if (createSSH) {
54
- const spinner = ora(
55
- "Generating SSH key..."
56
- ).start();
51
+ const spinner = ora("Generating SSH key...").start();
57
52
 
58
53
  try {
59
- sshKey = await generateSSHKey(
60
- name,
61
- email
62
- );
63
-
64
- spinner.succeed(
65
- "SSH key generated"
66
- );
54
+ sshKey = await generateSSHKey(name, email);
55
+
56
+ spinner.succeed("SSH key generated");
67
57
  } catch (err) {
68
- spinner.fail(
69
- "Unable to generate SSH key"
70
- );
58
+ spinner.fail("Unable to generate SSH key");
71
59
 
72
- error(
73
- "Could not create SSH key. Ensure OpenSSH is installed and available."
74
- );
60
+ error("Could not create SSH key. Ensure OpenSSH is installed and available.");
75
61
 
76
62
  if (
77
63
  err &&
@@ -100,6 +86,7 @@ export async function addCommand() {
100
86
  } catch (err) {
101
87
  if (err && err.name === "ExitPromptError") {
102
88
  // User canceled the prompt (Ctrl+C / SIGINT). Exit gracefully.
89
+ error("Profile creation canceled.");
103
90
  process.exitCode = 0;
104
91
  return;
105
92
  }
@@ -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
+ }
@@ -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
  }