@webhikers/cli 1.0.0 → 1.0.2
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 +1 -1
- package/src/commands/config.js +67 -31
- package/src/commands/create.js +1 -1
- package/src/utils/ssh-key.js +34 -12
package/package.json
CHANGED
package/src/commands/config.js
CHANGED
|
@@ -5,19 +5,21 @@ import {
|
|
|
5
5
|
maskValue,
|
|
6
6
|
getConfigPath,
|
|
7
7
|
} from "../utils/config-store.js";
|
|
8
|
-
import {
|
|
8
|
+
import { findSSHKeys } from "../utils/ssh-key.js";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_COOLIFY_PORT = "8000";
|
|
9
11
|
|
|
10
12
|
export async function configCommand() {
|
|
11
13
|
const existing = loadConfig();
|
|
12
14
|
|
|
13
15
|
if (existing) {
|
|
14
16
|
console.log("\nExisting configuration found:");
|
|
15
|
-
console.log(`
|
|
17
|
+
console.log(` Server IP: ${existing.serverIp || "—"}`);
|
|
18
|
+
console.log(` Coolify Port: ${existing.coolifyPort || DEFAULT_COOLIFY_PORT}`);
|
|
16
19
|
console.log(` Coolify Token: ${maskValue(existing.coolifyToken)}`);
|
|
17
20
|
console.log(` Server UUID: ${maskValue(existing.serverUuid)}`);
|
|
18
|
-
console.log(` Server IP: ${existing.serverIp || "—"}`);
|
|
19
21
|
console.log(` SSH User: ${existing.sshUser || "—"}`);
|
|
20
|
-
console.log(` SSH Key: ${
|
|
22
|
+
console.log(` SSH Key: ${existing.sshKeyPath || "—"}`);
|
|
21
23
|
console.log("");
|
|
22
24
|
|
|
23
25
|
const { overwrite } = await inquirer.prompt([
|
|
@@ -35,62 +37,96 @@ export async function configCommand() {
|
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
// --- SSH Key selection ---
|
|
41
|
+
const sshKeys = findSSHKeys();
|
|
42
|
+
let sshKeyPath;
|
|
43
|
+
|
|
44
|
+
if (sshKeys.length > 0) {
|
|
45
|
+
const sshChoices = [
|
|
46
|
+
...sshKeys,
|
|
47
|
+
{ name: "Enter path manually", value: "__manual__" },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const { selectedKey } = await inquirer.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: "list",
|
|
53
|
+
name: "selectedKey",
|
|
54
|
+
message: "SSH Key auswählen:",
|
|
55
|
+
choices: sshChoices,
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
if (selectedKey === "__manual__") {
|
|
60
|
+
const { manualPath } = await inquirer.prompt([
|
|
61
|
+
{
|
|
62
|
+
type: "input",
|
|
63
|
+
name: "manualPath",
|
|
64
|
+
message: "SSH Key Pfad:",
|
|
65
|
+
validate: (v) => (v.length > 0 ? true : "Pfad ist erforderlich"),
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
sshKeyPath = manualPath;
|
|
69
|
+
} else {
|
|
70
|
+
sshKeyPath = selectedKey;
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
console.log("\nKein SSH Key gefunden. Erstelle einen:");
|
|
74
|
+
console.log(" ssh-keygen -t ed25519 -f ~/.ssh/hetzner");
|
|
75
|
+
console.log("Dann füge ~/.ssh/hetzner.pub bei Hetzner hinzu:");
|
|
76
|
+
console.log(" Hetzner Console → Security → SSH Keys → Add\n");
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// --- Server + Coolify config ---
|
|
38
81
|
const answers = await inquirer.prompt([
|
|
39
82
|
{
|
|
40
83
|
type: "input",
|
|
41
|
-
name: "
|
|
42
|
-
message: "
|
|
43
|
-
validate: (v) => (v.
|
|
84
|
+
name: "serverIp",
|
|
85
|
+
message: "Server IP-Adresse:\n (Hetzner Cloud Console → Server → IP-Adresse)\n ",
|
|
86
|
+
validate: (v) => (v.length > 0 ? true : "IP ist erforderlich"),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: "input",
|
|
90
|
+
name: "coolifyPort",
|
|
91
|
+
message: "Coolify Port:\n (Standard ist 8000, Enter drücken wenn korrekt)\n ",
|
|
92
|
+
default: DEFAULT_COOLIFY_PORT,
|
|
44
93
|
},
|
|
45
94
|
{
|
|
46
95
|
type: "password",
|
|
47
96
|
name: "coolifyToken",
|
|
48
|
-
message: "Coolify API Token
|
|
97
|
+
message: "Coolify API Token:\n (Coolify UI → Keys & Tokens → API Token erstellen)\n ",
|
|
49
98
|
mask: "*",
|
|
50
|
-
validate: (v) => (v.length > 0 ? true : "Token
|
|
99
|
+
validate: (v) => (v.length > 0 ? true : "Token ist erforderlich"),
|
|
51
100
|
},
|
|
52
101
|
{
|
|
53
102
|
type: "input",
|
|
54
103
|
name: "serverUuid",
|
|
55
|
-
message: "Server UUID
|
|
56
|
-
validate: (v) => (v.length > 0 ? true : "
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
type: "input",
|
|
60
|
-
name: "serverIp",
|
|
61
|
-
message: "Server IP address:",
|
|
62
|
-
validate: (v) => (v.length > 0 ? true : "Server IP is required"),
|
|
104
|
+
message: "Server UUID:\n (Coolify UI → Servers → auf Server klicken → UUID steht in der URL)\n ",
|
|
105
|
+
validate: (v) => (v.length > 0 ? true : "UUID ist erforderlich"),
|
|
63
106
|
},
|
|
64
107
|
{
|
|
65
108
|
type: "input",
|
|
66
109
|
name: "sshUser",
|
|
67
|
-
message: "SSH User
|
|
110
|
+
message: "SSH User:\n (Standard ist root, Enter drücken wenn korrekt)\n ",
|
|
68
111
|
default: "root",
|
|
69
112
|
},
|
|
70
|
-
{
|
|
71
|
-
type: "editor",
|
|
72
|
-
name: "sshKey",
|
|
73
|
-
message:
|
|
74
|
-
"SSH Private Key (your editor will open — paste the key, save, and close):",
|
|
75
|
-
validate: (v) =>
|
|
76
|
-
v.includes("PRIVATE KEY") ? true : "Does not look like a valid SSH key",
|
|
77
|
-
},
|
|
78
113
|
]);
|
|
79
114
|
|
|
80
|
-
const
|
|
115
|
+
const coolifyUrl = `http://${answers.serverIp}:${answers.coolifyPort}`;
|
|
81
116
|
|
|
82
117
|
const config = {
|
|
83
|
-
|
|
118
|
+
serverIp: answers.serverIp,
|
|
119
|
+
coolifyPort: answers.coolifyPort,
|
|
120
|
+
coolifyUrl,
|
|
84
121
|
coolifyToken: answers.coolifyToken,
|
|
85
122
|
serverUuid: answers.serverUuid,
|
|
86
|
-
serverIp: answers.serverIp,
|
|
87
123
|
sshUser: answers.sshUser,
|
|
88
|
-
sshKeyPath
|
|
124
|
+
sshKeyPath,
|
|
89
125
|
};
|
|
90
126
|
|
|
91
127
|
saveConfig(config);
|
|
92
128
|
|
|
93
129
|
console.log(`\nConfiguration saved to ${getConfigPath()}`);
|
|
94
|
-
console.log(`
|
|
130
|
+
console.log(`Coolify URL: ${coolifyUrl}`);
|
|
95
131
|
console.log("\nDone! You can now run: webhikers create <project-name>");
|
|
96
132
|
}
|
package/src/commands/create.js
CHANGED
|
@@ -81,7 +81,7 @@ export async function createCommand(name) {
|
|
|
81
81
|
console.log("=========================================");
|
|
82
82
|
console.log("");
|
|
83
83
|
console.log(` Repo: https://github.com/${GITHUB_ORG}/${name}`);
|
|
84
|
-
console.log(` Domain: https://${name}.webhikers.
|
|
84
|
+
console.log(` Domain: https://${name}.preview.webhikers.dev`);
|
|
85
85
|
console.log(` Dir: ${projectDir}`);
|
|
86
86
|
console.log("");
|
|
87
87
|
console.log(" MANUAL STEP:");
|
package/src/utils/ssh-key.js
CHANGED
|
@@ -1,17 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readdirSync, readFileSync, existsSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
-
import {
|
|
3
|
+
import { homedir } from "os";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const SSH_DIR = join(homedir(), ".ssh");
|
|
6
6
|
|
|
7
|
-
export function
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export function findSSHKeys() {
|
|
8
|
+
if (!existsSync(SSH_DIR)) return [];
|
|
9
|
+
|
|
10
|
+
const files = readdirSync(SSH_DIR);
|
|
11
|
+
const keys = [];
|
|
12
|
+
|
|
13
|
+
for (const file of files) {
|
|
14
|
+
if (file.endsWith(".pub")) continue;
|
|
15
|
+
if (file === "known_hosts" || file === "config" || file === "authorized_keys") continue;
|
|
16
|
+
if (file.startsWith(".")) continue;
|
|
17
|
+
|
|
18
|
+
const privatePath = join(SSH_DIR, file);
|
|
19
|
+
const pubPath = privatePath + ".pub";
|
|
20
|
+
|
|
21
|
+
if (!existsSync(pubPath)) continue;
|
|
22
|
+
|
|
23
|
+
let comment = "";
|
|
24
|
+
try {
|
|
25
|
+
const pubContent = readFileSync(pubPath, "utf-8").trim();
|
|
26
|
+
const parts = pubContent.split(" ");
|
|
27
|
+
if (parts.length >= 3) {
|
|
28
|
+
comment = parts.slice(2).join(" ");
|
|
29
|
+
}
|
|
30
|
+
} catch {}
|
|
31
|
+
|
|
32
|
+
keys.push({
|
|
33
|
+
name: `~/.ssh/${file}${comment ? ` (${comment})` : ""}`,
|
|
34
|
+
value: privatePath,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
10
37
|
|
|
11
|
-
|
|
12
|
-
const keyPath = getSSHKeyPath();
|
|
13
|
-
const normalized = keyContent.trim() + "\n";
|
|
14
|
-
writeFileSync(keyPath, normalized, "utf-8");
|
|
15
|
-
chmodSync(keyPath, 0o600);
|
|
16
|
-
return keyPath;
|
|
38
|
+
return keys;
|
|
17
39
|
}
|