@mks2508/coolify-mks-cli-mcp 0.8.0 → 0.9.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.
- package/dist/cli/coolify-state.d.ts +12 -4
- package/dist/cli/coolify-state.d.ts.map +1 -1
- package/dist/cli/index.js +8886 -7957
- package/dist/coolify/config.d.ts +25 -0
- package/dist/coolify/config.d.ts.map +1 -1
- package/dist/coolify/index.d.ts +118 -10
- package/dist/coolify/index.d.ts.map +1 -1
- package/dist/coolify/types.d.ts +61 -1
- package/dist/coolify/types.d.ts.map +1 -1
- package/dist/index.cjs +2267 -227
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2289 -227
- package/dist/index.js.map +1 -1
- package/dist/sdk.d.ts +56 -8
- package/dist/sdk.d.ts.map +1 -1
- package/dist/server/stdio.js +253 -100
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/utils/env-parser.d.ts +24 -0
- package/dist/utils/env-parser.d.ts.map +1 -0
- package/dist/utils/format.d.ts +32 -0
- package/dist/utils/format.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/cli/commands/create.ts +279 -37
- package/src/cli/commands/env.ts +348 -54
- package/src/cli/commands/init.ts +69 -15
- package/src/cli/commands/main-menu.ts +1 -1
- package/src/cli/commands/projects.ts +3 -3
- package/src/cli/commands/show.ts +39 -10
- package/src/cli/commands/status.ts +23 -7
- package/src/cli/commands/svc.ts +7 -1
- package/src/cli/commands/update.ts +52 -0
- package/src/cli/commands/volumes.ts +293 -0
- package/src/cli/coolify-state.ts +42 -4
- package/src/cli/index.ts +50 -4
- package/src/cli/ui/banner.ts +3 -3
- package/src/cli/ui/screen.ts +26 -2
- package/src/coolify/config.ts +75 -0
- package/src/coolify/index.ts +325 -106
- package/src/coolify/types.ts +62 -1
- package/src/sdk.ts +87 -39
- package/src/tools/definitions.ts +22 -0
- package/src/tools/handlers.ts +19 -0
- package/src/utils/env-parser.ts +45 -0
- package/src/utils/format.ts +178 -0
package/src/cli/index.ts
CHANGED
|
@@ -82,6 +82,11 @@ import {
|
|
|
82
82
|
networkInspectCommand,
|
|
83
83
|
analyzeDeployCommand,
|
|
84
84
|
} from "./commands/network.js";
|
|
85
|
+
import {
|
|
86
|
+
volumesListCommand,
|
|
87
|
+
volumesAddCommand,
|
|
88
|
+
volumesRemoveCommand,
|
|
89
|
+
} from "./commands/volumes.js";
|
|
85
90
|
|
|
86
91
|
const program = new Command();
|
|
87
92
|
|
|
@@ -94,11 +99,11 @@ program
|
|
|
94
99
|
`${chalk.bold.hex("#8c52ff")("Coolify CLI")} — Manage deployments, env vars, and resources\n` +
|
|
95
100
|
` Global: ${chalk.gray("bun install -g @mks2508/coolify-mks-cli-mcp")}`,
|
|
96
101
|
)
|
|
97
|
-
.version("0.
|
|
102
|
+
.version("0.9.0")
|
|
98
103
|
.addHelpText("beforeAll", () => {
|
|
99
104
|
// Show banner before help output
|
|
100
105
|
const { showAutoBanner } = require("./ui/banner.js");
|
|
101
|
-
showAutoBanner("0.
|
|
106
|
+
showAutoBanner("0.9.0");
|
|
102
107
|
return "";
|
|
103
108
|
});
|
|
104
109
|
|
|
@@ -149,6 +154,10 @@ program
|
|
|
149
154
|
"--github-app-uuid <uuid>",
|
|
150
155
|
"GitHub App UUID (auto-detected if not provided)",
|
|
151
156
|
)
|
|
157
|
+
.option(
|
|
158
|
+
"--private-key-uuid <uuid>",
|
|
159
|
+
"Private key UUID (required for private-deploy-key type)",
|
|
160
|
+
)
|
|
152
161
|
.option(
|
|
153
162
|
"--domain <domain>",
|
|
154
163
|
"Domain to set after creation (e.g., app.example.com or https://app.example.com)",
|
|
@@ -247,14 +256,21 @@ program
|
|
|
247
256
|
program
|
|
248
257
|
.command("env [uuid]")
|
|
249
258
|
.description("Manage env vars (reads .coolify.json if no UUID)")
|
|
250
|
-
.option(
|
|
259
|
+
.option(
|
|
260
|
+
"--set <KEY=VALUE>",
|
|
261
|
+
"Set an environment variable (can be repeated: --set A=1 --set B=2)",
|
|
262
|
+
(value: string, prev: string[] | undefined) => (prev ?? []).concat(value),
|
|
263
|
+
[] as string[],
|
|
264
|
+
)
|
|
251
265
|
.option("--delete <KEY>", "Delete an environment variable")
|
|
266
|
+
.option("--get <KEY>", "Get a single environment variable value (prints value, no colors)")
|
|
252
267
|
.option("--buildtime", "Mark variable as build-time only (use with --set)")
|
|
253
268
|
.option("--runtime-only", "Mark variable as runtime only, not build-time (use with --set)")
|
|
254
|
-
.option("--sync [file]", "Sync env vars from .env file (default: .env)")
|
|
269
|
+
.option("--sync [file]", "Sync env vars from .env file (default: .env, or stdin with -)")
|
|
255
270
|
.option("--dry-run", "Preview changes without applying (use with --sync)")
|
|
256
271
|
.option("--prune", "Delete vars not in file (use with --sync)")
|
|
257
272
|
.option("--table", "Show env vars in table format")
|
|
273
|
+
.option("--json", "Output machine-parseable JSON (ICoolifyEnvVar[])")
|
|
258
274
|
.action((uuid, options) => envCommand(uuid, options));
|
|
259
275
|
|
|
260
276
|
// Update application
|
|
@@ -283,6 +299,11 @@ program
|
|
|
283
299
|
)
|
|
284
300
|
.option("--auto-deploy", "Enable auto-deploy on git push")
|
|
285
301
|
.option("--no-auto-deploy", "Disable auto-deploy on git push")
|
|
302
|
+
.option(
|
|
303
|
+
"--watch-paths <paths>",
|
|
304
|
+
'Watch paths for selective auto-deploy (newline-separated globs, e.g. "src/**\\npackages/**")',
|
|
305
|
+
)
|
|
306
|
+
.option("--clear-watch-paths", "Clear watch paths (deploy on all changes)")
|
|
286
307
|
.option("--force-https", "Enable forced HTTPS redirect")
|
|
287
308
|
.option("--health-check-enabled", "Enable health check")
|
|
288
309
|
.option("--no-health-check-enabled", "Disable health check")
|
|
@@ -553,6 +574,31 @@ program
|
|
|
553
574
|
.description("Analyze a failed deployment (extract errors, suggest fixes)")
|
|
554
575
|
.action(analyzeDeployCommand);
|
|
555
576
|
|
|
577
|
+
// ─── Volumes subcommands ──────────────────────────────────────────────────────
|
|
578
|
+
|
|
579
|
+
const volumes = program.command("volumes").description("Manage volumes for docker-compose apps");
|
|
580
|
+
volumes
|
|
581
|
+
.command("list <uuid>")
|
|
582
|
+
.description("List volumes for an application")
|
|
583
|
+
.option("--service <name>", "Service name (for multi-service compose)")
|
|
584
|
+
.action((uuid, options) => volumesListCommand(uuid, options));
|
|
585
|
+
volumes
|
|
586
|
+
.command("add <uuid>")
|
|
587
|
+
.description("Add a bind mount volume")
|
|
588
|
+
.requiredOption("--source <path>", "Source path on host")
|
|
589
|
+
.requiredOption("--target <path>", "Target path in container")
|
|
590
|
+
.option("--service <name>", "Service name (required for multi-service compose)")
|
|
591
|
+
.option("--no-restart", "Skip automatic redeploy after adding volume")
|
|
592
|
+
.action((uuid, options) => volumesAddCommand(uuid, options));
|
|
593
|
+
volumes
|
|
594
|
+
.command("remove <uuid>")
|
|
595
|
+
.description("Remove a volume by target path")
|
|
596
|
+
.requiredOption("--target <path>", "Target path in container to remove")
|
|
597
|
+
.option("--service <name>", "Service name (required for multi-service compose)")
|
|
598
|
+
.option("--no-restart", "Skip automatic redeploy after removing volume")
|
|
599
|
+
.action((uuid, options) => volumesRemoveCommand(uuid, options));
|
|
600
|
+
volumes.action(() => volumes.help());
|
|
601
|
+
|
|
556
602
|
// Show help by default (or interactive menu if no args)
|
|
557
603
|
program.action(async () => {
|
|
558
604
|
// If called without arguments, show interactive menu
|
package/src/cli/ui/banner.ts
CHANGED
|
@@ -203,7 +203,7 @@ export function getMiniLogoLines(): string[] {
|
|
|
203
203
|
* @param subtitle - Optional subtitle line
|
|
204
204
|
*/
|
|
205
205
|
export function showBanner(
|
|
206
|
-
version: string = "0.
|
|
206
|
+
version: string = "0.9.0",
|
|
207
207
|
subtitle?: string,
|
|
208
208
|
): void {
|
|
209
209
|
const logoLines = renderLogo();
|
|
@@ -244,7 +244,7 @@ export function showBanner(
|
|
|
244
244
|
*
|
|
245
245
|
* @param version - CLI version string
|
|
246
246
|
*/
|
|
247
|
-
export function showCompactBanner(version: string = "0.
|
|
247
|
+
export function showCompactBanner(version: string = "0.9.0"): void {
|
|
248
248
|
console.log(
|
|
249
249
|
`${chalk.hex("#8c52ff")("█")} ${chalk.bold("Coolify CLI")} ${chalk.gray(`v${version}`)}`,
|
|
250
250
|
);
|
|
@@ -257,7 +257,7 @@ export function showCompactBanner(version: string = "0.8.0"): void {
|
|
|
257
257
|
* @param subtitle - Optional subtitle for full banner
|
|
258
258
|
*/
|
|
259
259
|
export function showAutoBanner(
|
|
260
|
-
version: string = "0.
|
|
260
|
+
version: string = "0.9.0",
|
|
261
261
|
subtitle?: string,
|
|
262
262
|
): void {
|
|
263
263
|
if (process.stdout.isTTY) {
|
package/src/cli/ui/screen.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
ICoolifyApplication,
|
|
13
13
|
ICoolifyResource,
|
|
14
14
|
} from "../../coolify/types.js";
|
|
15
|
-
import { loadConfig } from "../../coolify/config.js";
|
|
15
|
+
import { loadConfig, getCachedAppSettings } from "../../coolify/config.js";
|
|
16
16
|
import { getMiniLogoLines } from "./banner.js";
|
|
17
17
|
|
|
18
18
|
// ─── ANSI ────────────────────────────────────────────────────────────────────
|
|
@@ -147,7 +147,7 @@ function renderHeader(tree: ICoolifyInfrastructureTree): void {
|
|
|
147
147
|
|
|
148
148
|
const textLines = [
|
|
149
149
|
"",
|
|
150
|
-
`${chalk.bold.hex("#a875ff")("Coolify CLI")} ${chalk.hex("#777777")("v0.
|
|
150
|
+
`${chalk.bold.hex("#a875ff")("Coolify CLI")} ${chalk.hex("#777777")("v0.9.0")}`,
|
|
151
151
|
"",
|
|
152
152
|
`${chalk.hex("#cccccc")(serverDisplay)}`,
|
|
153
153
|
"",
|
|
@@ -400,6 +400,25 @@ function buildDetailPanel(
|
|
|
400
400
|
);
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
// Deploy settings (auto-deploy from API settings or local cache, watch_paths from API)
|
|
404
|
+
lines.push("");
|
|
405
|
+
const autoDeployFromApi = app.settings?.is_auto_deploy_enabled;
|
|
406
|
+
// getCachedAppSettings is async but we need sync here — use a pre-fetched value
|
|
407
|
+
// passed via the context, or show API value / fallback
|
|
408
|
+
if (autoDeployFromApi !== undefined) {
|
|
409
|
+
lines.push(
|
|
410
|
+
`${chalk.hex("#888888")("Auto-deploy:")} ${autoDeployFromApi ? chalk.green("ON") : chalk.red("OFF")}`,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
if (app.watch_paths) {
|
|
414
|
+
const paths = app.watch_paths.split("\n").filter(Boolean);
|
|
415
|
+
lines.push(`${chalk.hex("#888888")("Watch:")} ${chalk.hex("#cccccc")(paths[0])}`);
|
|
416
|
+
for (const p of paths.slice(1, 3)) {
|
|
417
|
+
lines.push(` ${chalk.hex("#cccccc")(p)}`);
|
|
418
|
+
}
|
|
419
|
+
if (paths.length > 3) lines.push(chalk.hex("#555555")(` +${paths.length - 3} more`));
|
|
420
|
+
}
|
|
421
|
+
|
|
403
422
|
if (app.install_command || app.build_command || app.start_command) {
|
|
404
423
|
lines.push("");
|
|
405
424
|
if (app.install_command) lines.push(`${chalk.hex("#888888")("Install:")} ${chalk.hex("#aaaaaa")(app.install_command.slice(0, rightW - 10))}`);
|
|
@@ -564,6 +583,11 @@ export function buildResourcePreview(app: ICoolifyApplication): string[] {
|
|
|
564
583
|
for (const [label, value] of fields) {
|
|
565
584
|
if (value) lines.push(`${chalk.hex("#888888")(label + ":")} ${chalk.hex("#cccccc")(value)}`);
|
|
566
585
|
}
|
|
586
|
+
if (app.watch_paths) {
|
|
587
|
+
const paths = app.watch_paths.split("\n").filter(Boolean);
|
|
588
|
+
lines.push(`${chalk.hex("#888888")("Watch:")} ${chalk.hex("#cccccc")(paths[0])}`);
|
|
589
|
+
if (paths.length > 1) lines.push(chalk.hex("#555555")(` +${paths.length - 1} more`));
|
|
590
|
+
}
|
|
567
591
|
if (app.destination?.server) {
|
|
568
592
|
lines.push("");
|
|
569
593
|
lines.push(`${chalk.hex("#888888")("Server:")} ${chalk.hex("#cccccc")(app.destination.server.name)}`);
|
package/src/coolify/config.ts
CHANGED
|
@@ -112,4 +112,79 @@ export async function getCoolifyToken(): Promise<string | undefined> {
|
|
|
112
112
|
return process.env.COOLIFY_TOKEN;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// ─── App Settings Cache ──────────────────────────────────────────────────────
|
|
116
|
+
// Coolify API GET does not return application_settings (is_auto_deploy_enabled,
|
|
117
|
+
// is_force_https_enabled, etc). We cache these locally when the user sets them
|
|
118
|
+
// via our CLI so we can display them later in `show`.
|
|
119
|
+
|
|
120
|
+
const SETTINGS_CACHE_FILE = join(CONFIG_DIR, "app-settings-cache.json");
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Cached application settings that the Coolify API doesn't expose in GET responses.
|
|
124
|
+
*/
|
|
125
|
+
export interface ICachedAppSettings {
|
|
126
|
+
/** Auto-deploy on git push */
|
|
127
|
+
isAutoDeployEnabled?: boolean;
|
|
128
|
+
/** Watch paths for selective deploy */
|
|
129
|
+
watchPaths?: string | null;
|
|
130
|
+
/** When this cache entry was last updated */
|
|
131
|
+
cachedAt?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Reads the full settings cache from disk.
|
|
136
|
+
*
|
|
137
|
+
* @returns Map of appUuid → cached settings
|
|
138
|
+
*/
|
|
139
|
+
async function readSettingsCache(): Promise<Record<string, ICachedAppSettings>> {
|
|
140
|
+
try {
|
|
141
|
+
if (existsSync(SETTINGS_CACHE_FILE)) {
|
|
142
|
+
const content = await readFile(SETTINGS_CACHE_FILE, "utf-8");
|
|
143
|
+
return JSON.parse(content);
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
// Corrupted file — start fresh
|
|
147
|
+
}
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Caches application settings locally after a successful PATCH.
|
|
153
|
+
*
|
|
154
|
+
* @param appUuid - Application UUID
|
|
155
|
+
* @param settings - Settings to cache (merged with existing)
|
|
156
|
+
*/
|
|
157
|
+
export async function cacheAppSettings(
|
|
158
|
+
appUuid: string,
|
|
159
|
+
settings: Partial<ICachedAppSettings>,
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
try {
|
|
162
|
+
const cache = await readSettingsCache();
|
|
163
|
+
cache[appUuid] = {
|
|
164
|
+
...cache[appUuid],
|
|
165
|
+
...settings,
|
|
166
|
+
cachedAt: new Date().toISOString(),
|
|
167
|
+
};
|
|
168
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
169
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
170
|
+
}
|
|
171
|
+
await writeFile(SETTINGS_CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
172
|
+
} catch {
|
|
173
|
+
// Non-critical — silently ignore cache write failures
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Reads cached settings for an application.
|
|
179
|
+
*
|
|
180
|
+
* @param appUuid - Application UUID
|
|
181
|
+
* @returns Cached settings or null if not cached
|
|
182
|
+
*/
|
|
183
|
+
export async function getCachedAppSettings(
|
|
184
|
+
appUuid: string,
|
|
185
|
+
): Promise<ICachedAppSettings | null> {
|
|
186
|
+
const cache = await readSettingsCache();
|
|
187
|
+
return cache[appUuid] || null;
|
|
188
|
+
}
|
|
189
|
+
|
|
115
190
|
export { CONFIG_DIR, CONFIG_FILE };
|