@mks2508/coolify-mks-cli-mcp 0.6.3 → 0.8.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 (60) hide show
  1. package/dist/cli/coolify-state.d.ts +92 -4
  2. package/dist/cli/coolify-state.d.ts.map +1 -1
  3. package/dist/cli/index.js +22149 -11456
  4. package/dist/cli/ui/highlighter.d.ts +28 -0
  5. package/dist/cli/ui/highlighter.d.ts.map +1 -0
  6. package/dist/cli/ui/index.d.ts +9 -0
  7. package/dist/cli/ui/index.d.ts.map +1 -0
  8. package/dist/cli/ui/spinners.d.ts +100 -0
  9. package/dist/cli/ui/spinners.d.ts.map +1 -0
  10. package/dist/cli/ui/tables.d.ts +103 -0
  11. package/dist/cli/ui/tables.d.ts.map +1 -0
  12. package/dist/coolify/index.d.ts +22 -3
  13. package/dist/coolify/index.d.ts.map +1 -1
  14. package/dist/coolify/types.d.ts +99 -1
  15. package/dist/coolify/types.d.ts.map +1 -1
  16. package/dist/examples/demo-ui.d.ts +8 -0
  17. package/dist/examples/demo-ui.d.ts.map +1 -0
  18. package/dist/index.cjs +322 -12
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.js +322 -12
  21. package/dist/index.js.map +1 -1
  22. package/dist/sdk.d.ts +41 -0
  23. package/dist/sdk.d.ts.map +1 -1
  24. package/dist/server/stdio.js +258 -9
  25. package/package.json +16 -4
  26. package/src/cli/actions.ts +9 -2
  27. package/src/cli/commands/create.ts +71 -5
  28. package/src/cli/commands/db.ts +37 -0
  29. package/src/cli/commands/delete.ts +6 -2
  30. package/src/cli/commands/deploy.ts +347 -49
  31. package/src/cli/commands/deployments.ts +6 -2
  32. package/src/cli/commands/diagnose.ts +3 -3
  33. package/src/cli/commands/env.ts +121 -22
  34. package/src/cli/commands/exec.ts +6 -2
  35. package/src/cli/commands/init.ts +937 -0
  36. package/src/cli/commands/logs.ts +224 -24
  37. package/src/cli/commands/main-menu.ts +21 -0
  38. package/src/cli/commands/projects.ts +312 -29
  39. package/src/cli/commands/restart.ts +6 -2
  40. package/src/cli/commands/service-logs.ts +14 -0
  41. package/src/cli/commands/show.ts +6 -2
  42. package/src/cli/commands/start.ts +6 -2
  43. package/src/cli/commands/status.ts +538 -0
  44. package/src/cli/commands/stop.ts +6 -2
  45. package/src/cli/commands/update.ts +27 -2
  46. package/src/cli/coolify-state.ts +164 -11
  47. package/src/cli/index.ts +91 -10
  48. package/src/cli/name-resolver.ts +228 -0
  49. package/src/cli/ui/banner.ts +276 -0
  50. package/src/cli/ui/highlighter.ts +176 -0
  51. package/src/cli/ui/index.ts +9 -0
  52. package/src/cli/ui/prompts.ts +155 -0
  53. package/src/cli/ui/screen.ts +606 -0
  54. package/src/cli/ui/select.ts +280 -0
  55. package/src/cli/ui/spinners.ts +256 -0
  56. package/src/cli/ui/tables.ts +407 -0
  57. package/src/coolify/index.ts +257 -12
  58. package/src/coolify/types.ts +103 -1
  59. package/src/examples/demo-ui.ts +78 -0
  60. package/src/sdk.ts +162 -0
@@ -5,94 +5,377 @@
5
5
  */
6
6
 
7
7
  import { isOk, isErr } from "@mks2508/no-throw";
8
- import ora from "ora";
9
8
  import chalk from "chalk";
10
9
  import Table from "cli-table3";
11
10
  import { getCoolifyService } from "../../coolify/index.js";
11
+ import { resolveProjectNameOrUuid } from "../name-resolver.js";
12
+ import {
13
+ createSpinner,
14
+ } from "../ui/spinners.js";
15
+ import {
16
+ createSummaryCard,
17
+ } from "../ui/index.js";
12
18
 
13
19
  /**
14
20
  * Projects command handler.
15
- * Lists all projects, or creates a new one if --create is provided.
21
+ * Lists all projects, shows project details, or creates a new one.
16
22
  */
17
23
  export async function projectsCommand(
18
- options: { full?: boolean; create?: string; description?: string } = {},
24
+ options: {
25
+ full?: boolean;
26
+ create?: string;
27
+ description?: string;
28
+ show?: string; // Show project details by UUID
29
+ apps?: string; // Show apps for project by UUID
30
+ } = {},
19
31
  ) {
20
- const spinner = ora("Connecting to Coolify...").start();
32
+ console.log("");
33
+ console.log(chalk.bold.cyan("┌─────────────────────────────────────────────┐"));
34
+ console.log(chalk.bold.cyan("│") + chalk.bold.white(" 📁 Coolify Projects") + chalk.bold.cyan(" │"));
35
+ console.log(chalk.bold.cyan("└─────────────────────────────────────────────┘"));
36
+ console.log("");
37
+
38
+ const spinner = createSpinner({
39
+ text: "Connecting to Coolify...",
40
+ color: "cyan",
41
+ }).start();
21
42
 
22
43
  try {
23
44
  const coolify = getCoolifyService();
24
45
  const initResult = await coolify.init();
25
46
 
26
47
  if (isErr(initResult)) {
27
- spinner.fail(
28
- chalk.red(`Failed to initialize: ${initResult.error.message}`),
29
- );
48
+ spinner.fail("Connection failed");
49
+ console.error(chalk.red(`Failed to initialize: ${initResult.error.message}`));
30
50
  return;
31
51
  }
32
52
 
53
+ spinner.succeed("Connected to Coolify");
54
+
33
55
  // Create mode
34
56
  if (options.create) {
35
- spinner.text = `Creating project "${options.create}"...`;
57
+ const createSpinner = createSpinner({
58
+ text: `Creating project "${options.create}"...`,
59
+ color: "green",
60
+ }).start();
61
+
36
62
  const createResult = await coolify.createProject(
37
63
  options.create,
38
64
  options.description,
39
65
  );
40
66
 
41
67
  if (isOk(createResult)) {
42
- spinner.succeed(
43
- chalk.green(
44
- `Project created: ${chalk.cyan(createResult.value.uuid)}`,
45
- ),
46
- );
47
- console.log(` Name: ${chalk.cyan(options.create)}`);
48
- console.log(` UUID: ${chalk.cyan(createResult.value.uuid)}`);
68
+ createSpinner.succeed(`Project ${chalk.bold.white(options.create)} created`);
69
+ console.log("");
70
+ console.log(createSummaryCard("Project Details", {
71
+ "Name": { value: options.create, color: chalk.white },
72
+ "UUID": { value: createResult.value.uuid, color: chalk.cyan },
73
+ "Description": { value: options.description || "-", color: chalk.gray },
74
+ }));
75
+ console.log("");
49
76
  } else {
50
- spinner.fail(
51
- chalk.red(`Failed to create project: ${createResult.error.message}`),
52
- );
77
+ createSpinner.fail("Failed to create project");
78
+ console.error(chalk.red(` ${createResult.error.message}`));
79
+ }
80
+ return;
81
+ }
82
+
83
+ // Show project details mode
84
+ if (options.show) {
85
+ const resolvedShow = await resolveProjectNameOrUuid(options.show);
86
+ if (!resolvedShow) {
87
+ console.error(chalk.red(` ✗ Project not found: ${options.show}`));
88
+ return;
53
89
  }
90
+ await showProjectDetails(coolify, resolvedShow);
91
+ return;
92
+ }
93
+
94
+ // Show apps for project mode
95
+ if (options.apps) {
96
+ const resolvedApps = await resolveProjectNameOrUuid(options.apps);
97
+ if (!resolvedApps) {
98
+ console.error(chalk.red(` ✗ Project not found: ${options.apps}`));
99
+ return;
100
+ }
101
+ await showProjectApps(coolify, resolvedApps);
54
102
  return;
55
103
  }
56
104
 
57
105
  // List mode
58
- spinner.text = "Fetching projects...";
106
+ const listSpinner = createSpinner({
107
+ text: "Fetching projects...",
108
+ color: "cyan",
109
+ }).start();
59
110
 
60
111
  const result = await coolify.listProjects();
61
112
 
62
113
  if (isOk(result)) {
63
- spinner.succeed(chalk.green("Projects retrieved"));
114
+ listSpinner.succeed(`Found ${chalk.bold.green(String(result.value.length))} project(s)`);
64
115
 
65
116
  const projects = result.value;
66
117
 
67
118
  if (projects.length === 0) {
68
- console.log(chalk.yellow("No projects found"));
119
+ console.log("");
120
+ console.log(chalk.yellow(" ⚠ No projects found"));
121
+ console.log("");
69
122
  return;
70
123
  }
71
124
 
125
+ console.log("");
72
126
  const table = new Table({
73
127
  head: [
74
- chalk.cyan("UUID"),
75
128
  chalk.cyan("Name"),
129
+ chalk.cyan("UUID"),
76
130
  chalk.cyan("Description"),
77
131
  ],
132
+ wordWrap: true,
133
+ colWidths: [30, 40, 50],
78
134
  });
79
135
 
80
136
  for (const project of projects) {
81
- table.push([project.uuid, project.name, project.description || "-"]);
137
+ table.push([
138
+ chalk.white(project.name),
139
+ chalk.gray(project.uuid.slice(0, 8) + "..."),
140
+ project.description || chalk.gray("-"),
141
+ ]);
82
142
  }
83
143
 
84
144
  console.log(table.toString());
85
- console.log(chalk.gray(`Total: ${projects.length} project(s)`));
86
- } else {
87
- spinner.fail(
88
- chalk.red(`Failed to fetch projects: ${result.error.message}`),
145
+ console.log("");
146
+ console.log(chalk.gray(" Commands:"));
147
+ console.log(
148
+ " " +
149
+ chalk.cyan("coolify-cli projects --show <uuid>") +
150
+ chalk.gray(" - Show project details"),
89
151
  );
152
+ console.log(
153
+ " " +
154
+ chalk.cyan("coolify-cli projects --apps <uuid>") +
155
+ chalk.gray(" - Show apps in project"),
156
+ );
157
+ console.log("");
158
+ } else {
159
+ listSpinner.fail("Failed to fetch projects");
160
+ console.error(chalk.red(` ✗ ${result.error.message}`));
90
161
  }
91
162
  } catch (error) {
92
- spinner.fail(
163
+ spinner.fail("Error");
164
+ console.error(
93
165
  chalk.red(
94
- `Error: ${error instanceof Error ? error.message : String(error)}`,
166
+ ` ${error instanceof Error ? error.message : String(error)}`,
95
167
  ),
96
168
  );
97
169
  }
98
170
  }
171
+
172
+ /**
173
+ * Show detailed information about a project.
174
+ */
175
+ async function showProjectDetails(coolify: any, projectUuid: string) {
176
+ const spinner = createSpinner({
177
+ text: "Fetching project details...",
178
+ color: "cyan",
179
+ }).start();
180
+
181
+ // Get project info
182
+ const projectsResult = await coolify.listProjects();
183
+ if (isErr(projectsResult)) {
184
+ spinner.fail("Failed to fetch project");
185
+ console.error(chalk.red(` ✗ ${projectsResult.error.message}`));
186
+ return;
187
+ }
188
+
189
+ const project = projectsResult.value.find((p: any) => p.uuid === projectUuid);
190
+ if (!project) {
191
+ spinner.fail("Project not found");
192
+ console.error(chalk.red(` ✗ Project not found: ${projectUuid}`));
193
+ return;
194
+ }
195
+
196
+ // Get environments
197
+ const envsResult = await coolify.getProjectEnvironments(projectUuid);
198
+ const environments = isOk(envsResult) ? envsResult.value : [];
199
+
200
+ // Get all apps and filter by project
201
+ const appsResult = await coolify.listApplications();
202
+ const projectApps = isOk(appsResult)
203
+ ? appsResult.value.filter((app: any) => app.environment_id &&
204
+ environments.some((env: any) => env.id === app.environment_id))
205
+ : [];
206
+
207
+ // Get all databases and filter by project
208
+ const dbsResult = await coolify.listDatabases();
209
+ const projectDbs = isOk(dbsResult)
210
+ ? dbsResult.value.filter((db: any) => db.environment_id &&
211
+ environments.some((env: any) => env.id === db.environment_id))
212
+ : [];
213
+
214
+ spinner.succeed("Project details retrieved");
215
+
216
+ console.log("");
217
+ console.log(createSummaryCard("Project Details", {
218
+ "Name": { value: project.name, color: chalk.white },
219
+ "UUID": { value: project.uuid, color: chalk.gray },
220
+ "Description": { value: project.description || "-", color: chalk.gray },
221
+ "Environments": { value: String(environments.length), color: chalk.cyan },
222
+ "Applications": { value: String(projectApps.length), color: chalk.green },
223
+ "Databases": { value: String(projectDbs.length), color: chalk.yellow },
224
+ }));
225
+
226
+ // Show environments
227
+ if (environments.length > 0) {
228
+ console.log("");
229
+ console.log(chalk.gray(" ") + chalk.bold("Environments:"));
230
+ console.log("");
231
+ for (const env of environments) {
232
+ const envApps = projectApps.filter((app: any) => app.environment_id === env.id);
233
+ const envDbs = projectDbs.filter((db: any) => db.environment_id === env.id);
234
+ console.log(
235
+ " " +
236
+ chalk.cyan("●") +
237
+ " " +
238
+ chalk.bold.white(env.name) +
239
+ chalk.gray(` (${env.uuid.slice(0, 8)}...)`),
240
+ );
241
+ console.log(
242
+ " " +
243
+ chalk.gray("Apps: ") +
244
+ chalk.green(String(envApps.length)) +
245
+ chalk.gray(" | Databases: ") +
246
+ chalk.yellow(String(envDbs.length)),
247
+ );
248
+ }
249
+ console.log("");
250
+ }
251
+
252
+ // Show apps
253
+ if (projectApps.length > 0) {
254
+ console.log("");
255
+ console.log(chalk.gray(" ") + chalk.bold("Applications:"));
256
+ console.log("");
257
+ for (const app of projectApps) {
258
+ const statusIcon = app.status.includes("running")
259
+ ? chalk.green("●")
260
+ : chalk.yellow("○");
261
+ console.log(
262
+ " " +
263
+ statusIcon +
264
+ " " +
265
+ chalk.bold.white(app.name) +
266
+ chalk.gray(` (${app.uuid.slice(0, 8)}...)`),
267
+ );
268
+ console.log(
269
+ " " +
270
+ chalk.gray("Status: ") +
271
+ chalk.white(app.status) +
272
+ chalk.gray(" | Branch: ") +
273
+ chalk.cyan(app.git_branch || "-"),
274
+ );
275
+ }
276
+ console.log("");
277
+ }
278
+
279
+ // Show databases
280
+ if (projectDbs.length > 0) {
281
+ console.log("");
282
+ console.log(chalk.gray(" ") + chalk.bold("Databases:"));
283
+ console.log("");
284
+ for (const db of projectDbs) {
285
+ const statusIcon = db.status === "running"
286
+ ? chalk.green("●")
287
+ : chalk.yellow("○");
288
+ console.log(
289
+ " " +
290
+ statusIcon +
291
+ " " +
292
+ chalk.bold.white(db.name) +
293
+ chalk.gray(` (${db.type})`),
294
+ );
295
+ console.log(
296
+ " " +
297
+ chalk.gray("Status: ") +
298
+ chalk.white(db.status) +
299
+ chalk.gray(" | UUID: ") +
300
+ chalk.gray(db.uuid.slice(0, 8)) +
301
+ chalk.gray("..."),
302
+ );
303
+ }
304
+ console.log("");
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Show all applications in a project.
310
+ */
311
+ async function showProjectApps(coolify: any, projectUuid: string) {
312
+ const spinner = createSpinner({
313
+ text: "Fetching project applications...",
314
+ color: "cyan",
315
+ }).start();
316
+
317
+ // Get environments
318
+ const envsResult = await coolify.getProjectEnvironments(projectUuid);
319
+ const environments = isOk(envsResult) ? envsResult.value : [];
320
+
321
+ // Get all apps and filter by project
322
+ const appsResult = await coolify.listApplications();
323
+ const projectApps = isOk(appsResult)
324
+ ? appsResult.value.filter((app: any) => app.environment_id &&
325
+ environments.some((env: any) => env.id === app.environment_id))
326
+ : [];
327
+
328
+ spinner.succeed(`Found ${chalk.bold.green(String(projectApps.length))} application(s)`);
329
+
330
+ if (projectApps.length === 0) {
331
+ console.log("");
332
+ console.log(chalk.yellow(" ⚠ No applications found in this project"));
333
+ console.log("");
334
+ return;
335
+ }
336
+
337
+ console.log("");
338
+ const table = new Table({
339
+ head: [
340
+ chalk.cyan("Name"),
341
+ chalk.cyan("Status"),
342
+ chalk.cyan("Type"),
343
+ chalk.cyan("Branch"),
344
+ chalk.cyan("UUID"),
345
+ ],
346
+ wordWrap: true,
347
+ colWidths: [30, 20, 15, 15, 40],
348
+ });
349
+
350
+ for (const app of projectApps) {
351
+ const statusColor = app.status.includes("running") ? chalk.green : chalk.yellow;
352
+ const appType = getAppTypeFromSourceType(app.source_type);
353
+
354
+ table.push([
355
+ chalk.white(app.name),
356
+ statusColor(app.status),
357
+ chalk.gray(appType),
358
+ chalk.cyan(app.git_branch || "-"),
359
+ chalk.gray(app.uuid.slice(0, 8) + "..."),
360
+ ]);
361
+ }
362
+
363
+ console.log(table.toString());
364
+ console.log("");
365
+ }
366
+
367
+ /**
368
+ * Map source_type to readable app type.
369
+ */
370
+ function getAppTypeFromSourceType(sourceType: string | undefined): string {
371
+ if (!sourceType) return "unknown";
372
+
373
+ if (sourceType.includes("GithubApp")) return "github-app";
374
+ if (sourceType.includes("DeployKey")) return "deploy-key";
375
+ if (sourceType.includes("Dockerfile")) return "dockerfile";
376
+ if (sourceType.includes("DockerCompose")) return "docker-compose";
377
+ if (sourceType.includes("DockerImage")) return "docker-image";
378
+ if (sourceType.includes("Public")) return "public";
379
+
380
+ return "unknown";
381
+ }
@@ -9,6 +9,7 @@ import ora from "ora";
9
9
  import chalk from "chalk";
10
10
  import { getCoolifyService } from "../../coolify/index.js";
11
11
  import { resolveUuid } from "../coolify-state.js";
12
+ import { resolveAppNameOrUuid } from "../name-resolver.js";
12
13
 
13
14
  /**
14
15
  * Restart command handler.
@@ -17,10 +18,13 @@ import { resolveUuid } from "../coolify-state.js";
17
18
  * @param uuid - Application UUID (optional if .coolify.json exists)
18
19
  */
19
20
  export async function restartCommand(uuid?: string) {
20
- const resolvedUuid = resolveUuid(uuid);
21
+ let resolvedUuid = resolveUuid(uuid);
22
+ if (!resolvedUuid && uuid) {
23
+ resolvedUuid = await resolveAppNameOrUuid(uuid);
24
+ }
21
25
  if (!resolvedUuid) {
22
26
  console.error(
23
- chalk.red("Error: No UUID provided and no .coolify.json found"),
27
+ chalk.red("Error: No UUID/name provided and no .coolify.json found"),
24
28
  );
25
29
  return;
26
30
  }
@@ -9,6 +9,8 @@
9
9
  import { isErr } from "@mks2508/no-throw";
10
10
  import chalk from "chalk";
11
11
  import { getCoolifyService } from "../../coolify/index.js";
12
+ import { resolveUuid } from "../coolify-state.js";
13
+ import { resolveAppNameOrUuid } from "../name-resolver.js";
12
14
 
13
15
  /**
14
16
  * Service logs command handler.
@@ -22,6 +24,18 @@ export async function serviceLogsCommand(
22
24
  serviceName: string,
23
25
  options: { lines?: number },
24
26
  ) {
27
+ let resolvedUuid = resolveUuid(uuid);
28
+ if (!resolvedUuid && uuid) {
29
+ resolvedUuid = await resolveAppNameOrUuid(uuid);
30
+ }
31
+ if (!resolvedUuid) {
32
+ console.error(
33
+ chalk.red("Error: No UUID/name provided and no .coolify.json found"),
34
+ );
35
+ return;
36
+ }
37
+ uuid = resolvedUuid;
38
+
25
39
  const coolify = getCoolifyService();
26
40
  const initResult = await coolify.init();
27
41
 
@@ -10,6 +10,7 @@ import { isErr } from "@mks2508/no-throw";
10
10
  import chalk from "chalk";
11
11
  import { getCoolifyService } from "../../coolify/index.js";
12
12
  import { resolveUuid } from "../coolify-state.js";
13
+ import { resolveAppNameOrUuid } from "../name-resolver.js";
13
14
 
14
15
  /**
15
16
  * Show command handler.
@@ -18,10 +19,13 @@ import { resolveUuid } from "../coolify-state.js";
18
19
  * @param uuid - Application UUID (optional if .coolify.json exists)
19
20
  */
20
21
  export async function showCommand(uuid?: string) {
21
- const resolvedUuid = resolveUuid(uuid);
22
+ let resolvedUuid = resolveUuid(uuid);
23
+ if (!resolvedUuid && uuid) {
24
+ resolvedUuid = await resolveAppNameOrUuid(uuid);
25
+ }
22
26
  if (!resolvedUuid) {
23
27
  console.error(
24
- chalk.red("Error: No UUID provided and no .coolify.json found"),
28
+ chalk.red("Error: No UUID/name provided and no .coolify.json found"),
25
29
  );
26
30
  return;
27
31
  }
@@ -9,6 +9,7 @@ import ora from "ora";
9
9
  import chalk from "chalk";
10
10
  import { getCoolifyService } from "../../coolify/index.js";
11
11
  import { resolveUuid } from "../coolify-state.js";
12
+ import { resolveAppNameOrUuid } from "../name-resolver.js";
12
13
 
13
14
  /**
14
15
  * Start command handler.
@@ -17,10 +18,13 @@ import { resolveUuid } from "../coolify-state.js";
17
18
  * @param uuid - Application UUID (optional if .coolify.json exists)
18
19
  */
19
20
  export async function startCommand(uuid?: string) {
20
- const resolvedUuid = resolveUuid(uuid);
21
+ let resolvedUuid = resolveUuid(uuid);
22
+ if (!resolvedUuid && uuid) {
23
+ resolvedUuid = await resolveAppNameOrUuid(uuid);
24
+ }
21
25
  if (!resolvedUuid) {
22
26
  console.error(
23
- chalk.red("Error: No UUID provided and no .coolify.json found"),
27
+ chalk.red("Error: No UUID/name provided and no .coolify.json found"),
24
28
  );
25
29
  return;
26
30
  }