quicklify 1.0.5 → 1.2.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.
Files changed (214) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +86 -25
  3. package/README.tr.md +86 -25
  4. package/SECURITY.md +79 -17
  5. package/bin/quicklify-mcp +5 -0
  6. package/dist/commands/add.d.ts +1 -0
  7. package/dist/commands/add.d.ts.map +1 -1
  8. package/dist/commands/add.js +41 -65
  9. package/dist/commands/add.js.map +1 -1
  10. package/dist/commands/backup.d.ts +2 -11
  11. package/dist/commands/backup.d.ts.map +1 -1
  12. package/dist/commands/backup.js +113 -57
  13. package/dist/commands/backup.js.map +1 -1
  14. package/dist/commands/destroy.d.ts.map +1 -1
  15. package/dist/commands/destroy.js +58 -37
  16. package/dist/commands/destroy.js.map +1 -1
  17. package/dist/commands/domain.d.ts +2 -9
  18. package/dist/commands/domain.d.ts.map +1 -1
  19. package/dist/commands/domain.js +47 -56
  20. package/dist/commands/domain.js.map +1 -1
  21. package/dist/commands/firewall.d.ts +3 -10
  22. package/dist/commands/firewall.d.ts.map +1 -1
  23. package/dist/commands/firewall.js +28 -51
  24. package/dist/commands/firewall.js.map +1 -1
  25. package/dist/commands/health.d.ts +2 -2
  26. package/dist/commands/health.d.ts.map +1 -1
  27. package/dist/commands/health.js +77 -19
  28. package/dist/commands/health.js.map +1 -1
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +142 -24
  31. package/dist/commands/init.js.map +1 -1
  32. package/dist/commands/interactive.d.ts +2 -0
  33. package/dist/commands/interactive.d.ts.map +1 -0
  34. package/dist/commands/interactive.js +357 -0
  35. package/dist/commands/interactive.js.map +1 -0
  36. package/dist/commands/list.d.ts.map +1 -1
  37. package/dist/commands/list.js +4 -2
  38. package/dist/commands/list.js.map +1 -1
  39. package/dist/commands/logs.d.ts +3 -2
  40. package/dist/commands/logs.d.ts.map +1 -1
  41. package/dist/commands/logs.js +15 -12
  42. package/dist/commands/logs.js.map +1 -1
  43. package/dist/commands/maintain.d.ts.map +1 -1
  44. package/dist/commands/maintain.js +28 -47
  45. package/dist/commands/maintain.js.map +1 -1
  46. package/dist/commands/monitor.d.ts +3 -9
  47. package/dist/commands/monitor.d.ts.map +1 -1
  48. package/dist/commands/monitor.js +3 -48
  49. package/dist/commands/monitor.js.map +1 -1
  50. package/dist/commands/remove.d.ts.map +1 -1
  51. package/dist/commands/remove.js +25 -0
  52. package/dist/commands/remove.js.map +1 -1
  53. package/dist/commands/restart.d.ts.map +1 -1
  54. package/dist/commands/restart.js +39 -39
  55. package/dist/commands/restart.js.map +1 -1
  56. package/dist/commands/restore.d.ts +2 -13
  57. package/dist/commands/restore.d.ts.map +1 -1
  58. package/dist/commands/restore.js +42 -54
  59. package/dist/commands/restore.js.map +1 -1
  60. package/dist/commands/secure.d.ts +2 -9
  61. package/dist/commands/secure.d.ts.map +1 -1
  62. package/dist/commands/secure.js +2 -97
  63. package/dist/commands/secure.js.map +1 -1
  64. package/dist/commands/snapshot.d.ts.map +1 -1
  65. package/dist/commands/snapshot.js +55 -67
  66. package/dist/commands/snapshot.js.map +1 -1
  67. package/dist/commands/ssh.d.ts.map +1 -1
  68. package/dist/commands/ssh.js +4 -1
  69. package/dist/commands/ssh.js.map +1 -1
  70. package/dist/commands/status.d.ts.map +1 -1
  71. package/dist/commands/status.js +53 -85
  72. package/dist/commands/status.js.map +1 -1
  73. package/dist/commands/update.d.ts.map +1 -1
  74. package/dist/commands/update.js +23 -16
  75. package/dist/commands/update.js.map +1 -1
  76. package/dist/constants.d.ts +14 -0
  77. package/dist/constants.d.ts.map +1 -0
  78. package/dist/constants.js +23 -0
  79. package/dist/constants.js.map +1 -0
  80. package/dist/core/backup.d.ts +59 -0
  81. package/dist/core/backup.d.ts.map +1 -0
  82. package/dist/core/backup.js +417 -0
  83. package/dist/core/backup.js.map +1 -0
  84. package/dist/core/domain.d.ts +30 -0
  85. package/dist/core/domain.d.ts.map +1 -0
  86. package/dist/core/domain.js +170 -0
  87. package/dist/core/domain.js.map +1 -0
  88. package/dist/core/firewall.d.ts +27 -0
  89. package/dist/core/firewall.d.ts.map +1 -0
  90. package/dist/core/firewall.js +158 -0
  91. package/dist/core/firewall.js.map +1 -0
  92. package/dist/core/logs.d.ts +28 -0
  93. package/dist/core/logs.d.ts.map +1 -0
  94. package/dist/core/logs.js +129 -0
  95. package/dist/core/logs.js.map +1 -0
  96. package/dist/core/maintain.d.ts +41 -0
  97. package/dist/core/maintain.d.ts.map +1 -0
  98. package/dist/core/maintain.js +179 -0
  99. package/dist/core/maintain.js.map +1 -0
  100. package/dist/core/manage.d.ts +43 -0
  101. package/dist/core/manage.d.ts.map +1 -0
  102. package/dist/core/manage.js +241 -0
  103. package/dist/core/manage.js.map +1 -0
  104. package/dist/core/provision.d.ts +19 -0
  105. package/dist/core/provision.d.ts.map +1 -0
  106. package/dist/core/provision.js +192 -0
  107. package/dist/core/provision.js.map +1 -0
  108. package/dist/core/secure.d.ts +29 -0
  109. package/dist/core/secure.d.ts.map +1 -0
  110. package/dist/core/secure.js +204 -0
  111. package/dist/core/secure.js.map +1 -0
  112. package/dist/core/snapshot.d.ts +22 -0
  113. package/dist/core/snapshot.d.ts.map +1 -0
  114. package/dist/core/snapshot.js +58 -0
  115. package/dist/core/snapshot.js.map +1 -0
  116. package/dist/core/status.d.ts +12 -0
  117. package/dist/core/status.d.ts.map +1 -0
  118. package/dist/core/status.js +44 -0
  119. package/dist/core/status.js.map +1 -0
  120. package/dist/core/tokens.d.ts +4 -0
  121. package/dist/core/tokens.d.ts.map +1 -0
  122. package/dist/core/tokens.js +23 -0
  123. package/dist/core/tokens.js.map +1 -0
  124. package/dist/index.js +17 -4
  125. package/dist/index.js.map +1 -1
  126. package/dist/mcp/index.d.ts +3 -0
  127. package/dist/mcp/index.d.ts.map +1 -0
  128. package/dist/mcp/index.js +16 -0
  129. package/dist/mcp/index.js.map +1 -0
  130. package/dist/mcp/server.d.ts +3 -0
  131. package/dist/mcp/server.d.ts.map +1 -0
  132. package/dist/mcp/server.js +111 -0
  133. package/dist/mcp/server.js.map +1 -0
  134. package/dist/mcp/tools/serverBackup.d.ts +24 -0
  135. package/dist/mcp/tools/serverBackup.d.ts.map +1 -0
  136. package/dist/mcp/tools/serverBackup.js +262 -0
  137. package/dist/mcp/tools/serverBackup.js.map +1 -0
  138. package/dist/mcp/tools/serverInfo.d.ts +36 -0
  139. package/dist/mcp/tools/serverInfo.d.ts.map +1 -0
  140. package/dist/mcp/tools/serverInfo.js +283 -0
  141. package/dist/mcp/tools/serverInfo.js.map +1 -0
  142. package/dist/mcp/tools/serverLogs.d.ts +25 -0
  143. package/dist/mcp/tools/serverLogs.d.ts.map +1 -0
  144. package/dist/mcp/tools/serverLogs.js +124 -0
  145. package/dist/mcp/tools/serverLogs.js.map +1 -0
  146. package/dist/mcp/tools/serverMaintain.d.ts +17 -0
  147. package/dist/mcp/tools/serverMaintain.d.ts.map +1 -0
  148. package/dist/mcp/tools/serverMaintain.js +156 -0
  149. package/dist/mcp/tools/serverMaintain.js.map +1 -0
  150. package/dist/mcp/tools/serverManage.d.ts +38 -0
  151. package/dist/mcp/tools/serverManage.d.ts.map +1 -0
  152. package/dist/mcp/tools/serverManage.js +190 -0
  153. package/dist/mcp/tools/serverManage.js.map +1 -0
  154. package/dist/mcp/tools/serverProvision.d.ts +36 -0
  155. package/dist/mcp/tools/serverProvision.d.ts.map +1 -0
  156. package/dist/mcp/tools/serverProvision.js +116 -0
  157. package/dist/mcp/tools/serverProvision.js.map +1 -0
  158. package/dist/mcp/tools/serverSecure.d.ts +35 -0
  159. package/dist/mcp/tools/serverSecure.d.ts.map +1 -0
  160. package/dist/mcp/tools/serverSecure.js +335 -0
  161. package/dist/mcp/tools/serverSecure.js.map +1 -0
  162. package/dist/mcp/utils.d.ts +42 -0
  163. package/dist/mcp/utils.d.ts.map +1 -0
  164. package/dist/mcp/utils.js +61 -0
  165. package/dist/mcp/utils.js.map +1 -0
  166. package/dist/providers/base.d.ts +2 -2
  167. package/dist/providers/base.d.ts.map +1 -1
  168. package/dist/providers/digitalocean.d.ts +2 -2
  169. package/dist/providers/digitalocean.d.ts.map +1 -1
  170. package/dist/providers/digitalocean.js +3 -3
  171. package/dist/providers/digitalocean.js.map +1 -1
  172. package/dist/providers/hetzner.d.ts +2 -2
  173. package/dist/providers/hetzner.d.ts.map +1 -1
  174. package/dist/providers/hetzner.js +7 -4
  175. package/dist/providers/hetzner.js.map +1 -1
  176. package/dist/providers/linode.d.ts +2 -2
  177. package/dist/providers/linode.d.ts.map +1 -1
  178. package/dist/providers/linode.js +2 -2
  179. package/dist/providers/linode.js.map +1 -1
  180. package/dist/providers/vultr.d.ts +2 -2
  181. package/dist/providers/vultr.d.ts.map +1 -1
  182. package/dist/providers/vultr.js +9 -3
  183. package/dist/providers/vultr.js.map +1 -1
  184. package/dist/types/index.d.ts +11 -1
  185. package/dist/types/index.d.ts.map +1 -1
  186. package/dist/utils/cloudInit.d.ts +1 -0
  187. package/dist/utils/cloudInit.d.ts.map +1 -1
  188. package/dist/utils/cloudInit.js +62 -0
  189. package/dist/utils/cloudInit.js.map +1 -1
  190. package/dist/utils/config.js +1 -1
  191. package/dist/utils/config.js.map +1 -1
  192. package/dist/utils/errorMapper.d.ts +1 -0
  193. package/dist/utils/errorMapper.d.ts.map +1 -1
  194. package/dist/utils/errorMapper.js +25 -1
  195. package/dist/utils/errorMapper.js.map +1 -1
  196. package/dist/utils/modeGuard.d.ts +5 -0
  197. package/dist/utils/modeGuard.d.ts.map +1 -0
  198. package/dist/utils/modeGuard.js +13 -0
  199. package/dist/utils/modeGuard.js.map +1 -0
  200. package/dist/utils/openBrowser.d.ts.map +1 -1
  201. package/dist/utils/openBrowser.js +9 -2
  202. package/dist/utils/openBrowser.js.map +1 -1
  203. package/dist/utils/prompts.d.ts +2 -2
  204. package/dist/utils/prompts.d.ts.map +1 -1
  205. package/dist/utils/prompts.js +3 -3
  206. package/dist/utils/prompts.js.map +1 -1
  207. package/dist/utils/ssh.d.ts +10 -0
  208. package/dist/utils/ssh.d.ts.map +1 -1
  209. package/dist/utils/ssh.js +181 -17
  210. package/dist/utils/ssh.js.map +1 -1
  211. package/dist/utils/sshKey.d.ts.map +1 -1
  212. package/dist/utils/sshKey.js +3 -0
  213. package/dist/utils/sshKey.js.map +1 -1
  214. package/package.json +7 -4
@@ -0,0 +1,357 @@
1
+ import inquirer from "inquirer";
2
+ import chalk from "chalk";
3
+ const BACK = "__back__";
4
+ const MENU = [
5
+ {
6
+ label: "Server Management",
7
+ actions: [
8
+ { name: "Deploy a new server", value: "init" },
9
+ { name: "Add an existing server", value: "add" },
10
+ { name: "List all servers", value: "list" },
11
+ { name: "Check server status", value: "status" },
12
+ { name: "SSH into a server", value: "ssh" },
13
+ { name: "Restart a server", value: "restart" },
14
+ { name: "Remove from config", value: "remove" },
15
+ { name: "Destroy a server", value: "destroy" },
16
+ ],
17
+ },
18
+ {
19
+ label: "Security",
20
+ actions: [
21
+ { name: "Harden SSH & fail2ban", value: "secure" },
22
+ { name: "Manage firewall (UFW)", value: "firewall" },
23
+ { name: "Manage domain & SSL", value: "domain" },
24
+ ],
25
+ },
26
+ {
27
+ label: "Monitoring & Logs",
28
+ actions: [
29
+ { name: "View server logs", value: "logs" },
30
+ { name: "Monitor resources (CPU/RAM/Disk)", value: "monitor" },
31
+ { name: "Health check", value: "health" },
32
+ ],
33
+ },
34
+ {
35
+ label: "Backup & Snapshots",
36
+ actions: [
37
+ { name: "Create a backup", value: "backup" },
38
+ { name: "Restore from backup", value: "restore" },
39
+ { name: "Manage snapshots", value: "snapshot" },
40
+ ],
41
+ },
42
+ {
43
+ label: "Maintenance",
44
+ actions: [
45
+ { name: "Update Coolify", value: "update" },
46
+ { name: "Full maintenance cycle", value: "maintain" },
47
+ { name: "Check local environment", value: "doctor" },
48
+ ],
49
+ },
50
+ {
51
+ label: "Configuration",
52
+ actions: [
53
+ { name: "Manage defaults", value: "config" },
54
+ { name: "Export server list", value: "export" },
55
+ { name: "Import server list", value: "import" },
56
+ ],
57
+ },
58
+ ];
59
+ function buildMainChoices() {
60
+ const choices = [];
61
+ for (const category of MENU) {
62
+ choices.push(new inquirer.Separator(chalk.yellow.bold(` ${category.label}`)));
63
+ for (const action of category.actions) {
64
+ choices.push({ name: ` ${action.name}`, value: action.value });
65
+ }
66
+ }
67
+ choices.push(new inquirer.Separator(" "));
68
+ choices.push({ name: chalk.dim(" Exit"), value: "exit" });
69
+ return choices;
70
+ }
71
+ function backChoice() {
72
+ return { name: chalk.dim("← Back"), value: BACK };
73
+ }
74
+ // ─── Sub-option prompts ─────────────────────────────────────────────────────
75
+ async function promptList(message, choices) {
76
+ const { answer } = await inquirer.prompt([
77
+ {
78
+ type: "list",
79
+ name: "answer",
80
+ message,
81
+ choices: [...choices, new inquirer.Separator(" "), backChoice()],
82
+ loop: false,
83
+ },
84
+ ]);
85
+ return answer === BACK ? null : answer;
86
+ }
87
+ async function promptInit() {
88
+ const mode = await promptList("Server mode:", [
89
+ { name: "Coolify (auto-install panel)", value: "coolify" },
90
+ { name: "Bare (generic VPS, no panel)", value: "bare" },
91
+ ]);
92
+ if (!mode)
93
+ return null;
94
+ const template = await promptList("Server template:", [
95
+ { name: "Starter (cheapest option)", value: "starter" },
96
+ { name: "Production (more resources)", value: "production" },
97
+ { name: "Dev (development)", value: "dev" },
98
+ ]);
99
+ if (!template)
100
+ return null;
101
+ const { fullSetup } = await inquirer.prompt([
102
+ {
103
+ type: "confirm",
104
+ name: "fullSetup",
105
+ message: "Run full setup after deploy? (firewall + SSH hardening)",
106
+ default: true,
107
+ },
108
+ ]);
109
+ const args = ["init", "--mode", mode, "--template", template];
110
+ if (fullSetup)
111
+ args.push("--full-setup");
112
+ return args;
113
+ }
114
+ async function promptLogs() {
115
+ const service = await promptList("Log source:", [
116
+ { name: "Coolify container logs", value: "coolify" },
117
+ { name: "Docker service logs", value: "docker" },
118
+ { name: "Full system journal", value: "system" },
119
+ ]);
120
+ if (!service)
121
+ return null;
122
+ const lines = await promptList("Number of log lines:", [
123
+ { name: "25 lines", value: "25" },
124
+ { name: "50 lines (default)", value: "50" },
125
+ { name: "100 lines", value: "100" },
126
+ { name: "200 lines", value: "200" },
127
+ ]);
128
+ if (!lines)
129
+ return null;
130
+ const { follow } = await inquirer.prompt([
131
+ { type: "confirm", name: "follow", message: "Follow log output in real-time?", default: false },
132
+ ]);
133
+ const args = ["logs", "--service", service, "--lines", lines];
134
+ if (follow)
135
+ args.push("--follow");
136
+ return args;
137
+ }
138
+ async function promptFirewall() {
139
+ const sub = await promptList("Firewall action:", [
140
+ { name: "Show current rules", value: "status" },
141
+ { name: "Initial firewall setup", value: "setup" },
142
+ { name: "Add a port rule", value: "add" },
143
+ { name: "Remove a port rule", value: "remove" },
144
+ ]);
145
+ if (!sub)
146
+ return null;
147
+ if (sub === "add" || sub === "remove") {
148
+ const answers = await inquirer.prompt([
149
+ {
150
+ type: "input",
151
+ name: "port",
152
+ message: "Port number:",
153
+ validate: (v) => {
154
+ const n = Number(v);
155
+ return n >= 1 && n <= 65535 ? true : "Enter a valid port (1-65535)";
156
+ },
157
+ },
158
+ ]);
159
+ const protocol = await promptList("Protocol:", [
160
+ { name: "TCP", value: "tcp" },
161
+ { name: "UDP", value: "udp" },
162
+ ]);
163
+ if (!protocol)
164
+ return null;
165
+ return ["firewall", sub, "--port", answers.port, "--protocol", protocol];
166
+ }
167
+ return ["firewall", sub];
168
+ }
169
+ async function promptSecure() {
170
+ const sub = await promptList("Security action:", [
171
+ { name: "Harden SSH + install fail2ban", value: "setup" },
172
+ { name: "Run security audit", value: "audit" },
173
+ { name: "Show security status", value: "status" },
174
+ ]);
175
+ if (!sub)
176
+ return null;
177
+ return ["secure", sub];
178
+ }
179
+ async function promptDomain() {
180
+ const sub = await promptList("Domain action:", [
181
+ { name: "Show current domain info", value: "info" },
182
+ { name: "Set a custom domain", value: "add" },
183
+ { name: "Check DNS for a domain", value: "check" },
184
+ { name: "Remove domain", value: "remove" },
185
+ ]);
186
+ if (!sub)
187
+ return null;
188
+ if (sub === "add" || sub === "check") {
189
+ const { domain } = await inquirer.prompt([
190
+ {
191
+ type: "input",
192
+ name: "domain",
193
+ message: "Domain name (e.g. panel.example.com):",
194
+ validate: (v) => (v.includes(".") ? true : "Enter a valid domain"),
195
+ },
196
+ ]);
197
+ const args = ["domain", sub, "--domain", domain];
198
+ if (sub === "add") {
199
+ const { ssl } = await inquirer.prompt([
200
+ { type: "confirm", name: "ssl", message: "Enable SSL (HTTPS)?", default: true },
201
+ ]);
202
+ if (!ssl)
203
+ args.push("--no-ssl");
204
+ }
205
+ return args;
206
+ }
207
+ return ["domain", sub];
208
+ }
209
+ async function promptSnapshot() {
210
+ const sub = await promptList("Snapshot action:", [
211
+ { name: "List snapshots", value: "list" },
212
+ { name: "Create a snapshot", value: "create" },
213
+ { name: "Delete a snapshot", value: "delete" },
214
+ ]);
215
+ if (!sub)
216
+ return null;
217
+ return ["snapshot", sub];
218
+ }
219
+ async function promptMonitor() {
220
+ const { containers } = await inquirer.prompt([
221
+ {
222
+ type: "confirm",
223
+ name: "containers",
224
+ message: "Include Docker container list?",
225
+ default: false,
226
+ },
227
+ ]);
228
+ const args = ["monitor"];
229
+ if (containers)
230
+ args.push("--containers");
231
+ return args;
232
+ }
233
+ async function promptMaintain() {
234
+ const { skipReboot } = await inquirer.prompt([
235
+ {
236
+ type: "confirm",
237
+ name: "skipReboot",
238
+ message: "Skip reboot step? (useful during business hours)",
239
+ default: false,
240
+ },
241
+ ]);
242
+ const args = ["maintain"];
243
+ if (skipReboot)
244
+ args.push("--skip-reboot");
245
+ return args;
246
+ }
247
+ async function promptStatus() {
248
+ const { all } = await inquirer.prompt([
249
+ { type: "confirm", name: "all", message: "Check all servers at once?", default: false },
250
+ ]);
251
+ const args = ["status"];
252
+ if (all)
253
+ args.push("--all");
254
+ return args;
255
+ }
256
+ async function promptUpdate() {
257
+ const { all } = await inquirer.prompt([
258
+ { type: "confirm", name: "all", message: "Update all servers at once?", default: false },
259
+ ]);
260
+ const args = ["update"];
261
+ if (all)
262
+ args.push("--all");
263
+ return args;
264
+ }
265
+ async function promptDoctor() {
266
+ const { checkTokens } = await inquirer.prompt([
267
+ { type: "confirm", name: "checkTokens", message: "Validate provider API tokens?", default: false },
268
+ ]);
269
+ const args = ["doctor"];
270
+ if (checkTokens)
271
+ args.push("--check-tokens");
272
+ return args;
273
+ }
274
+ async function promptSsh() {
275
+ const mode = await promptList("SSH mode:", [
276
+ { name: "Open interactive SSH session", value: "interactive" },
277
+ { name: "Run a single command", value: "command" },
278
+ ]);
279
+ if (!mode)
280
+ return null;
281
+ if (mode === "command") {
282
+ const { command } = await inquirer.prompt([
283
+ { type: "input", name: "command", message: "Command to execute:" },
284
+ ]);
285
+ return ["ssh", "--command", command];
286
+ }
287
+ return ["ssh"];
288
+ }
289
+ async function promptBackup() {
290
+ const { all } = await inquirer.prompt([
291
+ { type: "confirm", name: "all", message: "Backup all servers?", default: false },
292
+ ]);
293
+ const args = ["backup"];
294
+ if (all)
295
+ args.push("--all");
296
+ return args;
297
+ }
298
+ async function promptImport() {
299
+ const { path } = await inquirer.prompt([
300
+ {
301
+ type: "input",
302
+ name: "path",
303
+ message: "Path to JSON file to import:",
304
+ validate: (v) => (v.trim().length > 0 ? true : "File path is required"),
305
+ },
306
+ ]);
307
+ return ["import", path];
308
+ }
309
+ // ─── Command → args mapping ─────────────────────────────────────────────────
310
+ const SUB_PROMPTS = {
311
+ init: promptInit,
312
+ logs: promptLogs,
313
+ firewall: promptFirewall,
314
+ secure: promptSecure,
315
+ domain: promptDomain,
316
+ snapshot: promptSnapshot,
317
+ monitor: promptMonitor,
318
+ maintain: promptMaintain,
319
+ status: promptStatus,
320
+ update: promptUpdate,
321
+ doctor: promptDoctor,
322
+ ssh: promptSsh,
323
+ backup: promptBackup,
324
+ import: promptImport,
325
+ };
326
+ const DIRECT_COMMANDS = new Set([
327
+ "list", "add", "destroy", "restart", "remove", "restore", "export", "config",
328
+ ]);
329
+ export async function interactiveMenu() {
330
+ // Loop: back from sub-menus returns here
331
+ for (;;) {
332
+ const { action } = await inquirer.prompt([
333
+ {
334
+ type: "list",
335
+ name: "action",
336
+ message: "What would you like to do?",
337
+ choices: buildMainChoices(),
338
+ pageSize: 22,
339
+ loop: false,
340
+ },
341
+ ]);
342
+ if (action === "exit")
343
+ return null;
344
+ if (DIRECT_COMMANDS.has(action)) {
345
+ return [action];
346
+ }
347
+ const promptFn = SUB_PROMPTS[action];
348
+ if (promptFn) {
349
+ const result = await promptFn();
350
+ if (result === null)
351
+ continue; // back → show main menu again
352
+ return result;
353
+ }
354
+ return [action];
355
+ }
356
+ }
357
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/commands/interactive.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAyBjD"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA0BjD"}
@@ -1,5 +1,6 @@
1
1
  import { getServers } from "../utils/config.js";
2
2
  import { logger } from "../utils/logger.js";
3
+ import { getServerMode } from "../utils/modeGuard.js";
3
4
  export async function listCommand() {
4
5
  const servers = getServers();
5
6
  if (servers.length === 0) {
@@ -8,13 +9,14 @@ export async function listCommand() {
8
9
  }
9
10
  logger.title("Registered Servers");
10
11
  // Table header
11
- const header = `${"ID".padEnd(12)} ${"Name".padEnd(20)} ${"Provider".padEnd(14)} ${"IP".padEnd(16)} ${"Region".padEnd(10)} ${"Created".padEnd(12)}`;
12
+ const header = `${"ID".padEnd(12)} ${"Name".padEnd(20)} ${"Provider".padEnd(14)} ${"Mode".padEnd(10)} ${"IP".padEnd(16)} ${"Region".padEnd(10)} ${"Created".padEnd(12)}`;
12
13
  console.log(header);
13
14
  console.log("─".repeat(header.length));
14
15
  // Table rows
15
16
  for (const server of servers) {
16
17
  const created = server.createdAt ? server.createdAt.split("T")[0] : "N/A";
17
- console.log(`${server.id.padEnd(12)} ${server.name.padEnd(20)} ${server.provider.padEnd(14)} ${server.ip.padEnd(16)} ${server.region.padEnd(10)} ${created.padEnd(12)}`);
18
+ const mode = getServerMode(server);
19
+ console.log(`${server.id.padEnd(12)} ${server.name.padEnd(20)} ${server.provider.padEnd(14)} ${mode.padEnd(10)} ${server.ip.padEnd(16)} ${server.region.padEnd(10)} ${created.padEnd(12)}`);
18
20
  }
19
21
  console.log();
20
22
  logger.info(`Total: ${servers.length} server(s)`);
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAEnC,eAAe;IACf,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IACpJ,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvC,aAAa;IACb,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1E,OAAO,CAAC,GAAG,CACT,GAAG,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAC5J,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,MAAM,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;AACpD,CAAC"}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAEnC,eAAe;IACf,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IACzK,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvC,aAAa;IACb,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1E,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CACT,GAAG,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAC/K,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,MAAM,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;AACpD,CAAC"}
@@ -1,5 +1,6 @@
1
- export type LogService = "coolify" | "docker" | "system";
2
- export declare function buildLogCommand(service: LogService, lines: number, follow: boolean): string;
1
+ import { buildLogCommand } from "../core/logs.js";
2
+ import type { LogService } from "../core/logs.js";
3
+ export { buildLogCommand, type LogService };
3
4
  export declare function logsCommand(query?: string, options?: {
4
5
  lines?: string;
5
6
  follow?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEzD,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAS3F;AAED,wBAAsB,WAAW,CAC/B,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAwCf"}
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,CAAC;AAE5C,wBAAsB,WAAW,CAC/B,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAoDf"}
@@ -1,16 +1,9 @@
1
1
  import { resolveServer } from "../utils/serverSelect.js";
2
2
  import { checkSshAvailable, sshExec, sshStream } from "../utils/ssh.js";
3
3
  import { logger } from "../utils/logger.js";
4
- export function buildLogCommand(service, lines, follow) {
5
- switch (service) {
6
- case "coolify":
7
- return `docker logs coolify --tail ${lines}${follow ? " --follow" : ""}`;
8
- case "docker":
9
- return `journalctl -u docker --no-pager -n ${lines}${follow ? " -f" : ""}`;
10
- case "system":
11
- return `journalctl --no-pager -n ${lines}${follow ? " -f" : ""}`;
12
- }
13
- }
4
+ import { isBareServer } from "../utils/modeGuard.js";
5
+ import { buildLogCommand } from "../core/logs.js";
6
+ export { buildLogCommand };
14
7
  export async function logsCommand(query, options) {
15
8
  if (!checkSshAvailable()) {
16
9
  logger.error("SSH client not found. Please install OpenSSH.");
@@ -24,18 +17,28 @@ export async function logsCommand(query, options) {
24
17
  logger.error("Invalid --lines value. Must be a positive number.");
25
18
  return;
26
19
  }
27
- const service = options?.service || "coolify";
20
+ // For bare servers, default to "system" if no explicit service specified
21
+ const defaultService = isBareServer(server) ? "system" : "coolify";
22
+ const service = options?.service || defaultService;
28
23
  const validServices = ["coolify", "docker", "system"];
29
24
  if (!validServices.includes(service)) {
30
25
  logger.error(`Invalid service: ${service}. Choose from: ${validServices.join(", ")}`);
31
26
  return;
32
27
  }
28
+ // Bare servers cannot access Coolify logs
29
+ if (isBareServer(server) && service === "coolify") {
30
+ logger.error("Coolify logs are not available for bare servers. Use --service system or --service docker instead.");
31
+ return;
32
+ }
33
33
  const follow = options?.follow || false;
34
34
  const command = buildLogCommand(service, lines, follow);
35
35
  logger.info(`Fetching ${service} logs from ${server.name} (${server.ip})...`);
36
36
  if (follow) {
37
37
  const exitCode = await sshStream(server.ip, command);
38
- if (exitCode !== 0) {
38
+ if (exitCode === 130) {
39
+ // Ctrl+C — normal user-initiated exit
40
+ }
41
+ else if (exitCode !== 0) {
39
42
  logger.error(`Log stream ended with code ${exitCode}`);
40
43
  }
41
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"maintain.d.ts","sourceRoot":"","sources":["../../src/commands/maintain.ts"],"names":[],"mappings":"AAYA,UAAU,eAAe;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAgTD,wBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB9F"}
1
+ {"version":3,"file":"maintain.d.ts","sourceRoot":"","sources":["../../src/commands/maintain.ts"],"names":[],"mappings":"AAcA,UAAU,eAAe;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAuRD,wBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B9F"}
@@ -1,35 +1,12 @@
1
1
  import inquirer from "inquirer";
2
- import axios from "axios";
3
2
  import { getServers } from "../utils/config.js";
4
3
  import { resolveServer, promptApiToken, collectProviderTokens } from "../utils/serverSelect.js";
5
- import { createProviderWithToken } from "../utils/providerFactory.js";
6
- import { checkSshAvailable, sshExec } from "../utils/ssh.js";
4
+ import { checkSshAvailable } from "../utils/ssh.js";
7
5
  import { logger, createSpinner } from "../utils/logger.js";
8
- import { getErrorMessage, mapProviderError, mapSshError } from "../utils/errorMapper.js";
9
- const COOLIFY_UPDATE_CMD = "curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash";
10
- async function checkCoolifyHealth(ip) {
11
- try {
12
- await axios.get(`http://${ip}:8000`, {
13
- timeout: 5000,
14
- validateStatus: () => true,
15
- });
16
- return true;
17
- }
18
- catch {
19
- return false;
20
- }
21
- }
22
- async function pollCoolifyHealth(ip, maxAttempts, intervalMs) {
23
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
24
- const healthy = await checkCoolifyHealth(ip);
25
- if (healthy)
26
- return true;
27
- if (attempt < maxAttempts) {
28
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
29
- }
30
- }
31
- return false;
32
- }
6
+ import { getErrorMessage, mapProviderError } from "../utils/errorMapper.js";
7
+ import { createProviderWithToken } from "../utils/providerFactory.js";
8
+ import { isBareServer, requireCoolifyMode } from "../utils/modeGuard.js";
9
+ import { executeCoolifyUpdate, pollCoolifyHealth, } from "../core/maintain.js";
33
10
  function showDryRun(server, skipReboot) {
34
11
  logger.title("Dry Run: Maintenance Steps");
35
12
  logger.step(`Target: ${server.name} (${server.ip})`);
@@ -126,29 +103,23 @@ async function maintainSingleServer(server, apiToken, options) {
126
103
  return result;
127
104
  }
128
105
  }
129
- // Step 2: Coolify update
106
+ // Step 2: Coolify update via core
130
107
  const updateSpinner = createSpinner("Step 2: Updating Coolify...");
131
108
  updateSpinner.start();
132
- try {
133
- const updateResult = await sshExec(server.ip, COOLIFY_UPDATE_CMD);
134
- if (updateResult.code !== 0) {
135
- updateSpinner.fail(`Step 2: Update failed (exit code ${updateResult.code})`);
136
- if (updateResult.stderr)
137
- logger.error(updateResult.stderr.trim());
138
- return result;
139
- }
140
- updateSpinner.succeed("Step 2: Coolify updated");
141
- result.update = true;
142
- }
143
- catch (error) {
144
- updateSpinner.fail("Step 2: Update failed");
145
- logger.error(getErrorMessage(error));
146
- const hint = mapSshError(error, server.ip);
147
- if (hint)
148
- logger.info(hint);
109
+ const updateResult = await executeCoolifyUpdate(server.ip);
110
+ if (!updateResult.success) {
111
+ updateSpinner.fail(`Step 2: Update failed`);
112
+ if (updateResult.output)
113
+ logger.error(updateResult.output.trim());
114
+ if (updateResult.error && !updateResult.output)
115
+ logger.error(updateResult.error);
116
+ if (updateResult.hint)
117
+ logger.info(updateResult.hint);
149
118
  return result;
150
119
  }
151
- // Step 3: Health check after update
120
+ updateSpinner.succeed("Step 2: Coolify updated");
121
+ result.update = true;
122
+ // Step 3: Health check after update via core
152
123
  const healthSpinner = createSpinner("Step 3: Checking Coolify health...");
153
124
  healthSpinner.start();
154
125
  const healthOk = await pollCoolifyHealth(server.ip, 12, 5000);
@@ -264,6 +235,11 @@ async function maintainAll(options) {
264
235
  const tokenMap = await collectProviderTokens(servers);
265
236
  const results = [];
266
237
  for (const server of servers) {
238
+ if (isBareServer(server)) {
239
+ logger.warning(`Skipping ${server.name}: maintain command is not available for bare servers (requires Coolify).`);
240
+ console.log();
241
+ continue;
242
+ }
267
243
  const token = tokenMap.get(server.provider);
268
244
  if (options.dryRun) {
269
245
  showDryRun(server, !!options.skipReboot);
@@ -290,6 +266,11 @@ export async function maintainCommand(query, options) {
290
266
  const server = await resolveServer(query, "Select a server to maintain:");
291
267
  if (!server)
292
268
  return;
269
+ const modeError = requireCoolifyMode(server, "maintain");
270
+ if (modeError) {
271
+ logger.error(modeError);
272
+ return;
273
+ }
293
274
  if (options?.dryRun) {
294
275
  showDryRun(server, !!options.skipReboot);
295
276
  return;