This repository has been archived on 2026-06-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
master-ai/vibn-agent-runner/dist/tools/coolify-api.js

119 lines
5.2 KiB
JavaScript

"use strict";
// =============================================================================
// Pure Coolify API — no ToolContext coupling, no registry coupling.
//
// Everything in here takes a plain { apiUrl, apiToken } config and calls
// the Coolify v1 API directly. Security guardrails (PROTECTED_COOLIFY_PROJECT,
// PROTECTED_COOLIFY_APPS, assertCoolifyDeployable) are enforced inside each
// function so every caller — in-process tool handler, MCP server, or future
// direct SDK user — gets the same protection.
//
// This is the shared core consumed by:
// - tools/coolify.ts (in-process registry used by agent-runner loop)
// - mcp/coolify-server.ts (stdio MCP server exposed to Goose/Claude/Cursor)
// =============================================================================
Object.defineProperty(exports, "__esModule", { value: true });
exports.listProjects = listProjects;
exports.listApplications = listApplications;
exports.deploy = deploy;
exports.getLogs = getLogs;
exports.listAllApps = listAllApps;
exports.getAppStatus = getAppStatus;
exports.deployApp = deployApp;
const security_1 = require("./security");
async function coolifyFetch(cfg, path, method = 'GET', body) {
const res = await fetch(`${cfg.apiUrl}/api/v1${path}`, {
method,
headers: {
'Authorization': `Bearer ${cfg.apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: body ? JSON.stringify(body) : undefined
});
if (!res.ok) {
return { error: `Coolify API error: ${res.status} ${res.statusText}` };
}
return res.json();
}
// ---------------------------------------------------------------------------
// Public API — each function corresponds 1:1 with a registered tool today
// ---------------------------------------------------------------------------
async function listProjects(cfg) {
const projects = await coolifyFetch(cfg, '/projects');
if (!Array.isArray(projects))
return projects;
return projects.filter((p) => p.uuid !== security_1.PROTECTED_COOLIFY_PROJECT);
}
async function listApplications(cfg, projectUuid) {
const all = await coolifyFetch(cfg, '/applications');
if (!Array.isArray(all))
return all;
return all.filter((a) => a.project_uuid === projectUuid);
}
async function deploy(cfg, applicationUuid) {
(0, security_1.assertCoolifyDeployable)(applicationUuid);
const apps = await coolifyFetch(cfg, '/applications');
if (Array.isArray(apps)) {
const app = apps.find((a) => a.uuid === applicationUuid);
if (app?.project_uuid === security_1.PROTECTED_COOLIFY_PROJECT) {
return {
error: `SECURITY: App "${applicationUuid}" belongs to the protected Vibn project. Agents cannot deploy platform apps.`
};
}
}
return coolifyFetch(cfg, `/applications/${applicationUuid}/deploy`, 'POST');
}
async function getLogs(cfg, applicationUuid, limit = 50) {
return coolifyFetch(cfg, `/applications/${applicationUuid}/logs?limit=${limit}`);
}
async function listAllApps(cfg) {
const apps = await coolifyFetch(cfg, '/applications');
if (!Array.isArray(apps))
return apps;
return apps
.filter((a) => a.project_uuid !== security_1.PROTECTED_COOLIFY_PROJECT && !security_1.PROTECTED_COOLIFY_APPS.has(a.uuid))
.map((a) => ({
uuid: a.uuid,
name: a.name,
fqdn: a.fqdn,
status: a.status,
repo: a.git_repository,
branch: a.git_branch
}));
}
async function getAppStatus(cfg, appName) {
const apps = await coolifyFetch(cfg, '/applications');
if (!Array.isArray(apps))
return apps;
const app = apps.find((a) => a.name?.toLowerCase() === appName.toLowerCase() || a.uuid === appName);
if (!app)
return { error: `App "${appName}" not found` };
if (security_1.PROTECTED_COOLIFY_APPS.has(app.uuid) || app.project_uuid === security_1.PROTECTED_COOLIFY_PROJECT) {
return {
error: `SECURITY: "${appName}" is a protected Vibn platform app. Status is not exposed to agents.`
};
}
const logs = await coolifyFetch(cfg, `/applications/${app.uuid}/logs?limit=20`);
return { name: app.name, uuid: app.uuid, status: app.status, fqdn: app.fqdn, logs };
}
async function deployApp(cfg, appName) {
const apps = await coolifyFetch(cfg, '/applications');
if (!Array.isArray(apps))
return apps;
const app = apps.find((a) => a.name?.toLowerCase() === appName.toLowerCase() || a.uuid === appName);
if (!app)
return { error: `App "${appName}" not found` };
if (security_1.PROTECTED_COOLIFY_APPS.has(app.uuid) || app.project_uuid === security_1.PROTECTED_COOLIFY_PROJECT) {
return {
error: `SECURITY: "${appName}" is a protected Vibn platform application. ` +
`Agents can only deploy user project apps, not platform infrastructure.`
};
}
// Non-project-prefixed deploy endpoint — older Coolify entry point still in use
const result = await fetch(`${cfg.apiUrl}/api/v1/deploy?uuid=${app.uuid}&force=false`, {
headers: { 'Authorization': `Bearer ${cfg.apiToken}` }
});
return result.json();
}