@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/dist/server/stdio.js
CHANGED
|
@@ -1,31 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
7
13
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
8
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
23
|
for (let key of __getOwnPropNames(mod))
|
|
11
24
|
if (!__hasOwnProp.call(to, key))
|
|
12
25
|
__defProp(to, key, {
|
|
13
|
-
get: (
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
14
27
|
enumerable: true
|
|
15
28
|
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
16
31
|
return to;
|
|
17
32
|
};
|
|
18
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __returnValue = (v) => v;
|
|
35
|
+
function __exportSetter(name, newValue) {
|
|
36
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
+
}
|
|
19
38
|
var __export = (target, all) => {
|
|
20
39
|
for (var name in all)
|
|
21
40
|
__defProp(target, name, {
|
|
22
41
|
get: all[name],
|
|
23
42
|
enumerable: true,
|
|
24
43
|
configurable: true,
|
|
25
|
-
set: (
|
|
44
|
+
set: __exportSetter.bind(all, name)
|
|
26
45
|
});
|
|
27
46
|
};
|
|
28
47
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
48
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
29
49
|
|
|
30
50
|
// ../../../node_modules/.bun/ajv@8.17.1/node_modules/ajv/dist/compile/codegen/code.js
|
|
31
51
|
var require_code = __commonJS((exports) => {
|
|
@@ -6277,7 +6297,7 @@ var require_formats = __commonJS((exports) => {
|
|
|
6277
6297
|
}
|
|
6278
6298
|
var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
|
|
6279
6299
|
function getTime(strictTimeZone) {
|
|
6280
|
-
return function
|
|
6300
|
+
return function time3(str) {
|
|
6281
6301
|
const matches = TIME.exec(str);
|
|
6282
6302
|
if (!matches)
|
|
6283
6303
|
return false;
|
|
@@ -12971,6 +12991,11 @@ Redeploy after updating to apply changes.`,
|
|
|
12971
12991
|
type: "string",
|
|
12972
12992
|
description: 'Base directory for build context (default: "/")'
|
|
12973
12993
|
},
|
|
12994
|
+
watchPaths: {
|
|
12995
|
+
type: "string",
|
|
12996
|
+
description: 'Watch paths for selective auto-deploy. Newline-separated globs (e.g. "src/**\\npackages/**"). Set to empty string or null to clear.',
|
|
12997
|
+
nullable: true
|
|
12998
|
+
},
|
|
12974
12999
|
dockerComposeDomains: {
|
|
12975
13000
|
type: "string",
|
|
12976
13001
|
description: 'Docker Compose domains JSON: { "service-name": { "domain": "https://..." } }'
|
|
@@ -12979,6 +13004,22 @@ Redeploy after updating to apply changes.`,
|
|
|
12979
13004
|
required: ["uuid"]
|
|
12980
13005
|
}
|
|
12981
13006
|
},
|
|
13007
|
+
{
|
|
13008
|
+
name: "get_application",
|
|
13009
|
+
description: `Get detailed information about a Coolify application including settings (auto-deploy, force HTTPS) and watch paths.
|
|
13010
|
+
|
|
13011
|
+
Returns full application details that list_applications doesn't include.`,
|
|
13012
|
+
inputSchema: {
|
|
13013
|
+
type: "object",
|
|
13014
|
+
properties: {
|
|
13015
|
+
uuid: {
|
|
13016
|
+
type: "string",
|
|
13017
|
+
description: "Application UUID"
|
|
13018
|
+
}
|
|
13019
|
+
},
|
|
13020
|
+
required: ["uuid"]
|
|
13021
|
+
}
|
|
13022
|
+
},
|
|
12982
13023
|
{
|
|
12983
13024
|
name: "set_domains",
|
|
12984
13025
|
description: `Set domains/FQDN for a Coolify application.
|
|
@@ -18445,6 +18486,7 @@ async function loadConfig() {
|
|
|
18445
18486
|
return err(error2 instanceof Error ? error2 : new Error(String(error2)));
|
|
18446
18487
|
}
|
|
18447
18488
|
}
|
|
18489
|
+
var SETTINGS_CACHE_FILE = join(CONFIG_DIR, "app-settings-cache.json");
|
|
18448
18490
|
|
|
18449
18491
|
// src/coolify/index.ts
|
|
18450
18492
|
var log = component("CoolifyService");
|
|
@@ -18506,7 +18548,10 @@ class CoolifyService {
|
|
|
18506
18548
|
let data;
|
|
18507
18549
|
try {
|
|
18508
18550
|
data = text ? JSON.parse(text) : undefined;
|
|
18509
|
-
} catch {
|
|
18551
|
+
} catch (parseErr) {
|
|
18552
|
+
const preview = text ? text.slice(0, 200) : "(empty body)";
|
|
18553
|
+
const method = options.method ?? "GET";
|
|
18554
|
+
log.warn(`Failed to parse JSON response from ${method} ${endpoint} (status ${response.status}): ${parseErr instanceof Error ? parseErr.message : String(parseErr)}. Body preview: ${preview}`);
|
|
18510
18555
|
if (!response.ok) {
|
|
18511
18556
|
return {
|
|
18512
18557
|
error: text || `HTTP ${response.status}`,
|
|
@@ -18514,6 +18559,11 @@ class CoolifyService {
|
|
|
18514
18559
|
durationMs
|
|
18515
18560
|
};
|
|
18516
18561
|
}
|
|
18562
|
+
return {
|
|
18563
|
+
error: `Response was not valid JSON (status ${response.status}): ${preview}`,
|
|
18564
|
+
status: response.status,
|
|
18565
|
+
durationMs
|
|
18566
|
+
};
|
|
18517
18567
|
}
|
|
18518
18568
|
if (!response.ok) {
|
|
18519
18569
|
const parsed = data;
|
|
@@ -18580,8 +18630,8 @@ class CoolifyService {
|
|
|
18580
18630
|
"private-github-app": "/applications/private-github-app",
|
|
18581
18631
|
"private-deploy-key": "/applications/private-deploy-key",
|
|
18582
18632
|
dockerfile: "/applications/dockerfile",
|
|
18583
|
-
"docker-image": "/applications/
|
|
18584
|
-
"docker-compose": "/applications/
|
|
18633
|
+
"docker-image": "/applications/dockerimage",
|
|
18634
|
+
"docker-compose": "/applications/dockercompose",
|
|
18585
18635
|
dockerimage: "/applications/dockerimage",
|
|
18586
18636
|
dockercompose: "/applications/dockercompose"
|
|
18587
18637
|
};
|
|
@@ -18591,33 +18641,40 @@ class CoolifyService {
|
|
|
18591
18641
|
description: options.description,
|
|
18592
18642
|
project_uuid: options.projectUuid,
|
|
18593
18643
|
environment_uuid: options.environmentUuid,
|
|
18644
|
+
environment_name: options.environmentName,
|
|
18594
18645
|
server_uuid: options.serverUuid
|
|
18595
18646
|
};
|
|
18596
18647
|
if (options.githubRepoUrl) {
|
|
18597
|
-
body.git_repository = options.githubRepoUrl
|
|
18648
|
+
body.git_repository = options.githubRepoUrl;
|
|
18598
18649
|
}
|
|
18599
18650
|
if (appType === "public" || appType === "private-github-app" || appType === "private-deploy-key") {
|
|
18600
18651
|
if (options.githubAppUuid) {
|
|
18601
18652
|
body.github_app_uuid = options.githubAppUuid;
|
|
18602
18653
|
}
|
|
18654
|
+
if (appType === "private-deploy-key" && options.privateKeyUuid) {
|
|
18655
|
+
body.private_key_uuid = options.privateKeyUuid;
|
|
18656
|
+
}
|
|
18603
18657
|
body.git_branch = options.branch || "main";
|
|
18604
18658
|
body.build_pack = options.buildPack || "dockerfile";
|
|
18605
18659
|
if (options.portsExposes) {
|
|
18606
18660
|
body.ports_exposes = options.portsExposes;
|
|
18607
18661
|
}
|
|
18608
18662
|
if (options.dockerfileLocation) {
|
|
18609
|
-
|
|
18663
|
+
const p = options.dockerfileLocation;
|
|
18664
|
+
body.dockerfile_location = p.startsWith("/") ? p : `/${p}`;
|
|
18610
18665
|
}
|
|
18611
18666
|
if (options.dockerComposeLocation) {
|
|
18612
|
-
|
|
18667
|
+
const p = options.dockerComposeLocation;
|
|
18668
|
+
body.docker_compose_location = p.startsWith("/") ? p : `/${p}`;
|
|
18613
18669
|
}
|
|
18614
18670
|
if (options.baseDirectory) {
|
|
18615
|
-
|
|
18671
|
+
const p = options.baseDirectory;
|
|
18672
|
+
body.base_directory = p.startsWith("/") ? p : `/${p}`;
|
|
18616
18673
|
}
|
|
18617
18674
|
} else if (appType === "docker-image" && options.dockerImage) {
|
|
18618
|
-
body.
|
|
18675
|
+
body.docker_registry_image_name = options.dockerImage;
|
|
18619
18676
|
} else if (appType === "docker-compose" && options.dockerCompose) {
|
|
18620
|
-
body.
|
|
18677
|
+
body.docker_compose_raw = options.dockerCompose;
|
|
18621
18678
|
}
|
|
18622
18679
|
log.debug(`Create application body: ${JSON.stringify(body, null, 2)}`);
|
|
18623
18680
|
log.debug(`Endpoint: POST ${endpoint}`);
|
|
@@ -18638,37 +18695,17 @@ class CoolifyService {
|
|
|
18638
18695
|
}
|
|
18639
18696
|
async setEnvironmentVariables(appUuid, envVars) {
|
|
18640
18697
|
log.info(`Setting ${Object.keys(envVars).length} environment variables for ${appUuid}`);
|
|
18641
|
-
|
|
18642
|
-
|
|
18643
|
-
|
|
18644
|
-
|
|
18645
|
-
|
|
18646
|
-
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
18650
|
-
await this.request(`/applications/${appUuid}/envs/${existing.uuid}`, {
|
|
18651
|
-
method: "DELETE"
|
|
18652
|
-
});
|
|
18653
|
-
const repost = await this.request(`/applications/${appUuid}/envs`, {
|
|
18654
|
-
method: "POST",
|
|
18655
|
-
body: JSON.stringify({ key, value, is_preview: false, is_buildtime: false })
|
|
18656
|
-
});
|
|
18657
|
-
if (repost.error) {
|
|
18658
|
-
log.error(`Failed to update env var ${key}: ${repost.error}`);
|
|
18659
|
-
return err(new Error(`Failed to update ${key}: ${repost.error}`));
|
|
18660
|
-
}
|
|
18661
|
-
log.debug(`Updated existing env var: ${key}`);
|
|
18662
|
-
} else {
|
|
18663
|
-
log.error(`Failed to set env var ${key}: ${result.error}`);
|
|
18664
|
-
return err(new Error(`Failed to set ${key}: ${result.error}`));
|
|
18665
|
-
}
|
|
18666
|
-
} else if (result.error) {
|
|
18667
|
-
log.error(`Failed to set env var ${key}: ${result.error}`);
|
|
18668
|
-
return err(new Error(`Failed to set ${key}: ${result.error}`));
|
|
18669
|
-
}
|
|
18698
|
+
const vars = Object.entries(envVars).map(([key, value]) => ({
|
|
18699
|
+
key,
|
|
18700
|
+
value,
|
|
18701
|
+
is_buildtime: false,
|
|
18702
|
+
is_runtime: true
|
|
18703
|
+
}));
|
|
18704
|
+
const result = await this.bulkUpdateEnvironmentVariables(appUuid, vars);
|
|
18705
|
+
if (isErr(result)) {
|
|
18706
|
+
return err(result.error);
|
|
18670
18707
|
}
|
|
18671
|
-
log.success(`${
|
|
18708
|
+
log.success(`${vars.length} environment variables set`);
|
|
18672
18709
|
return ok(undefined);
|
|
18673
18710
|
}
|
|
18674
18711
|
async getEnvironmentVariables(appUuid) {
|
|
@@ -18683,39 +18720,16 @@ class CoolifyService {
|
|
|
18683
18720
|
}
|
|
18684
18721
|
async setEnvironmentVariable(appUuid, key, value, isBuildTime = false) {
|
|
18685
18722
|
log.info(`Setting environment variable ${key} for ${appUuid} (buildtime: ${isBuildTime})`);
|
|
18686
|
-
const
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
log.debug(`Variable ${key} exists, using PATCH to update`);
|
|
18693
|
-
const result = await this.request(`/applications/${appUuid}/envs`, {
|
|
18694
|
-
method: "PATCH",
|
|
18695
|
-
body: JSON.stringify({
|
|
18696
|
-
key,
|
|
18697
|
-
value,
|
|
18698
|
-
is_buildtime: isBuildTime
|
|
18699
|
-
})
|
|
18700
|
-
});
|
|
18701
|
-
if (result.error) {
|
|
18702
|
-
log.error(`Failed to update env var: ${result.error}`);
|
|
18703
|
-
return err(new Error(result.error));
|
|
18704
|
-
}
|
|
18705
|
-
} else {
|
|
18706
|
-
log.debug(`Variable ${key} does not exist, using POST to create`);
|
|
18707
|
-
const result = await this.request(`/applications/${appUuid}/envs`, {
|
|
18708
|
-
method: "POST",
|
|
18709
|
-
body: JSON.stringify({
|
|
18710
|
-
key,
|
|
18711
|
-
value,
|
|
18712
|
-
is_buildtime: isBuildTime
|
|
18713
|
-
})
|
|
18714
|
-
});
|
|
18715
|
-
if (result.error) {
|
|
18716
|
-
log.error(`Failed to create env var: ${result.error}`);
|
|
18717
|
-
return err(new Error(result.error));
|
|
18723
|
+
const result = await this.bulkUpdateEnvironmentVariables(appUuid, [
|
|
18724
|
+
{
|
|
18725
|
+
key,
|
|
18726
|
+
value,
|
|
18727
|
+
is_buildtime: isBuildTime,
|
|
18728
|
+
is_runtime: !isBuildTime
|
|
18718
18729
|
}
|
|
18730
|
+
]);
|
|
18731
|
+
if (isErr(result)) {
|
|
18732
|
+
return err(result.error);
|
|
18719
18733
|
}
|
|
18720
18734
|
log.success(`Environment variable ${key} set for ${appUuid}`);
|
|
18721
18735
|
return ok(undefined);
|
|
@@ -18789,6 +18803,23 @@ class CoolifyService {
|
|
|
18789
18803
|
return err(new Error(result.error));
|
|
18790
18804
|
return ok(result.data || []);
|
|
18791
18805
|
}
|
|
18806
|
+
async listGithubAppsAll(perPage = 50) {
|
|
18807
|
+
const allApps = [];
|
|
18808
|
+
let page = 1;
|
|
18809
|
+
while (true) {
|
|
18810
|
+
const result = await this.listGithubApps(page, perPage);
|
|
18811
|
+
if (isErr(result))
|
|
18812
|
+
return err(result.error);
|
|
18813
|
+
const apps = result.value;
|
|
18814
|
+
if (apps.length === 0)
|
|
18815
|
+
break;
|
|
18816
|
+
allApps.push(...apps);
|
|
18817
|
+
if (apps.length < perPage)
|
|
18818
|
+
break;
|
|
18819
|
+
page++;
|
|
18820
|
+
}
|
|
18821
|
+
return ok(allApps);
|
|
18822
|
+
}
|
|
18792
18823
|
async listProjects(page, perPage) {
|
|
18793
18824
|
let endpoint = "/projects";
|
|
18794
18825
|
const params = new URLSearchParams;
|
|
@@ -18924,10 +18955,14 @@ class CoolifyService {
|
|
|
18924
18955
|
body.domains = options.domains;
|
|
18925
18956
|
if (options.dockerComposeDomains)
|
|
18926
18957
|
body.docker_compose_domains = options.dockerComposeDomains;
|
|
18958
|
+
if (options.dockerComposeRaw !== undefined)
|
|
18959
|
+
body.docker_compose_raw = options.dockerComposeRaw;
|
|
18927
18960
|
if (options.isForceHttpsEnabled !== undefined)
|
|
18928
18961
|
body.is_force_https_enabled = options.isForceHttpsEnabled;
|
|
18929
18962
|
if (options.isAutoDeployEnabled !== undefined)
|
|
18930
18963
|
body.is_auto_deploy_enabled = options.isAutoDeployEnabled;
|
|
18964
|
+
if (options.watchPaths !== undefined)
|
|
18965
|
+
body.watch_paths = options.watchPaths;
|
|
18931
18966
|
if (options.healthCheckEnabled !== undefined)
|
|
18932
18967
|
body.health_check_enabled = options.healthCheckEnabled;
|
|
18933
18968
|
if (options.healthCheckPath)
|
|
@@ -18998,7 +19033,7 @@ class CoolifyService {
|
|
|
18998
19033
|
log.info(`Bulk updating ${envVars.length} env vars for ${appUuid}`);
|
|
18999
19034
|
const result = await this.request(`/applications/${appUuid}/envs/bulk`, {
|
|
19000
19035
|
method: "PATCH",
|
|
19001
|
-
body: JSON.stringify(envVars)
|
|
19036
|
+
body: JSON.stringify({ data: envVars })
|
|
19002
19037
|
});
|
|
19003
19038
|
if (result.error) {
|
|
19004
19039
|
log.error(`Failed to bulk update env vars: ${result.error}`);
|
|
@@ -19007,6 +19042,19 @@ class CoolifyService {
|
|
|
19007
19042
|
log.success(`Bulk updated ${envVars.length} env vars for ${appUuid}`);
|
|
19008
19043
|
return ok(result.data || { message: "Environment variables updated" });
|
|
19009
19044
|
}
|
|
19045
|
+
async bulkUpdateDatabaseEnvVars(databaseUuid, envVars) {
|
|
19046
|
+
log.info(`Bulk updating ${envVars.length} env vars for database ${databaseUuid}`);
|
|
19047
|
+
const result = await this.request(`/databases/${databaseUuid}/envs/bulk`, {
|
|
19048
|
+
method: "PATCH",
|
|
19049
|
+
body: JSON.stringify({ data: envVars })
|
|
19050
|
+
});
|
|
19051
|
+
if (result.error) {
|
|
19052
|
+
log.error(`Failed to bulk update database env vars: ${result.error}`);
|
|
19053
|
+
return err(new Error(result.error));
|
|
19054
|
+
}
|
|
19055
|
+
log.success(`Bulk updated ${envVars.length} env vars for database ${databaseUuid}`);
|
|
19056
|
+
return ok(result.data || { message: "Environment variables updated" });
|
|
19057
|
+
}
|
|
19010
19058
|
async getApplicationDeploymentHistory(appUuid) {
|
|
19011
19059
|
log.info(`Getting deployment history for ${appUuid}`);
|
|
19012
19060
|
const result = await this.request(`/deployments/applications/${appUuid}`);
|
|
@@ -19426,12 +19474,76 @@ class CoolifyService {
|
|
|
19426
19474
|
return err(new Error(result.error));
|
|
19427
19475
|
return ok(result.data || []);
|
|
19428
19476
|
}
|
|
19477
|
+
async bulkUpdateServiceEnvVars(serviceUuid, envVars) {
|
|
19478
|
+
log.info(`Bulk updating ${envVars.length} env vars for service ${serviceUuid}`);
|
|
19479
|
+
const result = await this.request(`/services/${serviceUuid}/envs/bulk`, {
|
|
19480
|
+
method: "PATCH",
|
|
19481
|
+
body: JSON.stringify({ data: envVars })
|
|
19482
|
+
});
|
|
19483
|
+
if (result.error) {
|
|
19484
|
+
log.error(`Failed to bulk update service env vars: ${result.error}`);
|
|
19485
|
+
return err(new Error(result.error));
|
|
19486
|
+
}
|
|
19487
|
+
log.success(`Bulk updated ${envVars.length} env vars for service ${serviceUuid}`);
|
|
19488
|
+
return ok(result.data || { message: "Environment variables updated" });
|
|
19489
|
+
}
|
|
19429
19490
|
async createServiceEnvVar(uuid2, data) {
|
|
19430
19491
|
const result = await this.request(`/services/${uuid2}/envs`, { method: "POST", body: JSON.stringify(data) });
|
|
19431
19492
|
if (result.error)
|
|
19432
19493
|
return err(new Error(result.error));
|
|
19433
19494
|
return ok(result.data);
|
|
19434
19495
|
}
|
|
19496
|
+
async deleteServiceEnvVar(serviceUuid, key) {
|
|
19497
|
+
log.info(`Deleting environment variable ${key} from service ${serviceUuid}`);
|
|
19498
|
+
const envVarsResult = await this.listServiceEnvVars(serviceUuid);
|
|
19499
|
+
if (isErr(envVarsResult)) {
|
|
19500
|
+
return err(envVarsResult.error);
|
|
19501
|
+
}
|
|
19502
|
+
const envVar = envVarsResult.value.find((ev) => ev.key === key);
|
|
19503
|
+
if (!envVar) {
|
|
19504
|
+
log.error(`Environment variable ${key} not found on service ${serviceUuid}`);
|
|
19505
|
+
return err(new Error(`Environment variable ${key} not found`));
|
|
19506
|
+
}
|
|
19507
|
+
const result = await this.request(`/services/${serviceUuid}/envs/${envVar.uuid}`, {
|
|
19508
|
+
method: "DELETE"
|
|
19509
|
+
});
|
|
19510
|
+
if (result.error) {
|
|
19511
|
+
log.error(`Failed to delete service env var: ${result.error}`);
|
|
19512
|
+
return err(new Error(result.error));
|
|
19513
|
+
}
|
|
19514
|
+
log.success(`Environment variable ${key} deleted from service ${serviceUuid}`);
|
|
19515
|
+
return ok(undefined);
|
|
19516
|
+
}
|
|
19517
|
+
async listDatabaseEnvVars(databaseUuid) {
|
|
19518
|
+
log.info(`Listing env vars for database ${databaseUuid}`);
|
|
19519
|
+
const result = await this.request(`/databases/${databaseUuid}/envs`);
|
|
19520
|
+
if (result.error) {
|
|
19521
|
+
log.error(`Failed to list database env vars: ${result.error}`);
|
|
19522
|
+
return err(new Error(result.error));
|
|
19523
|
+
}
|
|
19524
|
+
return ok(result.data || []);
|
|
19525
|
+
}
|
|
19526
|
+
async deleteDatabaseEnvVar(databaseUuid, key) {
|
|
19527
|
+
log.info(`Deleting environment variable ${key} from database ${databaseUuid}`);
|
|
19528
|
+
const envVarsResult = await this.listDatabaseEnvVars(databaseUuid);
|
|
19529
|
+
if (isErr(envVarsResult)) {
|
|
19530
|
+
return err(envVarsResult.error);
|
|
19531
|
+
}
|
|
19532
|
+
const envVar = envVarsResult.value.find((ev) => ev.key === key);
|
|
19533
|
+
if (!envVar) {
|
|
19534
|
+
log.error(`Environment variable ${key} not found on database ${databaseUuid}`);
|
|
19535
|
+
return err(new Error(`Environment variable ${key} not found`));
|
|
19536
|
+
}
|
|
19537
|
+
const result = await this.request(`/databases/${databaseUuid}/envs/${envVar.uuid}`, {
|
|
19538
|
+
method: "DELETE"
|
|
19539
|
+
});
|
|
19540
|
+
if (result.error) {
|
|
19541
|
+
log.error(`Failed to delete database env var: ${result.error}`);
|
|
19542
|
+
return err(new Error(result.error));
|
|
19543
|
+
}
|
|
19544
|
+
log.success(`Environment variable ${key} deleted from database ${databaseUuid}`);
|
|
19545
|
+
return ok(undefined);
|
|
19546
|
+
}
|
|
19435
19547
|
async getServerResources(serverUuid) {
|
|
19436
19548
|
log.info(`Getting resources for server ${serverUuid}`);
|
|
19437
19549
|
const result = await this.request(`/servers/${serverUuid}/resources`);
|
|
@@ -19948,6 +20060,28 @@ Please use the full UUID.`));
|
|
|
19948
20060
|
}
|
|
19949
20061
|
}
|
|
19950
20062
|
|
|
20063
|
+
// src/utils/env-parser.ts
|
|
20064
|
+
function parseEnvContent(content) {
|
|
20065
|
+
const envVars = new Map;
|
|
20066
|
+
for (const line of content.split(`
|
|
20067
|
+
`)) {
|
|
20068
|
+
const trimmed = line.trim();
|
|
20069
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
20070
|
+
continue;
|
|
20071
|
+
const eq = trimmed.indexOf("=");
|
|
20072
|
+
if (eq === -1)
|
|
20073
|
+
continue;
|
|
20074
|
+
const key = trimmed.slice(0, eq).trim();
|
|
20075
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
20076
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
20077
|
+
value = value.slice(1, -1);
|
|
20078
|
+
}
|
|
20079
|
+
if (key)
|
|
20080
|
+
envVars.set(key, value);
|
|
20081
|
+
}
|
|
20082
|
+
return envVars;
|
|
20083
|
+
}
|
|
20084
|
+
|
|
19951
20085
|
// src/sdk.ts
|
|
19952
20086
|
function unwrap(result) {
|
|
19953
20087
|
if (isErr(result))
|
|
@@ -19966,6 +20100,9 @@ class ApplicationsResource {
|
|
|
19966
20100
|
async listSummaries() {
|
|
19967
20101
|
return unwrap(await this.svc.listApplicationSummaries());
|
|
19968
20102
|
}
|
|
20103
|
+
async get(uuid2) {
|
|
20104
|
+
return unwrap(await this.svc.getApplication(uuid2));
|
|
20105
|
+
}
|
|
19969
20106
|
async resolve(query) {
|
|
19970
20107
|
return unwrap(await this.svc.resolveApplication(query));
|
|
19971
20108
|
}
|
|
@@ -20014,10 +20151,15 @@ class ApplicationsResource {
|
|
|
20014
20151
|
async syncEnv(uuid2, options = {}) {
|
|
20015
20152
|
const { filePath, dryRun = false, prune = false, onProgress } = options;
|
|
20016
20153
|
let envContent;
|
|
20154
|
+
const { readFileSync } = await import("node:fs");
|
|
20155
|
+
const { resolve, isAbsolute } = await import("node:path");
|
|
20156
|
+
const target = filePath || ".env";
|
|
20157
|
+
const absoluteTarget = isAbsolute(target) ? target : resolve(process.cwd(), target);
|
|
20017
20158
|
try {
|
|
20018
|
-
envContent =
|
|
20019
|
-
} catch {
|
|
20020
|
-
|
|
20159
|
+
envContent = readFileSync(absoluteTarget, "utf-8");
|
|
20160
|
+
} catch (err2) {
|
|
20161
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
20162
|
+
throw new Error(`Cannot read env file at ${absoluteTarget} (resolved from ${target}): ${msg}`);
|
|
20021
20163
|
}
|
|
20022
20164
|
const localVars = this.parseEnvContent(envContent);
|
|
20023
20165
|
if (localVars.size === 0) {
|
|
@@ -20075,26 +20217,7 @@ class ApplicationsResource {
|
|
|
20075
20217
|
};
|
|
20076
20218
|
}
|
|
20077
20219
|
parseEnvContent(content) {
|
|
20078
|
-
|
|
20079
|
-
const lines = content.split(`
|
|
20080
|
-
`);
|
|
20081
|
-
for (const line of lines) {
|
|
20082
|
-
const trimmedLine = line.trim();
|
|
20083
|
-
if (!trimmedLine || trimmedLine.startsWith("#")) {
|
|
20084
|
-
continue;
|
|
20085
|
-
}
|
|
20086
|
-
const eqIndex = trimmedLine.indexOf("=");
|
|
20087
|
-
if (eqIndex === -1) {
|
|
20088
|
-
continue;
|
|
20089
|
-
}
|
|
20090
|
-
const key = trimmedLine.slice(0, eqIndex).trim();
|
|
20091
|
-
let value = trimmedLine.slice(eqIndex + 1).trim();
|
|
20092
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
20093
|
-
value = value.slice(1, -1);
|
|
20094
|
-
}
|
|
20095
|
-
envVars.set(key, value);
|
|
20096
|
-
}
|
|
20097
|
-
return envVars;
|
|
20220
|
+
return parseEnvContent(content);
|
|
20098
20221
|
}
|
|
20099
20222
|
}
|
|
20100
20223
|
|
|
@@ -20142,6 +20265,15 @@ class DatabasesResource {
|
|
|
20142
20265
|
async deleteBackup(dbUuid, backupUuid) {
|
|
20143
20266
|
return unwrap(await this.svc.deleteDatabaseBackup(dbUuid, backupUuid));
|
|
20144
20267
|
}
|
|
20268
|
+
async envVars(uuid2) {
|
|
20269
|
+
return unwrap(await this.svc.listDatabaseEnvVars(uuid2));
|
|
20270
|
+
}
|
|
20271
|
+
async bulkSetEnv(uuid2, vars) {
|
|
20272
|
+
return unwrap(await this.svc.bulkUpdateDatabaseEnvVars(uuid2, vars));
|
|
20273
|
+
}
|
|
20274
|
+
async deleteEnv(uuid2, key) {
|
|
20275
|
+
return unwrap(await this.svc.deleteDatabaseEnvVar(uuid2, key));
|
|
20276
|
+
}
|
|
20145
20277
|
}
|
|
20146
20278
|
|
|
20147
20279
|
class ServicesResource {
|
|
@@ -20180,7 +20312,13 @@ class ServicesResource {
|
|
|
20180
20312
|
return unwrap(await this.svc.listServiceEnvVars(uuid2));
|
|
20181
20313
|
}
|
|
20182
20314
|
async setEnv(uuid2, data) {
|
|
20183
|
-
return unwrap(await this.svc.
|
|
20315
|
+
return unwrap(await this.svc.bulkUpdateServiceEnvVars(uuid2, [data]));
|
|
20316
|
+
}
|
|
20317
|
+
async bulkSetEnv(uuid2, vars) {
|
|
20318
|
+
return unwrap(await this.svc.bulkUpdateServiceEnvVars(uuid2, vars));
|
|
20319
|
+
}
|
|
20320
|
+
async deleteEnv(uuid2, key) {
|
|
20321
|
+
return unwrap(await this.svc.deleteServiceEnvVar(uuid2, key));
|
|
20184
20322
|
}
|
|
20185
20323
|
}
|
|
20186
20324
|
|
|
@@ -20514,11 +20652,26 @@ async function handleToolCall(name, args) {
|
|
|
20514
20652
|
startCommand: a.startCommand,
|
|
20515
20653
|
domains: a.domains,
|
|
20516
20654
|
isForceHttpsEnabled: a.isForceHttpsEnabled,
|
|
20517
|
-
isAutoDeployEnabled: a.isAutoDeployEnabled
|
|
20655
|
+
isAutoDeployEnabled: a.isAutoDeployEnabled,
|
|
20656
|
+
watchPaths: a.watchPaths
|
|
20518
20657
|
}).then((app) => ({
|
|
20519
20658
|
message: `Application ${a.uuid} updated`,
|
|
20520
20659
|
application: app
|
|
20521
20660
|
})), "Failed to update application");
|
|
20661
|
+
case "get_application":
|
|
20662
|
+
return mcpCall((s) => s.applications.get(a.uuid).then((app) => ({
|
|
20663
|
+
uuid: app.uuid,
|
|
20664
|
+
name: app.name,
|
|
20665
|
+
status: app.status,
|
|
20666
|
+
fqdn: app.fqdn,
|
|
20667
|
+
git_repository: app.git_repository,
|
|
20668
|
+
git_branch: app.git_branch,
|
|
20669
|
+
build_pack: app.build_pack,
|
|
20670
|
+
dockerfile_location: app.dockerfile_location,
|
|
20671
|
+
base_directory: app.base_directory,
|
|
20672
|
+
watch_paths: app.watch_paths,
|
|
20673
|
+
settings: app.settings
|
|
20674
|
+
})), "Failed to get application");
|
|
20522
20675
|
case "get_application_logs":
|
|
20523
20676
|
return mcpCall((s) => s.applications.logs(a.uuid, { tail: a.tail, serviceName: a.serviceName }).then((logs) => ({
|
|
20524
20677
|
timestamp: logs.timestamp,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,IAAI,EAyrC9B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA+DzE;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA+DzE;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC,CAmgBzB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .env file parser shared between the SDK (syncEnv) and the CLI (--sync stdin).
|
|
3
|
+
*
|
|
4
|
+
* Kept as a standalone exported function (not a class method) so both the
|
|
5
|
+
* SDK's ApplicationsResource and the CLI's stdin sync handler can use the
|
|
6
|
+
* same implementation without coupling to either.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Parses .env-style content into a Map.
|
|
12
|
+
*
|
|
13
|
+
* Handles:
|
|
14
|
+
* - Comments (lines starting with `#`)
|
|
15
|
+
* - Empty lines (skipped)
|
|
16
|
+
* - Quoted values (`"value"` or `'value'`)
|
|
17
|
+
* - Values containing `=` (only the first `=` is the separator)
|
|
18
|
+
* - Lines without `=` (skipped — invalid)
|
|
19
|
+
*
|
|
20
|
+
* @param content - File contents in KEY=VALUE format
|
|
21
|
+
* @returns Map of key → value (empty string for `KEY=` with no value)
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseEnvContent(content: string): Map<string, string>;
|
|
24
|
+
//# sourceMappingURL=env-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-parser.d.ts","sourceRoot":"","sources":["../../src/utils/env-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBpE"}
|
package/dist/utils/format.d.ts
CHANGED
|
@@ -28,6 +28,38 @@ export declare function formatStatus(status: string): string;
|
|
|
28
28
|
* @returns Formatted string with unit
|
|
29
29
|
*/
|
|
30
30
|
export declare function formatBytes(bytes: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Validates a port number string (single or comma-separated).
|
|
33
|
+
* Valid: "3000", "3000,3001", "80,443,8080"
|
|
34
|
+
* Invalid: "abc", "99999", "0", "-1", "3000,", ",3000"
|
|
35
|
+
*
|
|
36
|
+
* @param ports - Port string to validate
|
|
37
|
+
* @returns Object with valid flag, parsed ports, and error message
|
|
38
|
+
*/
|
|
39
|
+
export declare function validatePorts(ports: string): {
|
|
40
|
+
valid: boolean;
|
|
41
|
+
ports: number[];
|
|
42
|
+
error?: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Parses EXPOSE directives from a Dockerfile.
|
|
46
|
+
*
|
|
47
|
+
* @param dockerfilePath - Path to the Dockerfile
|
|
48
|
+
* @returns Array of exposed port numbers, empty if none found or file unreadable
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseDockerfileExpose(dockerfilePath: string): number[];
|
|
51
|
+
/**
|
|
52
|
+
* Validates a .coolify.json state object (single-app format).
|
|
53
|
+
* Checks required fields, types, and port validity.
|
|
54
|
+
*
|
|
55
|
+
* @param state - The parsed JSON object
|
|
56
|
+
* @returns Object with valid flag, warnings, and errors
|
|
57
|
+
*/
|
|
58
|
+
export declare function validateCoolifyState(state: Record<string, unknown>): {
|
|
59
|
+
valid: boolean;
|
|
60
|
+
errors: string[];
|
|
61
|
+
warnings: string[];
|
|
62
|
+
};
|
|
31
63
|
/**
|
|
32
64
|
* Formats timestamp to relative time.
|
|
33
65
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,YAAY,CAAC;AAY/B;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAOlE;AAmBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAY5D"}
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,YAAY,CAAC;AAY/B;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAOlE;AAmBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQjD;AAID;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG;IAC5C,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAqCA;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBtE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACpE,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAmFA;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAY5D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mks2508/coolify-mks-cli-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "MCP server and CLI for Coolify deployment management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"shiki": "^4.0.2"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
+
"@types/bun": "^1.3.14",
|
|
69
70
|
"@types/node": "^22.10.5",
|
|
70
71
|
"@types/prompts": "^2.4.9",
|
|
71
72
|
"rolldown": "^1.0.0-beta.58",
|