helipod-mcp 0.5.8 → 0.5.10
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/http.js +87 -37
- package/dist/index.js +87 -37
- package/dist/stdio.js +87 -37
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -35582,10 +35582,12 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
35582
35582
|
class HelipodError extends Error {
|
|
35583
35583
|
status;
|
|
35584
35584
|
code;
|
|
35585
|
-
|
|
35585
|
+
details;
|
|
35586
|
+
constructor(status, code, message, details) {
|
|
35586
35587
|
super(message);
|
|
35587
35588
|
this.status = status;
|
|
35588
35589
|
this.code = code;
|
|
35590
|
+
this.details = details;
|
|
35589
35591
|
this.name = "HelipodError";
|
|
35590
35592
|
}
|
|
35591
35593
|
}
|
|
@@ -35681,7 +35683,8 @@ class HelipodClient {
|
|
|
35681
35683
|
if (!res.ok || json2?.success === false) {
|
|
35682
35684
|
const retry = res.headers.get("retry-after");
|
|
35683
35685
|
const msg = json2?.error ?? (text.slice(0, 300) || res.statusText);
|
|
35684
|
-
|
|
35686
|
+
const details = json2?.details && typeof json2.details === "object" && !Array.isArray(json2.details) ? json2.details : undefined;
|
|
35687
|
+
throw new HelipodError(res.status, json2?.code, retry ? `${msg} (retry after ${retry}s)` : String(msg), details);
|
|
35685
35688
|
}
|
|
35686
35689
|
return json2 && "data" in json2 ? json2.data : json2;
|
|
35687
35690
|
}
|
|
@@ -35713,7 +35716,7 @@ function register(server, api2, defs) {
|
|
|
35713
35716
|
const err = e instanceof HelipodError ? e : new HelipodError(0, "CLIENT_ERROR", String(e?.message ?? e));
|
|
35714
35717
|
return {
|
|
35715
35718
|
isError: true,
|
|
35716
|
-
content: [{ type: "text", text: JSON.stringify({ status: err.status, code: err.code ?? null, error: err.message }, null, 2) }]
|
|
35719
|
+
content: [{ type: "text", text: JSON.stringify({ status: err.status, code: err.code ?? null, error: err.message, ...err.details ? { details: err.details } : {} }, null, 2) }]
|
|
35717
35720
|
};
|
|
35718
35721
|
}
|
|
35719
35722
|
});
|
|
@@ -35847,18 +35850,48 @@ var containerTools = [
|
|
|
35847
35850
|
input: { serviceId: id("Service") },
|
|
35848
35851
|
run: (a, api2) => api2.api("GET", `${C}/services/${a.serviceId}`)
|
|
35849
35852
|
}),
|
|
35853
|
+
defineTool({
|
|
35854
|
+
name: "get_git_connections",
|
|
35855
|
+
title: "Git connections",
|
|
35856
|
+
kind: "read",
|
|
35857
|
+
description: "Whether the user connected GitHub (sign-in + the Helipod GitHub App, with the accounts it is installed on) and GitLab, plus connectUrl: the Helipod page where the user connects them. Check this before deploying from a private repo. Connecting needs the user in a browser: give them connectUrl, never try to connect yourself.",
|
|
35858
|
+
input: {},
|
|
35859
|
+
run: (_a3, api2) => api2.api("GET", `${C}/git/connections`)
|
|
35860
|
+
}),
|
|
35861
|
+
defineTool({
|
|
35862
|
+
name: "list_git_repos",
|
|
35863
|
+
title: "List Git repositories",
|
|
35864
|
+
kind: "read",
|
|
35865
|
+
description: "Repositories the user's connected GitHub App installations (host github, default) or GitLab account (host gitlab) can reach: fullName, url, private, defaultBranch, newest first. Pass one url to create_service as repo. Not connected: 409 with details.connectUrl for the user.",
|
|
35866
|
+
input: {
|
|
35867
|
+
host: exports_external.enum(["github", "gitlab"]).optional().describe("github (default) or gitlab"),
|
|
35868
|
+
installationId: exports_external.number().int().positive().optional().describe("Only this GitHub installation (id from get_git_connections)"),
|
|
35869
|
+
search: exports_external.string().max(200).optional().describe("Filter by part of owner/name"),
|
|
35870
|
+
limit: exports_external.number().int().min(1).max(100).optional().describe("Default 50"),
|
|
35871
|
+
offset: exports_external.number().int().min(0).optional()
|
|
35872
|
+
},
|
|
35873
|
+
run: (a, api2) => api2.api("GET", `${C}/git/repos`, {
|
|
35874
|
+
query: {
|
|
35875
|
+
host: a.host,
|
|
35876
|
+
installationId: a.installationId !== undefined ? String(a.installationId) : undefined,
|
|
35877
|
+
search: a.search,
|
|
35878
|
+
limit: a.limit !== undefined ? String(a.limit) : undefined,
|
|
35879
|
+
offset: a.offset !== undefined ? String(a.offset) : undefined
|
|
35880
|
+
}
|
|
35881
|
+
})
|
|
35882
|
+
}),
|
|
35850
35883
|
defineTool({
|
|
35851
35884
|
name: "create_service",
|
|
35852
35885
|
title: "Create service",
|
|
35853
35886
|
kind: "write",
|
|
35854
|
-
description: "Create a service from a container image, a
|
|
35887
|
+
description: "Create a service from a container image, a Git repository or an inline Dockerfile, and (unless deploy=false) start its first deploy. Private GitHub / GitLab repos work once connected (get_git_connections, list_git_repos); such services also redeploy on every push. A private repo that is not connected is refused (409 GITHUB_NOT_CONNECTED / GITLAB_NOT_CONNECTED / REPO_NOT_ACCESSIBLE, nothing created): give the user details.connectUrl and retry after they connect. COSTS MONEY once deployed (billed daily from the wallet): call with dryRun=true first, show the dailyCost to the user and get their OK.",
|
|
35855
35888
|
input: {
|
|
35856
35889
|
environmentId: id("Environment"),
|
|
35857
35890
|
name: exports_external.string().regex(/^[A-Za-z][A-Za-z0-9_-]{0,39}$/).describe("Service name (letters, digits, _ -; starts with a letter). Also used in references like ${{name.KEY}}"),
|
|
35858
35891
|
image: exports_external.string().optional().describe("Container image, e.g. nginx:alpine or ghcr.io/acme/app:1.2"),
|
|
35859
35892
|
registryUsername: exports_external.string().optional().describe("Private registry user (with registryPassword)"),
|
|
35860
35893
|
registryPassword: exports_external.string().optional().describe("Private registry password or token"),
|
|
35861
|
-
repo: exports_external.string().optional().describe("
|
|
35894
|
+
repo: exports_external.string().optional().describe("Git repository: https URL or owner/name for GitHub (instead of image). Private repos need a connected GitHub / GitLab (list_git_repos)"),
|
|
35862
35895
|
branch: exports_external.string().optional().describe("Git branch (default main)"),
|
|
35863
35896
|
rootDirectory: exports_external.string().optional().describe("Monorepo: folder to build, e.g. apps/web"),
|
|
35864
35897
|
dockerfile: exports_external.string().optional().describe("Inline Dockerfile content (instead of image/repo)"),
|
|
@@ -36248,6 +36281,10 @@ var period = exports_external.enum(["monthly", "3month", "6month", "yearly"]);
|
|
|
36248
36281
|
var pointId = exports_external.string().describe("Restore point id (from list_vps_restore_points)");
|
|
36249
36282
|
var backupPath = exports_external.string().max(1024).describe("Absolute path inside the backup, e.g. /etc/nginx or /var/www/index.html");
|
|
36250
36283
|
var migrationId = exports_external.string().describe("Migration id (from list_vps_migrations)");
|
|
36284
|
+
var dryRun2 = exports_external.boolean().optional().describe("true = return the price (IDR) and the wallet balance after it; nothing is charged or changed");
|
|
36285
|
+
var idempotencyKey = exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real call. Generated when omitted; pass the same value when retrying so it is never charged twice");
|
|
36286
|
+
var DRY = "dryRun=true returns the price and walletBalanceAfter without charging or changing anything.";
|
|
36287
|
+
var dryQuery = (d) => ({ dryRun: d ? "true" : undefined });
|
|
36251
36288
|
var vpsTools = [
|
|
36252
36289
|
defineTool({
|
|
36253
36290
|
name: "list_vps_plans",
|
|
@@ -36277,7 +36314,7 @@ var vpsTools = [
|
|
|
36277
36314
|
name: "create_vps",
|
|
36278
36315
|
title: "Create VPS",
|
|
36279
36316
|
kind: "write",
|
|
36280
|
-
description:
|
|
36317
|
+
description: `Order a server. COSTS MONEY right away (the whole billing period is charged from the wallet; refunded if provisioning fails). Call with dryRun=true first, show the price and the wallet after it, and get the user's explicit OK. ${DRY} autoRenew=false creates it with auto-renew off (renew it with renew_vps). Provisioning takes a few minutes: poll get_vps.`,
|
|
36281
36318
|
input: {
|
|
36282
36319
|
projectId: exports_external.string().uuid(),
|
|
36283
36320
|
planId: exports_external.string(),
|
|
@@ -36285,9 +36322,12 @@ var vpsTools = [
|
|
|
36285
36322
|
osType: exports_external.string().describe("From the plan's osTemplates, e.g. ubuntu"),
|
|
36286
36323
|
osVersion: exports_external.string().describe("e.g. 24.04"),
|
|
36287
36324
|
rootPassword: password,
|
|
36288
|
-
billingPeriod: period.optional().describe("Default monthly")
|
|
36325
|
+
billingPeriod: period.optional().describe("Default monthly"),
|
|
36326
|
+
autoRenew: exports_external.boolean().optional().describe("false = no automatic renewal from the wallet (default true)"),
|
|
36327
|
+
dryRun: dryRun2,
|
|
36328
|
+
idempotencyKey
|
|
36289
36329
|
},
|
|
36290
|
-
run: (
|
|
36330
|
+
run: ({ dryRun: dryRun3, idempotencyKey: idempotencyKey2, ...body }, api2) => api2.api("POST", "/vps", { body, query: dryQuery(dryRun3), idempotencyKey: purchaseKey(dryRun3, idempotencyKey2) })
|
|
36291
36331
|
}),
|
|
36292
36332
|
defineTool({
|
|
36293
36333
|
name: "vps_power",
|
|
@@ -36341,17 +36381,17 @@ var vpsTools = [
|
|
|
36341
36381
|
name: "renew_vps",
|
|
36342
36382
|
title: "Renew VPS",
|
|
36343
36383
|
kind: "write",
|
|
36344
|
-
description:
|
|
36345
|
-
input: { vpsId, billingPeriod: period },
|
|
36346
|
-
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/renew`, { body: { billingPeriod: a.billingPeriod } })
|
|
36384
|
+
description: `Extend a server's paid period. COSTS MONEY: call with dryRun=true first, show the price and the wallet after it, and get the user's OK. ${DRY}`,
|
|
36385
|
+
input: { vpsId, billingPeriod: period, dryRun: dryRun2, idempotencyKey },
|
|
36386
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/renew`, { body: { billingPeriod: a.billingPeriod }, query: dryQuery(a.dryRun), idempotencyKey: purchaseKey(a.dryRun, a.idempotencyKey) })
|
|
36347
36387
|
}),
|
|
36348
36388
|
defineTool({
|
|
36349
36389
|
name: "upgrade_vps",
|
|
36350
36390
|
title: "Upgrade VPS plan",
|
|
36351
36391
|
kind: "write",
|
|
36352
|
-
description:
|
|
36353
|
-
input: { vpsId, planId: exports_external.string() },
|
|
36354
|
-
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/upgrade`, { body: { planId: a.planId } })
|
|
36392
|
+
description: `Move a server to a larger plan in the same family and region. COSTS MONEY (the difference for the days left) and restarts the server. planId must be one listed by get_vps_upgrade_options. Call with dryRun=true first and get the user's OK. ${DRY} Servers with providerCode 2 only.`,
|
|
36393
|
+
input: { vpsId, planId: exports_external.string(), dryRun: dryRun2, idempotencyKey },
|
|
36394
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/upgrade`, { body: { planId: a.planId }, query: dryQuery(a.dryRun), idempotencyKey: purchaseKey(a.dryRun, a.idempotencyKey) })
|
|
36355
36395
|
}),
|
|
36356
36396
|
defineTool({
|
|
36357
36397
|
name: "get_vps_upgrade_options",
|
|
@@ -36378,11 +36418,20 @@ var vpsTools = [
|
|
|
36378
36418
|
input: { vpsId, range: exports_external.enum(["1h", "6h", "24h", "7d", "30d"]).optional() },
|
|
36379
36419
|
run: (a, api2) => api2.api("GET", `/vps/${a.vpsId}/metrics`, { query: { range: a.range } })
|
|
36380
36420
|
}),
|
|
36421
|
+
defineTool({
|
|
36422
|
+
name: "set_vps_auto_renew",
|
|
36423
|
+
title: "Set VPS auto-renew",
|
|
36424
|
+
kind: "write",
|
|
36425
|
+
idempotent: true,
|
|
36426
|
+
description: "Turn auto-renew on or off (sets the value, safe to repeat). With it off, the server is only renewed by renew_vps and expires otherwise.",
|
|
36427
|
+
input: { vpsId, autoRenew: exports_external.boolean() },
|
|
36428
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/auto-renew`, { body: { autoRenew: a.autoRenew } })
|
|
36429
|
+
}),
|
|
36381
36430
|
defineTool({
|
|
36382
36431
|
name: "toggle_vps_auto_renew",
|
|
36383
36432
|
title: "Toggle VPS auto-renew",
|
|
36384
36433
|
kind: "write",
|
|
36385
|
-
description: "Flip auto-renew
|
|
36434
|
+
description: "Flip auto-renew to the other value; the response gives the new one. Prefer set_vps_auto_renew to reach a given state.",
|
|
36386
36435
|
input: { vpsId },
|
|
36387
36436
|
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/auto-renew-toggle`)
|
|
36388
36437
|
}),
|
|
@@ -36711,8 +36760,8 @@ var vpsTools = [
|
|
|
36711
36760
|
// src/tools/domains.ts
|
|
36712
36761
|
var domainId = exports_external.number().int().positive().describe("Domain id (number, from list_my_domains)");
|
|
36713
36762
|
var hostId = exports_external.number().int().positive().describe("Child nameserver id (from list_child_nameservers)");
|
|
36714
|
-
var
|
|
36715
|
-
var
|
|
36763
|
+
var dryRun3 = exports_external.boolean().optional().describe("true = return the exact price (IDR, VAT included) and the wallet balance after it; nothing is charged or registered");
|
|
36764
|
+
var DRY2 = "dryRun=true returns the price and walletBalanceAfter without charging or changing anything.";
|
|
36716
36765
|
var record3 = exports_external.object({
|
|
36717
36766
|
name: exports_external.string().describe('"@" for the domain itself, or the part before the domain, e.g. "www" or "_dmarc.mail". A full name like "www.example.com" is accepted and stored as "www"'),
|
|
36718
36767
|
type: exports_external.enum(["A", "AAAA", "MX", "MXE", "CNAME", "SPF", "TXT"]),
|
|
@@ -36788,12 +36837,12 @@ var domainTools = [
|
|
|
36788
36837
|
name: "register_domain",
|
|
36789
36838
|
title: "Register domain",
|
|
36790
36839
|
kind: "write",
|
|
36791
|
-
description: `Register a domain for 1 year. COSTS MONEY from the wallet. Check search_domain, and that the owner details are complete (check_registrant / update_registrant). ${
|
|
36840
|
+
description: `Register a domain for 1 year. COSTS MONEY from the wallet. Check search_domain, and that the owner details are complete (check_registrant / update_registrant). ${DRY2} The dry run includes WHOIS privacy when whoisProtection is true.`,
|
|
36792
36841
|
input: {
|
|
36793
36842
|
name: exports_external.string().describe("Full domain, e.g. tokosaya.id"),
|
|
36794
36843
|
nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(),
|
|
36795
36844
|
whoisProtection: exports_external.boolean().optional(),
|
|
36796
|
-
dryRun:
|
|
36845
|
+
dryRun: dryRun3
|
|
36797
36846
|
},
|
|
36798
36847
|
run: (a, api2) => api2.api("POST", "/domains/register", { body: { name: a.name, period: 1, nameservers: a.nameservers, whoisProtection: a.whoisProtection }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
36799
36848
|
}),
|
|
@@ -36801,16 +36850,16 @@ var domainTools = [
|
|
|
36801
36850
|
name: "transfer_domain",
|
|
36802
36851
|
title: "Transfer domain in",
|
|
36803
36852
|
kind: "write",
|
|
36804
|
-
description: `Transfer a domain from another registrar (adds 1 year). COSTS MONEY from the wallet. Needs the domain's auth code. ${
|
|
36805
|
-
input: { name: exports_external.string(), authCode: exports_external.string(), nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(), dryRun:
|
|
36853
|
+
description: `Transfer a domain from another registrar (adds 1 year). COSTS MONEY from the wallet. Needs the domain's auth code. ${DRY2}`,
|
|
36854
|
+
input: { name: exports_external.string(), authCode: exports_external.string(), nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(), dryRun: dryRun3 },
|
|
36806
36855
|
run: (a, api2) => api2.api("POST", "/domains/transfer", { body: { name: a.name, authCode: a.authCode, period: 1, nameservers: a.nameservers }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
36807
36856
|
}),
|
|
36808
36857
|
defineTool({
|
|
36809
36858
|
name: "renew_domain",
|
|
36810
36859
|
title: "Renew domain",
|
|
36811
36860
|
kind: "write",
|
|
36812
|
-
description: `Renew a domain for 1 year (plus WHOIS privacy when it is on). COSTS MONEY from the wallet. ${
|
|
36813
|
-
input: { domainId, dryRun:
|
|
36861
|
+
description: `Renew a domain for 1 year (plus WHOIS privacy when it is on). COSTS MONEY from the wallet. ${DRY2}`,
|
|
36862
|
+
input: { domainId, dryRun: dryRun3 },
|
|
36814
36863
|
run: (a, api2) => api2.api("POST", `/domains/${a.domainId}/renew`, { body: { period: 1 }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
36815
36864
|
}),
|
|
36816
36865
|
defineTool({
|
|
@@ -36973,7 +37022,7 @@ var message = exports_external.object({
|
|
|
36973
37022
|
variables: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
36974
37023
|
idempotencyKey: exports_external.string().max(128).optional()
|
|
36975
37024
|
});
|
|
36976
|
-
var
|
|
37025
|
+
var dryRun4 = exports_external.boolean().optional().describe("true = return the price (IDR) and the wallet balance after it; nothing is charged or changed");
|
|
36977
37026
|
var idem2 = exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real purchase. Generated when omitted; pass the same value when retrying so it is never charged twice");
|
|
36978
37027
|
var MONEY = "COSTS MONEY from the wallet. dryRun=true returns the charge (IDR) and walletBalanceAfter without charging or changing anything.";
|
|
36979
37028
|
var planCode = exports_external.string().min(1).max(50).describe("Plan code from list_email_plans");
|
|
@@ -37009,7 +37058,7 @@ var emailTools = [
|
|
|
37009
37058
|
title: "Buy email plan",
|
|
37010
37059
|
kind: "write",
|
|
37011
37060
|
description: `Start an email plan for the project (a free plan activates without charge). Works for a project with no email yet: the real call also sets email up (result.setup). ${MONEY} The dry run's mode says purchase, activate_free or already_active.`,
|
|
37012
|
-
input: { projectId, planCode, months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional().describe("Billing cycle, default 1"), dryRun:
|
|
37061
|
+
input: { projectId, planCode, months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional().describe("Billing cycle, default 1"), dryRun: dryRun4, idempotencyKey: idem2 },
|
|
37013
37062
|
run: (a, api2) => api2.email("POST", "/plan", {
|
|
37014
37063
|
project: a.projectId,
|
|
37015
37064
|
body: { planCode: a.planCode, months: a.months },
|
|
@@ -37022,7 +37071,7 @@ var emailTools = [
|
|
|
37022
37071
|
title: "Renew email plan",
|
|
37023
37072
|
kind: "write",
|
|
37024
37073
|
description: `Renew the project's ended or expiring email plan (409 PLAN_ACTIVE while one is still running and cannot be extended). Repeats the last plan and cycle unless planCode / months are given. ${MONEY}`,
|
|
37025
|
-
input: { projectId, planCode: planCode.optional(), months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional(), dryRun:
|
|
37074
|
+
input: { projectId, planCode: planCode.optional(), months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional(), dryRun: dryRun4, idempotencyKey: idem2 },
|
|
37026
37075
|
run: (a, api2) => api2.email("POST", "/plan/renew", {
|
|
37027
37076
|
project: a.projectId,
|
|
37028
37077
|
body: { planCode: a.planCode, months: a.months },
|
|
@@ -37035,7 +37084,7 @@ var emailTools = [
|
|
|
37035
37084
|
title: "Change email plan",
|
|
37036
37085
|
kind: "write",
|
|
37037
37086
|
description: `Move the active email plan to another plan. An upgrade applies now and charges the prorated difference to the same end date; a downgrade is scheduled for the next cycle (no refund). ${MONEY}`,
|
|
37038
|
-
input: { projectId, planCode, dryRun:
|
|
37087
|
+
input: { projectId, planCode, dryRun: dryRun4, idempotencyKey: idem2 },
|
|
37039
37088
|
run: (a, api2) => api2.email("POST", "/plan/change", {
|
|
37040
37089
|
project: a.projectId,
|
|
37041
37090
|
body: { planCode: a.planCode },
|
|
@@ -37052,7 +37101,7 @@ var emailTools = [
|
|
|
37052
37101
|
projectId,
|
|
37053
37102
|
extraMailboxes: exports_external.number().int().min(0).max(50).describe("Total extra mailboxes wanted (0-50)"),
|
|
37054
37103
|
extraStorageGb: exports_external.number().int().min(0).max(1000).describe("Total extra inbox storage in GB (0-1000)"),
|
|
37055
|
-
dryRun:
|
|
37104
|
+
dryRun: dryRun4,
|
|
37056
37105
|
idempotencyKey: idem2
|
|
37057
37106
|
},
|
|
37058
37107
|
run: (a, api2) => api2.email("POST", "/plan/addons", {
|
|
@@ -37622,7 +37671,7 @@ var emailTools = [
|
|
|
37622
37671
|
// src/tools/databases.ts
|
|
37623
37672
|
var databaseId = exports_external.string().uuid().describe("Database id (from list_databases)");
|
|
37624
37673
|
var environmentId = exports_external.string().uuid().describe("Environment id (from list_projects). Omit for the primary (production) branch.");
|
|
37625
|
-
var
|
|
37674
|
+
var dryRun5 = exports_external.boolean().optional().describe("true = only check and show the result or price; nothing changes");
|
|
37626
37675
|
var databaseTools = [
|
|
37627
37676
|
defineTool({
|
|
37628
37677
|
name: "list_database_plans",
|
|
@@ -37716,7 +37765,7 @@ var databaseTools = [
|
|
|
37716
37765
|
minCu: exports_external.number().min(0.25).max(10).optional(),
|
|
37717
37766
|
maxCu: exports_external.number().min(0.25).max(10).optional(),
|
|
37718
37767
|
suspendTimeoutSeconds: exports_external.number().int().min(0).max(604800).optional().describe("0 = never suspend, or 60-604800"),
|
|
37719
|
-
dryRun:
|
|
37768
|
+
dryRun: dryRun5
|
|
37720
37769
|
},
|
|
37721
37770
|
run: (a, api2) => api2.api("PATCH", `/databases/${a.databaseId}/settings`, {
|
|
37722
37771
|
body: { minCu: a.minCu, maxCu: a.maxCu, suspendTimeoutSeconds: a.suspendTimeoutSeconds },
|
|
@@ -37728,7 +37777,7 @@ var databaseTools = [
|
|
|
37728
37777
|
title: "Upgrade database plan / top up",
|
|
37729
37778
|
kind: "write",
|
|
37730
37779
|
description: "Buy a paid plan or top up credits. COSTS MONEY from the wallet: call with dryRun first, show price and wallet balance after, and get the user's explicit OK.",
|
|
37731
|
-
input: { databaseId, plan: exports_external.string().describe("Plan code (e.g. STARTER) or id from list_database_plans"), dryRun:
|
|
37780
|
+
input: { databaseId, plan: exports_external.string().describe("Plan code (e.g. STARTER) or id from list_database_plans"), dryRun: dryRun5, idempotencyKey: exports_external.string().max(128).optional() },
|
|
37732
37781
|
run: (a, api2) => api2.api("POST", `/databases/${a.databaseId}/upgrade`, { body: { plan: a.plan }, query: { dryRun: a.dryRun ? "true" : undefined }, idempotencyKey: a.idempotencyKey })
|
|
37733
37782
|
}),
|
|
37734
37783
|
defineTool({
|
|
@@ -37986,7 +38035,7 @@ var accountTools = [
|
|
|
37986
38035
|
var projectId2 = exports_external.string().uuid().optional().describe("Limit to one project (a project key is always limited to its own)");
|
|
37987
38036
|
var keyId = exports_external.string().uuid().optional().describe("Limit to one AI key (id from list_ai_keys)");
|
|
37988
38037
|
var model = exports_external.string().max(100).optional().describe("Limit to one model id");
|
|
37989
|
-
var
|
|
38038
|
+
var dryRun6 = exports_external.boolean().optional().describe("true = only check and show the result; nothing is charged or changed");
|
|
37990
38039
|
var ACCOUNT_KEY2 = "Needs a whole-account key (a key limited to one project gets 403 ACCOUNT_KEY_REQUIRED).";
|
|
37991
38040
|
var imageProject = exports_external.string().uuid().optional().describe("Project the images belong to (required with a whole-account key; a project key uses its own)");
|
|
37992
38041
|
var INLINE_MAX_BYTES = 1500000;
|
|
@@ -38071,7 +38120,7 @@ var aiTools = [
|
|
|
38071
38120
|
n: exports_external.number().int().min(1).max(10).optional().describe("Images in this request (up to the model's maxN; default 1)"),
|
|
38072
38121
|
images: exports_external.array(exports_external.string().url().startsWith("https://")).max(10).optional().describe("Reference images as https:// links (only models with refImages > 0)"),
|
|
38073
38122
|
projectId: imageProject,
|
|
38074
|
-
dryRun:
|
|
38123
|
+
dryRun: dryRun6,
|
|
38075
38124
|
wait: exports_external.number().int().min(0).max(55).optional().describe("Seconds to wait for the result (default 50; 0 = return the id at once)"),
|
|
38076
38125
|
idempotencyKey: exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real request. Generated when omitted; pass the same value when retrying so it is never charged twice")
|
|
38077
38126
|
},
|
|
@@ -38121,7 +38170,7 @@ var aiTools = [
|
|
|
38121
38170
|
input: {
|
|
38122
38171
|
packId: exports_external.string().min(1).max(64).optional(),
|
|
38123
38172
|
amount: exports_external.number().min(1).max(1e9).optional().describe("IDR"),
|
|
38124
|
-
dryRun:
|
|
38173
|
+
dryRun: dryRun6,
|
|
38125
38174
|
idempotencyKey: exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real top-up. Generated when omitted; pass the same value when retrying so it is never charged twice")
|
|
38126
38175
|
},
|
|
38127
38176
|
run: (a, api2) => {
|
|
@@ -38144,7 +38193,7 @@ var aiTools = [
|
|
|
38144
38193
|
enabled: exports_external.boolean(),
|
|
38145
38194
|
threshold: exports_external.number().min(1).optional().describe("Top up when the AI balance is below this (IDR)"),
|
|
38146
38195
|
amount: exports_external.number().min(1).optional().describe("How much to top up each time (IDR)"),
|
|
38147
|
-
dryRun:
|
|
38196
|
+
dryRun: dryRun6
|
|
38148
38197
|
},
|
|
38149
38198
|
run: (a, api2) => api2.api("PUT", "/ai/auto-topup", {
|
|
38150
38199
|
body: { enabled: a.enabled, threshold: a.threshold, amount: a.amount },
|
|
@@ -38180,7 +38229,7 @@ var generalTools = [
|
|
|
38180
38229
|
];
|
|
38181
38230
|
|
|
38182
38231
|
// src/server.ts
|
|
38183
|
-
var VERSION = "0.5.
|
|
38232
|
+
var VERSION = "0.5.10";
|
|
38184
38233
|
var INSTRUCTIONS = `Helipod is a cloud platform (Indonesia): containers, managed Postgres databases, VPS, domains, email and an AI gateway, billed from a prepaid wallet in Rupiah.
|
|
38185
38234
|
- Start with list_projects to find projects and environment ids. Account tools (get_wallet, invoices, statements, notifications, get_project_activity, support tickets) cover the account; AI tools (list_ai_models, get_ai_overview, get_ai_usage, AI keys, top-ups, generate_ai_image) cover the AI gateway.
|
|
38186
38235
|
- Anything that costs money (create/deploy/scale services, resize volumes, upgrade a database plan, create/renew/upgrade VPS, VPS backups, register/renew/transfer domains, email plans and inbox add-ons, AI top-ups and auto top-up, generating images): call it with dryRun=true first (or the price lookup when it has no dry run), tell the user the cost in IDR and the wallet balance after, and wait for an explicit yes before the real call. Never treat silence or an earlier general OK as a yes.
|
|
@@ -38190,9 +38239,10 @@ var INSTRUCTIONS = `Helipod is a cloud platform (Indonesia): containers, managed
|
|
|
38190
38239
|
- Databases: get_database_connection returns a password; put it in a secret variable (DATABASE_URL) instead of code or chat.
|
|
38191
38240
|
- Migrate (free): create_vps_import returns a one-time command for the USER to run as root on their old server (never run it yourself); before the first restore_vps_import, show fetchedIp and ask the user to confirm it is their server.
|
|
38192
38241
|
- Images from generate_ai_image are deleted after 7 days: tell the user and have them download the ones they keep.
|
|
38242
|
+
- Deploying from Git: public repos need nothing. For a private repo check get_git_connections / list_git_repos first; when GitHub or GitLab is not connected (or a call returns 409 GITHUB_NOT_CONNECTED / GITLAB_NOT_CONNECTED / REPO_NOT_ACCESSIBLE), give the user details.connectUrl to open in their browser and try again after they confirm. Never ask for a GitHub token.
|
|
38193
38243
|
- Deploys and VPS actions run in the background: poll get_deployment / get_vps until they settle; on a failed deploy read get_deployment_logs.
|
|
38194
38244
|
- Never print secrets (passwords, secret variable values, secret files) unless the user asks for them. Domain owner details are personal data: use only what the user gave.
|
|
38195
|
-
- Errors come back as { status, code, error }: 401/403 means the key lacks access (keys choose products and projects in Settings → API keys; wallet, invoices, tickets and AI money need a whole-account key: with a sign-in, reconnect and choose Whole account), 402 means plan limit or low balance.
|
|
38245
|
+
- Errors come back as { status, code, error, details? }: 401/403 means the key lacks access (keys choose products and projects in Settings → API keys; wallet, invoices, tickets and AI money need a whole-account key: with a sign-in, reconnect and choose Whole account), 402 means plan limit or low balance.
|
|
38196
38246
|
Docs: https://docs.helipod.io`;
|
|
38197
38247
|
var ALL_TOOLS = [...containerTools, ...databaseTools, ...vpsTools, ...domainTools, ...emailTools, ...accountTools, ...aiTools, ...generalTools];
|
|
38198
38248
|
function createHelipodServer(config2) {
|
package/dist/index.js
CHANGED
|
@@ -34727,10 +34727,12 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
34727
34727
|
class HelipodError extends Error {
|
|
34728
34728
|
status;
|
|
34729
34729
|
code;
|
|
34730
|
-
|
|
34730
|
+
details;
|
|
34731
|
+
constructor(status, code, message, details) {
|
|
34731
34732
|
super(message);
|
|
34732
34733
|
this.status = status;
|
|
34733
34734
|
this.code = code;
|
|
34735
|
+
this.details = details;
|
|
34734
34736
|
this.name = "HelipodError";
|
|
34735
34737
|
}
|
|
34736
34738
|
}
|
|
@@ -34826,7 +34828,8 @@ class HelipodClient {
|
|
|
34826
34828
|
if (!res.ok || json2?.success === false) {
|
|
34827
34829
|
const retry = res.headers.get("retry-after");
|
|
34828
34830
|
const msg = json2?.error ?? (text.slice(0, 300) || res.statusText);
|
|
34829
|
-
|
|
34831
|
+
const details = json2?.details && typeof json2.details === "object" && !Array.isArray(json2.details) ? json2.details : undefined;
|
|
34832
|
+
throw new HelipodError(res.status, json2?.code, retry ? `${msg} (retry after ${retry}s)` : String(msg), details);
|
|
34830
34833
|
}
|
|
34831
34834
|
return json2 && "data" in json2 ? json2.data : json2;
|
|
34832
34835
|
}
|
|
@@ -34858,7 +34861,7 @@ function register(server, api2, defs) {
|
|
|
34858
34861
|
const err = e instanceof HelipodError ? e : new HelipodError(0, "CLIENT_ERROR", String(e?.message ?? e));
|
|
34859
34862
|
return {
|
|
34860
34863
|
isError: true,
|
|
34861
|
-
content: [{ type: "text", text: JSON.stringify({ status: err.status, code: err.code ?? null, error: err.message }, null, 2) }]
|
|
34864
|
+
content: [{ type: "text", text: JSON.stringify({ status: err.status, code: err.code ?? null, error: err.message, ...err.details ? { details: err.details } : {} }, null, 2) }]
|
|
34862
34865
|
};
|
|
34863
34866
|
}
|
|
34864
34867
|
});
|
|
@@ -34992,18 +34995,48 @@ var containerTools = [
|
|
|
34992
34995
|
input: { serviceId: id("Service") },
|
|
34993
34996
|
run: (a, api2) => api2.api("GET", `${C}/services/${a.serviceId}`)
|
|
34994
34997
|
}),
|
|
34998
|
+
defineTool({
|
|
34999
|
+
name: "get_git_connections",
|
|
35000
|
+
title: "Git connections",
|
|
35001
|
+
kind: "read",
|
|
35002
|
+
description: "Whether the user connected GitHub (sign-in + the Helipod GitHub App, with the accounts it is installed on) and GitLab, plus connectUrl: the Helipod page where the user connects them. Check this before deploying from a private repo. Connecting needs the user in a browser: give them connectUrl, never try to connect yourself.",
|
|
35003
|
+
input: {},
|
|
35004
|
+
run: (_a3, api2) => api2.api("GET", `${C}/git/connections`)
|
|
35005
|
+
}),
|
|
35006
|
+
defineTool({
|
|
35007
|
+
name: "list_git_repos",
|
|
35008
|
+
title: "List Git repositories",
|
|
35009
|
+
kind: "read",
|
|
35010
|
+
description: "Repositories the user's connected GitHub App installations (host github, default) or GitLab account (host gitlab) can reach: fullName, url, private, defaultBranch, newest first. Pass one url to create_service as repo. Not connected: 409 with details.connectUrl for the user.",
|
|
35011
|
+
input: {
|
|
35012
|
+
host: exports_external.enum(["github", "gitlab"]).optional().describe("github (default) or gitlab"),
|
|
35013
|
+
installationId: exports_external.number().int().positive().optional().describe("Only this GitHub installation (id from get_git_connections)"),
|
|
35014
|
+
search: exports_external.string().max(200).optional().describe("Filter by part of owner/name"),
|
|
35015
|
+
limit: exports_external.number().int().min(1).max(100).optional().describe("Default 50"),
|
|
35016
|
+
offset: exports_external.number().int().min(0).optional()
|
|
35017
|
+
},
|
|
35018
|
+
run: (a, api2) => api2.api("GET", `${C}/git/repos`, {
|
|
35019
|
+
query: {
|
|
35020
|
+
host: a.host,
|
|
35021
|
+
installationId: a.installationId !== undefined ? String(a.installationId) : undefined,
|
|
35022
|
+
search: a.search,
|
|
35023
|
+
limit: a.limit !== undefined ? String(a.limit) : undefined,
|
|
35024
|
+
offset: a.offset !== undefined ? String(a.offset) : undefined
|
|
35025
|
+
}
|
|
35026
|
+
})
|
|
35027
|
+
}),
|
|
34995
35028
|
defineTool({
|
|
34996
35029
|
name: "create_service",
|
|
34997
35030
|
title: "Create service",
|
|
34998
35031
|
kind: "write",
|
|
34999
|
-
description: "Create a service from a container image, a
|
|
35032
|
+
description: "Create a service from a container image, a Git repository or an inline Dockerfile, and (unless deploy=false) start its first deploy. Private GitHub / GitLab repos work once connected (get_git_connections, list_git_repos); such services also redeploy on every push. A private repo that is not connected is refused (409 GITHUB_NOT_CONNECTED / GITLAB_NOT_CONNECTED / REPO_NOT_ACCESSIBLE, nothing created): give the user details.connectUrl and retry after they connect. COSTS MONEY once deployed (billed daily from the wallet): call with dryRun=true first, show the dailyCost to the user and get their OK.",
|
|
35000
35033
|
input: {
|
|
35001
35034
|
environmentId: id("Environment"),
|
|
35002
35035
|
name: exports_external.string().regex(/^[A-Za-z][A-Za-z0-9_-]{0,39}$/).describe("Service name (letters, digits, _ -; starts with a letter). Also used in references like ${{name.KEY}}"),
|
|
35003
35036
|
image: exports_external.string().optional().describe("Container image, e.g. nginx:alpine or ghcr.io/acme/app:1.2"),
|
|
35004
35037
|
registryUsername: exports_external.string().optional().describe("Private registry user (with registryPassword)"),
|
|
35005
35038
|
registryPassword: exports_external.string().optional().describe("Private registry password or token"),
|
|
35006
|
-
repo: exports_external.string().optional().describe("
|
|
35039
|
+
repo: exports_external.string().optional().describe("Git repository: https URL or owner/name for GitHub (instead of image). Private repos need a connected GitHub / GitLab (list_git_repos)"),
|
|
35007
35040
|
branch: exports_external.string().optional().describe("Git branch (default main)"),
|
|
35008
35041
|
rootDirectory: exports_external.string().optional().describe("Monorepo: folder to build, e.g. apps/web"),
|
|
35009
35042
|
dockerfile: exports_external.string().optional().describe("Inline Dockerfile content (instead of image/repo)"),
|
|
@@ -35393,6 +35426,10 @@ var period = exports_external.enum(["monthly", "3month", "6month", "yearly"]);
|
|
|
35393
35426
|
var pointId = exports_external.string().describe("Restore point id (from list_vps_restore_points)");
|
|
35394
35427
|
var backupPath = exports_external.string().max(1024).describe("Absolute path inside the backup, e.g. /etc/nginx or /var/www/index.html");
|
|
35395
35428
|
var migrationId = exports_external.string().describe("Migration id (from list_vps_migrations)");
|
|
35429
|
+
var dryRun2 = exports_external.boolean().optional().describe("true = return the price (IDR) and the wallet balance after it; nothing is charged or changed");
|
|
35430
|
+
var idempotencyKey = exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real call. Generated when omitted; pass the same value when retrying so it is never charged twice");
|
|
35431
|
+
var DRY = "dryRun=true returns the price and walletBalanceAfter without charging or changing anything.";
|
|
35432
|
+
var dryQuery = (d) => ({ dryRun: d ? "true" : undefined });
|
|
35396
35433
|
var vpsTools = [
|
|
35397
35434
|
defineTool({
|
|
35398
35435
|
name: "list_vps_plans",
|
|
@@ -35422,7 +35459,7 @@ var vpsTools = [
|
|
|
35422
35459
|
name: "create_vps",
|
|
35423
35460
|
title: "Create VPS",
|
|
35424
35461
|
kind: "write",
|
|
35425
|
-
description:
|
|
35462
|
+
description: `Order a server. COSTS MONEY right away (the whole billing period is charged from the wallet; refunded if provisioning fails). Call with dryRun=true first, show the price and the wallet after it, and get the user's explicit OK. ${DRY} autoRenew=false creates it with auto-renew off (renew it with renew_vps). Provisioning takes a few minutes: poll get_vps.`,
|
|
35426
35463
|
input: {
|
|
35427
35464
|
projectId: exports_external.string().uuid(),
|
|
35428
35465
|
planId: exports_external.string(),
|
|
@@ -35430,9 +35467,12 @@ var vpsTools = [
|
|
|
35430
35467
|
osType: exports_external.string().describe("From the plan's osTemplates, e.g. ubuntu"),
|
|
35431
35468
|
osVersion: exports_external.string().describe("e.g. 24.04"),
|
|
35432
35469
|
rootPassword: password,
|
|
35433
|
-
billingPeriod: period.optional().describe("Default monthly")
|
|
35470
|
+
billingPeriod: period.optional().describe("Default monthly"),
|
|
35471
|
+
autoRenew: exports_external.boolean().optional().describe("false = no automatic renewal from the wallet (default true)"),
|
|
35472
|
+
dryRun: dryRun2,
|
|
35473
|
+
idempotencyKey
|
|
35434
35474
|
},
|
|
35435
|
-
run: (
|
|
35475
|
+
run: ({ dryRun: dryRun3, idempotencyKey: idempotencyKey2, ...body }, api2) => api2.api("POST", "/vps", { body, query: dryQuery(dryRun3), idempotencyKey: purchaseKey(dryRun3, idempotencyKey2) })
|
|
35436
35476
|
}),
|
|
35437
35477
|
defineTool({
|
|
35438
35478
|
name: "vps_power",
|
|
@@ -35486,17 +35526,17 @@ var vpsTools = [
|
|
|
35486
35526
|
name: "renew_vps",
|
|
35487
35527
|
title: "Renew VPS",
|
|
35488
35528
|
kind: "write",
|
|
35489
|
-
description:
|
|
35490
|
-
input: { vpsId, billingPeriod: period },
|
|
35491
|
-
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/renew`, { body: { billingPeriod: a.billingPeriod } })
|
|
35529
|
+
description: `Extend a server's paid period. COSTS MONEY: call with dryRun=true first, show the price and the wallet after it, and get the user's OK. ${DRY}`,
|
|
35530
|
+
input: { vpsId, billingPeriod: period, dryRun: dryRun2, idempotencyKey },
|
|
35531
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/renew`, { body: { billingPeriod: a.billingPeriod }, query: dryQuery(a.dryRun), idempotencyKey: purchaseKey(a.dryRun, a.idempotencyKey) })
|
|
35492
35532
|
}),
|
|
35493
35533
|
defineTool({
|
|
35494
35534
|
name: "upgrade_vps",
|
|
35495
35535
|
title: "Upgrade VPS plan",
|
|
35496
35536
|
kind: "write",
|
|
35497
|
-
description:
|
|
35498
|
-
input: { vpsId, planId: exports_external.string() },
|
|
35499
|
-
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/upgrade`, { body: { planId: a.planId } })
|
|
35537
|
+
description: `Move a server to a larger plan in the same family and region. COSTS MONEY (the difference for the days left) and restarts the server. planId must be one listed by get_vps_upgrade_options. Call with dryRun=true first and get the user's OK. ${DRY} Servers with providerCode 2 only.`,
|
|
35538
|
+
input: { vpsId, planId: exports_external.string(), dryRun: dryRun2, idempotencyKey },
|
|
35539
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/upgrade`, { body: { planId: a.planId }, query: dryQuery(a.dryRun), idempotencyKey: purchaseKey(a.dryRun, a.idempotencyKey) })
|
|
35500
35540
|
}),
|
|
35501
35541
|
defineTool({
|
|
35502
35542
|
name: "get_vps_upgrade_options",
|
|
@@ -35523,11 +35563,20 @@ var vpsTools = [
|
|
|
35523
35563
|
input: { vpsId, range: exports_external.enum(["1h", "6h", "24h", "7d", "30d"]).optional() },
|
|
35524
35564
|
run: (a, api2) => api2.api("GET", `/vps/${a.vpsId}/metrics`, { query: { range: a.range } })
|
|
35525
35565
|
}),
|
|
35566
|
+
defineTool({
|
|
35567
|
+
name: "set_vps_auto_renew",
|
|
35568
|
+
title: "Set VPS auto-renew",
|
|
35569
|
+
kind: "write",
|
|
35570
|
+
idempotent: true,
|
|
35571
|
+
description: "Turn auto-renew on or off (sets the value, safe to repeat). With it off, the server is only renewed by renew_vps and expires otherwise.",
|
|
35572
|
+
input: { vpsId, autoRenew: exports_external.boolean() },
|
|
35573
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/auto-renew`, { body: { autoRenew: a.autoRenew } })
|
|
35574
|
+
}),
|
|
35526
35575
|
defineTool({
|
|
35527
35576
|
name: "toggle_vps_auto_renew",
|
|
35528
35577
|
title: "Toggle VPS auto-renew",
|
|
35529
35578
|
kind: "write",
|
|
35530
|
-
description: "Flip auto-renew
|
|
35579
|
+
description: "Flip auto-renew to the other value; the response gives the new one. Prefer set_vps_auto_renew to reach a given state.",
|
|
35531
35580
|
input: { vpsId },
|
|
35532
35581
|
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/auto-renew-toggle`)
|
|
35533
35582
|
}),
|
|
@@ -35856,8 +35905,8 @@ var vpsTools = [
|
|
|
35856
35905
|
// src/tools/domains.ts
|
|
35857
35906
|
var domainId = exports_external.number().int().positive().describe("Domain id (number, from list_my_domains)");
|
|
35858
35907
|
var hostId = exports_external.number().int().positive().describe("Child nameserver id (from list_child_nameservers)");
|
|
35859
|
-
var
|
|
35860
|
-
var
|
|
35908
|
+
var dryRun3 = exports_external.boolean().optional().describe("true = return the exact price (IDR, VAT included) and the wallet balance after it; nothing is charged or registered");
|
|
35909
|
+
var DRY2 = "dryRun=true returns the price and walletBalanceAfter without charging or changing anything.";
|
|
35861
35910
|
var record3 = exports_external.object({
|
|
35862
35911
|
name: exports_external.string().describe('"@" for the domain itself, or the part before the domain, e.g. "www" or "_dmarc.mail". A full name like "www.example.com" is accepted and stored as "www"'),
|
|
35863
35912
|
type: exports_external.enum(["A", "AAAA", "MX", "MXE", "CNAME", "SPF", "TXT"]),
|
|
@@ -35933,12 +35982,12 @@ var domainTools = [
|
|
|
35933
35982
|
name: "register_domain",
|
|
35934
35983
|
title: "Register domain",
|
|
35935
35984
|
kind: "write",
|
|
35936
|
-
description: `Register a domain for 1 year. COSTS MONEY from the wallet. Check search_domain, and that the owner details are complete (check_registrant / update_registrant). ${
|
|
35985
|
+
description: `Register a domain for 1 year. COSTS MONEY from the wallet. Check search_domain, and that the owner details are complete (check_registrant / update_registrant). ${DRY2} The dry run includes WHOIS privacy when whoisProtection is true.`,
|
|
35937
35986
|
input: {
|
|
35938
35987
|
name: exports_external.string().describe("Full domain, e.g. tokosaya.id"),
|
|
35939
35988
|
nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(),
|
|
35940
35989
|
whoisProtection: exports_external.boolean().optional(),
|
|
35941
|
-
dryRun:
|
|
35990
|
+
dryRun: dryRun3
|
|
35942
35991
|
},
|
|
35943
35992
|
run: (a, api2) => api2.api("POST", "/domains/register", { body: { name: a.name, period: 1, nameservers: a.nameservers, whoisProtection: a.whoisProtection }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
35944
35993
|
}),
|
|
@@ -35946,16 +35995,16 @@ var domainTools = [
|
|
|
35946
35995
|
name: "transfer_domain",
|
|
35947
35996
|
title: "Transfer domain in",
|
|
35948
35997
|
kind: "write",
|
|
35949
|
-
description: `Transfer a domain from another registrar (adds 1 year). COSTS MONEY from the wallet. Needs the domain's auth code. ${
|
|
35950
|
-
input: { name: exports_external.string(), authCode: exports_external.string(), nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(), dryRun:
|
|
35998
|
+
description: `Transfer a domain from another registrar (adds 1 year). COSTS MONEY from the wallet. Needs the domain's auth code. ${DRY2}`,
|
|
35999
|
+
input: { name: exports_external.string(), authCode: exports_external.string(), nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(), dryRun: dryRun3 },
|
|
35951
36000
|
run: (a, api2) => api2.api("POST", "/domains/transfer", { body: { name: a.name, authCode: a.authCode, period: 1, nameservers: a.nameservers }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
35952
36001
|
}),
|
|
35953
36002
|
defineTool({
|
|
35954
36003
|
name: "renew_domain",
|
|
35955
36004
|
title: "Renew domain",
|
|
35956
36005
|
kind: "write",
|
|
35957
|
-
description: `Renew a domain for 1 year (plus WHOIS privacy when it is on). COSTS MONEY from the wallet. ${
|
|
35958
|
-
input: { domainId, dryRun:
|
|
36006
|
+
description: `Renew a domain for 1 year (plus WHOIS privacy when it is on). COSTS MONEY from the wallet. ${DRY2}`,
|
|
36007
|
+
input: { domainId, dryRun: dryRun3 },
|
|
35959
36008
|
run: (a, api2) => api2.api("POST", `/domains/${a.domainId}/renew`, { body: { period: 1 }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
35960
36009
|
}),
|
|
35961
36010
|
defineTool({
|
|
@@ -36118,7 +36167,7 @@ var message = exports_external.object({
|
|
|
36118
36167
|
variables: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
36119
36168
|
idempotencyKey: exports_external.string().max(128).optional()
|
|
36120
36169
|
});
|
|
36121
|
-
var
|
|
36170
|
+
var dryRun4 = exports_external.boolean().optional().describe("true = return the price (IDR) and the wallet balance after it; nothing is charged or changed");
|
|
36122
36171
|
var idem2 = exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real purchase. Generated when omitted; pass the same value when retrying so it is never charged twice");
|
|
36123
36172
|
var MONEY = "COSTS MONEY from the wallet. dryRun=true returns the charge (IDR) and walletBalanceAfter without charging or changing anything.";
|
|
36124
36173
|
var planCode = exports_external.string().min(1).max(50).describe("Plan code from list_email_plans");
|
|
@@ -36154,7 +36203,7 @@ var emailTools = [
|
|
|
36154
36203
|
title: "Buy email plan",
|
|
36155
36204
|
kind: "write",
|
|
36156
36205
|
description: `Start an email plan for the project (a free plan activates without charge). Works for a project with no email yet: the real call also sets email up (result.setup). ${MONEY} The dry run's mode says purchase, activate_free or already_active.`,
|
|
36157
|
-
input: { projectId, planCode, months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional().describe("Billing cycle, default 1"), dryRun:
|
|
36206
|
+
input: { projectId, planCode, months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional().describe("Billing cycle, default 1"), dryRun: dryRun4, idempotencyKey: idem2 },
|
|
36158
36207
|
run: (a, api2) => api2.email("POST", "/plan", {
|
|
36159
36208
|
project: a.projectId,
|
|
36160
36209
|
body: { planCode: a.planCode, months: a.months },
|
|
@@ -36167,7 +36216,7 @@ var emailTools = [
|
|
|
36167
36216
|
title: "Renew email plan",
|
|
36168
36217
|
kind: "write",
|
|
36169
36218
|
description: `Renew the project's ended or expiring email plan (409 PLAN_ACTIVE while one is still running and cannot be extended). Repeats the last plan and cycle unless planCode / months are given. ${MONEY}`,
|
|
36170
|
-
input: { projectId, planCode: planCode.optional(), months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional(), dryRun:
|
|
36219
|
+
input: { projectId, planCode: planCode.optional(), months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional(), dryRun: dryRun4, idempotencyKey: idem2 },
|
|
36171
36220
|
run: (a, api2) => api2.email("POST", "/plan/renew", {
|
|
36172
36221
|
project: a.projectId,
|
|
36173
36222
|
body: { planCode: a.planCode, months: a.months },
|
|
@@ -36180,7 +36229,7 @@ var emailTools = [
|
|
|
36180
36229
|
title: "Change email plan",
|
|
36181
36230
|
kind: "write",
|
|
36182
36231
|
description: `Move the active email plan to another plan. An upgrade applies now and charges the prorated difference to the same end date; a downgrade is scheduled for the next cycle (no refund). ${MONEY}`,
|
|
36183
|
-
input: { projectId, planCode, dryRun:
|
|
36232
|
+
input: { projectId, planCode, dryRun: dryRun4, idempotencyKey: idem2 },
|
|
36184
36233
|
run: (a, api2) => api2.email("POST", "/plan/change", {
|
|
36185
36234
|
project: a.projectId,
|
|
36186
36235
|
body: { planCode: a.planCode },
|
|
@@ -36197,7 +36246,7 @@ var emailTools = [
|
|
|
36197
36246
|
projectId,
|
|
36198
36247
|
extraMailboxes: exports_external.number().int().min(0).max(50).describe("Total extra mailboxes wanted (0-50)"),
|
|
36199
36248
|
extraStorageGb: exports_external.number().int().min(0).max(1000).describe("Total extra inbox storage in GB (0-1000)"),
|
|
36200
|
-
dryRun:
|
|
36249
|
+
dryRun: dryRun4,
|
|
36201
36250
|
idempotencyKey: idem2
|
|
36202
36251
|
},
|
|
36203
36252
|
run: (a, api2) => api2.email("POST", "/plan/addons", {
|
|
@@ -36767,7 +36816,7 @@ var emailTools = [
|
|
|
36767
36816
|
// src/tools/databases.ts
|
|
36768
36817
|
var databaseId = exports_external.string().uuid().describe("Database id (from list_databases)");
|
|
36769
36818
|
var environmentId = exports_external.string().uuid().describe("Environment id (from list_projects). Omit for the primary (production) branch.");
|
|
36770
|
-
var
|
|
36819
|
+
var dryRun5 = exports_external.boolean().optional().describe("true = only check and show the result or price; nothing changes");
|
|
36771
36820
|
var databaseTools = [
|
|
36772
36821
|
defineTool({
|
|
36773
36822
|
name: "list_database_plans",
|
|
@@ -36861,7 +36910,7 @@ var databaseTools = [
|
|
|
36861
36910
|
minCu: exports_external.number().min(0.25).max(10).optional(),
|
|
36862
36911
|
maxCu: exports_external.number().min(0.25).max(10).optional(),
|
|
36863
36912
|
suspendTimeoutSeconds: exports_external.number().int().min(0).max(604800).optional().describe("0 = never suspend, or 60-604800"),
|
|
36864
|
-
dryRun:
|
|
36913
|
+
dryRun: dryRun5
|
|
36865
36914
|
},
|
|
36866
36915
|
run: (a, api2) => api2.api("PATCH", `/databases/${a.databaseId}/settings`, {
|
|
36867
36916
|
body: { minCu: a.minCu, maxCu: a.maxCu, suspendTimeoutSeconds: a.suspendTimeoutSeconds },
|
|
@@ -36873,7 +36922,7 @@ var databaseTools = [
|
|
|
36873
36922
|
title: "Upgrade database plan / top up",
|
|
36874
36923
|
kind: "write",
|
|
36875
36924
|
description: "Buy a paid plan or top up credits. COSTS MONEY from the wallet: call with dryRun first, show price and wallet balance after, and get the user's explicit OK.",
|
|
36876
|
-
input: { databaseId, plan: exports_external.string().describe("Plan code (e.g. STARTER) or id from list_database_plans"), dryRun:
|
|
36925
|
+
input: { databaseId, plan: exports_external.string().describe("Plan code (e.g. STARTER) or id from list_database_plans"), dryRun: dryRun5, idempotencyKey: exports_external.string().max(128).optional() },
|
|
36877
36926
|
run: (a, api2) => api2.api("POST", `/databases/${a.databaseId}/upgrade`, { body: { plan: a.plan }, query: { dryRun: a.dryRun ? "true" : undefined }, idempotencyKey: a.idempotencyKey })
|
|
36878
36927
|
}),
|
|
36879
36928
|
defineTool({
|
|
@@ -37131,7 +37180,7 @@ var accountTools = [
|
|
|
37131
37180
|
var projectId2 = exports_external.string().uuid().optional().describe("Limit to one project (a project key is always limited to its own)");
|
|
37132
37181
|
var keyId = exports_external.string().uuid().optional().describe("Limit to one AI key (id from list_ai_keys)");
|
|
37133
37182
|
var model = exports_external.string().max(100).optional().describe("Limit to one model id");
|
|
37134
|
-
var
|
|
37183
|
+
var dryRun6 = exports_external.boolean().optional().describe("true = only check and show the result; nothing is charged or changed");
|
|
37135
37184
|
var ACCOUNT_KEY2 = "Needs a whole-account key (a key limited to one project gets 403 ACCOUNT_KEY_REQUIRED).";
|
|
37136
37185
|
var imageProject = exports_external.string().uuid().optional().describe("Project the images belong to (required with a whole-account key; a project key uses its own)");
|
|
37137
37186
|
var INLINE_MAX_BYTES = 1500000;
|
|
@@ -37216,7 +37265,7 @@ var aiTools = [
|
|
|
37216
37265
|
n: exports_external.number().int().min(1).max(10).optional().describe("Images in this request (up to the model's maxN; default 1)"),
|
|
37217
37266
|
images: exports_external.array(exports_external.string().url().startsWith("https://")).max(10).optional().describe("Reference images as https:// links (only models with refImages > 0)"),
|
|
37218
37267
|
projectId: imageProject,
|
|
37219
|
-
dryRun:
|
|
37268
|
+
dryRun: dryRun6,
|
|
37220
37269
|
wait: exports_external.number().int().min(0).max(55).optional().describe("Seconds to wait for the result (default 50; 0 = return the id at once)"),
|
|
37221
37270
|
idempotencyKey: exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real request. Generated when omitted; pass the same value when retrying so it is never charged twice")
|
|
37222
37271
|
},
|
|
@@ -37266,7 +37315,7 @@ var aiTools = [
|
|
|
37266
37315
|
input: {
|
|
37267
37316
|
packId: exports_external.string().min(1).max(64).optional(),
|
|
37268
37317
|
amount: exports_external.number().min(1).max(1e9).optional().describe("IDR"),
|
|
37269
|
-
dryRun:
|
|
37318
|
+
dryRun: dryRun6,
|
|
37270
37319
|
idempotencyKey: exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real top-up. Generated when omitted; pass the same value when retrying so it is never charged twice")
|
|
37271
37320
|
},
|
|
37272
37321
|
run: (a, api2) => {
|
|
@@ -37289,7 +37338,7 @@ var aiTools = [
|
|
|
37289
37338
|
enabled: exports_external.boolean(),
|
|
37290
37339
|
threshold: exports_external.number().min(1).optional().describe("Top up when the AI balance is below this (IDR)"),
|
|
37291
37340
|
amount: exports_external.number().min(1).optional().describe("How much to top up each time (IDR)"),
|
|
37292
|
-
dryRun:
|
|
37341
|
+
dryRun: dryRun6
|
|
37293
37342
|
},
|
|
37294
37343
|
run: (a, api2) => api2.api("PUT", "/ai/auto-topup", {
|
|
37295
37344
|
body: { enabled: a.enabled, threshold: a.threshold, amount: a.amount },
|
|
@@ -37325,7 +37374,7 @@ var generalTools = [
|
|
|
37325
37374
|
];
|
|
37326
37375
|
|
|
37327
37376
|
// src/server.ts
|
|
37328
|
-
var VERSION = "0.5.
|
|
37377
|
+
var VERSION = "0.5.10";
|
|
37329
37378
|
var INSTRUCTIONS = `Helipod is a cloud platform (Indonesia): containers, managed Postgres databases, VPS, domains, email and an AI gateway, billed from a prepaid wallet in Rupiah.
|
|
37330
37379
|
- Start with list_projects to find projects and environment ids. Account tools (get_wallet, invoices, statements, notifications, get_project_activity, support tickets) cover the account; AI tools (list_ai_models, get_ai_overview, get_ai_usage, AI keys, top-ups, generate_ai_image) cover the AI gateway.
|
|
37331
37380
|
- Anything that costs money (create/deploy/scale services, resize volumes, upgrade a database plan, create/renew/upgrade VPS, VPS backups, register/renew/transfer domains, email plans and inbox add-ons, AI top-ups and auto top-up, generating images): call it with dryRun=true first (or the price lookup when it has no dry run), tell the user the cost in IDR and the wallet balance after, and wait for an explicit yes before the real call. Never treat silence or an earlier general OK as a yes.
|
|
@@ -37335,9 +37384,10 @@ var INSTRUCTIONS = `Helipod is a cloud platform (Indonesia): containers, managed
|
|
|
37335
37384
|
- Databases: get_database_connection returns a password; put it in a secret variable (DATABASE_URL) instead of code or chat.
|
|
37336
37385
|
- Migrate (free): create_vps_import returns a one-time command for the USER to run as root on their old server (never run it yourself); before the first restore_vps_import, show fetchedIp and ask the user to confirm it is their server.
|
|
37337
37386
|
- Images from generate_ai_image are deleted after 7 days: tell the user and have them download the ones they keep.
|
|
37387
|
+
- Deploying from Git: public repos need nothing. For a private repo check get_git_connections / list_git_repos first; when GitHub or GitLab is not connected (or a call returns 409 GITHUB_NOT_CONNECTED / GITLAB_NOT_CONNECTED / REPO_NOT_ACCESSIBLE), give the user details.connectUrl to open in their browser and try again after they confirm. Never ask for a GitHub token.
|
|
37338
37388
|
- Deploys and VPS actions run in the background: poll get_deployment / get_vps until they settle; on a failed deploy read get_deployment_logs.
|
|
37339
37389
|
- Never print secrets (passwords, secret variable values, secret files) unless the user asks for them. Domain owner details are personal data: use only what the user gave.
|
|
37340
|
-
- Errors come back as { status, code, error }: 401/403 means the key lacks access (keys choose products and projects in Settings → API keys; wallet, invoices, tickets and AI money need a whole-account key: with a sign-in, reconnect and choose Whole account), 402 means plan limit or low balance.
|
|
37390
|
+
- Errors come back as { status, code, error, details? }: 401/403 means the key lacks access (keys choose products and projects in Settings → API keys; wallet, invoices, tickets and AI money need a whole-account key: with a sign-in, reconnect and choose Whole account), 402 means plan limit or low balance.
|
|
37341
37391
|
Docs: https://docs.helipod.io`;
|
|
37342
37392
|
var ALL_TOOLS = [...containerTools, ...databaseTools, ...vpsTools, ...domainTools, ...emailTools, ...accountTools, ...aiTools, ...generalTools];
|
|
37343
37393
|
function createHelipodServer(config2) {
|
package/dist/stdio.js
CHANGED
|
@@ -34834,10 +34834,12 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
34834
34834
|
class HelipodError extends Error {
|
|
34835
34835
|
status;
|
|
34836
34836
|
code;
|
|
34837
|
-
|
|
34837
|
+
details;
|
|
34838
|
+
constructor(status, code, message, details) {
|
|
34838
34839
|
super(message);
|
|
34839
34840
|
this.status = status;
|
|
34840
34841
|
this.code = code;
|
|
34842
|
+
this.details = details;
|
|
34841
34843
|
this.name = "HelipodError";
|
|
34842
34844
|
}
|
|
34843
34845
|
}
|
|
@@ -34933,7 +34935,8 @@ class HelipodClient {
|
|
|
34933
34935
|
if (!res.ok || json2?.success === false) {
|
|
34934
34936
|
const retry = res.headers.get("retry-after");
|
|
34935
34937
|
const msg = json2?.error ?? (text.slice(0, 300) || res.statusText);
|
|
34936
|
-
|
|
34938
|
+
const details = json2?.details && typeof json2.details === "object" && !Array.isArray(json2.details) ? json2.details : undefined;
|
|
34939
|
+
throw new HelipodError(res.status, json2?.code, retry ? `${msg} (retry after ${retry}s)` : String(msg), details);
|
|
34937
34940
|
}
|
|
34938
34941
|
return json2 && "data" in json2 ? json2.data : json2;
|
|
34939
34942
|
}
|
|
@@ -34965,7 +34968,7 @@ function register(server, api2, defs) {
|
|
|
34965
34968
|
const err = e instanceof HelipodError ? e : new HelipodError(0, "CLIENT_ERROR", String(e?.message ?? e));
|
|
34966
34969
|
return {
|
|
34967
34970
|
isError: true,
|
|
34968
|
-
content: [{ type: "text", text: JSON.stringify({ status: err.status, code: err.code ?? null, error: err.message }, null, 2) }]
|
|
34971
|
+
content: [{ type: "text", text: JSON.stringify({ status: err.status, code: err.code ?? null, error: err.message, ...err.details ? { details: err.details } : {} }, null, 2) }]
|
|
34969
34972
|
};
|
|
34970
34973
|
}
|
|
34971
34974
|
});
|
|
@@ -35099,18 +35102,48 @@ var containerTools = [
|
|
|
35099
35102
|
input: { serviceId: id("Service") },
|
|
35100
35103
|
run: (a, api2) => api2.api("GET", `${C}/services/${a.serviceId}`)
|
|
35101
35104
|
}),
|
|
35105
|
+
defineTool({
|
|
35106
|
+
name: "get_git_connections",
|
|
35107
|
+
title: "Git connections",
|
|
35108
|
+
kind: "read",
|
|
35109
|
+
description: "Whether the user connected GitHub (sign-in + the Helipod GitHub App, with the accounts it is installed on) and GitLab, plus connectUrl: the Helipod page where the user connects them. Check this before deploying from a private repo. Connecting needs the user in a browser: give them connectUrl, never try to connect yourself.",
|
|
35110
|
+
input: {},
|
|
35111
|
+
run: (_a3, api2) => api2.api("GET", `${C}/git/connections`)
|
|
35112
|
+
}),
|
|
35113
|
+
defineTool({
|
|
35114
|
+
name: "list_git_repos",
|
|
35115
|
+
title: "List Git repositories",
|
|
35116
|
+
kind: "read",
|
|
35117
|
+
description: "Repositories the user's connected GitHub App installations (host github, default) or GitLab account (host gitlab) can reach: fullName, url, private, defaultBranch, newest first. Pass one url to create_service as repo. Not connected: 409 with details.connectUrl for the user.",
|
|
35118
|
+
input: {
|
|
35119
|
+
host: exports_external.enum(["github", "gitlab"]).optional().describe("github (default) or gitlab"),
|
|
35120
|
+
installationId: exports_external.number().int().positive().optional().describe("Only this GitHub installation (id from get_git_connections)"),
|
|
35121
|
+
search: exports_external.string().max(200).optional().describe("Filter by part of owner/name"),
|
|
35122
|
+
limit: exports_external.number().int().min(1).max(100).optional().describe("Default 50"),
|
|
35123
|
+
offset: exports_external.number().int().min(0).optional()
|
|
35124
|
+
},
|
|
35125
|
+
run: (a, api2) => api2.api("GET", `${C}/git/repos`, {
|
|
35126
|
+
query: {
|
|
35127
|
+
host: a.host,
|
|
35128
|
+
installationId: a.installationId !== undefined ? String(a.installationId) : undefined,
|
|
35129
|
+
search: a.search,
|
|
35130
|
+
limit: a.limit !== undefined ? String(a.limit) : undefined,
|
|
35131
|
+
offset: a.offset !== undefined ? String(a.offset) : undefined
|
|
35132
|
+
}
|
|
35133
|
+
})
|
|
35134
|
+
}),
|
|
35102
35135
|
defineTool({
|
|
35103
35136
|
name: "create_service",
|
|
35104
35137
|
title: "Create service",
|
|
35105
35138
|
kind: "write",
|
|
35106
|
-
description: "Create a service from a container image, a
|
|
35139
|
+
description: "Create a service from a container image, a Git repository or an inline Dockerfile, and (unless deploy=false) start its first deploy. Private GitHub / GitLab repos work once connected (get_git_connections, list_git_repos); such services also redeploy on every push. A private repo that is not connected is refused (409 GITHUB_NOT_CONNECTED / GITLAB_NOT_CONNECTED / REPO_NOT_ACCESSIBLE, nothing created): give the user details.connectUrl and retry after they connect. COSTS MONEY once deployed (billed daily from the wallet): call with dryRun=true first, show the dailyCost to the user and get their OK.",
|
|
35107
35140
|
input: {
|
|
35108
35141
|
environmentId: id("Environment"),
|
|
35109
35142
|
name: exports_external.string().regex(/^[A-Za-z][A-Za-z0-9_-]{0,39}$/).describe("Service name (letters, digits, _ -; starts with a letter). Also used in references like ${{name.KEY}}"),
|
|
35110
35143
|
image: exports_external.string().optional().describe("Container image, e.g. nginx:alpine or ghcr.io/acme/app:1.2"),
|
|
35111
35144
|
registryUsername: exports_external.string().optional().describe("Private registry user (with registryPassword)"),
|
|
35112
35145
|
registryPassword: exports_external.string().optional().describe("Private registry password or token"),
|
|
35113
|
-
repo: exports_external.string().optional().describe("
|
|
35146
|
+
repo: exports_external.string().optional().describe("Git repository: https URL or owner/name for GitHub (instead of image). Private repos need a connected GitHub / GitLab (list_git_repos)"),
|
|
35114
35147
|
branch: exports_external.string().optional().describe("Git branch (default main)"),
|
|
35115
35148
|
rootDirectory: exports_external.string().optional().describe("Monorepo: folder to build, e.g. apps/web"),
|
|
35116
35149
|
dockerfile: exports_external.string().optional().describe("Inline Dockerfile content (instead of image/repo)"),
|
|
@@ -35500,6 +35533,10 @@ var period = exports_external.enum(["monthly", "3month", "6month", "yearly"]);
|
|
|
35500
35533
|
var pointId = exports_external.string().describe("Restore point id (from list_vps_restore_points)");
|
|
35501
35534
|
var backupPath = exports_external.string().max(1024).describe("Absolute path inside the backup, e.g. /etc/nginx or /var/www/index.html");
|
|
35502
35535
|
var migrationId = exports_external.string().describe("Migration id (from list_vps_migrations)");
|
|
35536
|
+
var dryRun2 = exports_external.boolean().optional().describe("true = return the price (IDR) and the wallet balance after it; nothing is charged or changed");
|
|
35537
|
+
var idempotencyKey = exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real call. Generated when omitted; pass the same value when retrying so it is never charged twice");
|
|
35538
|
+
var DRY = "dryRun=true returns the price and walletBalanceAfter without charging or changing anything.";
|
|
35539
|
+
var dryQuery = (d) => ({ dryRun: d ? "true" : undefined });
|
|
35503
35540
|
var vpsTools = [
|
|
35504
35541
|
defineTool({
|
|
35505
35542
|
name: "list_vps_plans",
|
|
@@ -35529,7 +35566,7 @@ var vpsTools = [
|
|
|
35529
35566
|
name: "create_vps",
|
|
35530
35567
|
title: "Create VPS",
|
|
35531
35568
|
kind: "write",
|
|
35532
|
-
description:
|
|
35569
|
+
description: `Order a server. COSTS MONEY right away (the whole billing period is charged from the wallet; refunded if provisioning fails). Call with dryRun=true first, show the price and the wallet after it, and get the user's explicit OK. ${DRY} autoRenew=false creates it with auto-renew off (renew it with renew_vps). Provisioning takes a few minutes: poll get_vps.`,
|
|
35533
35570
|
input: {
|
|
35534
35571
|
projectId: exports_external.string().uuid(),
|
|
35535
35572
|
planId: exports_external.string(),
|
|
@@ -35537,9 +35574,12 @@ var vpsTools = [
|
|
|
35537
35574
|
osType: exports_external.string().describe("From the plan's osTemplates, e.g. ubuntu"),
|
|
35538
35575
|
osVersion: exports_external.string().describe("e.g. 24.04"),
|
|
35539
35576
|
rootPassword: password,
|
|
35540
|
-
billingPeriod: period.optional().describe("Default monthly")
|
|
35577
|
+
billingPeriod: period.optional().describe("Default monthly"),
|
|
35578
|
+
autoRenew: exports_external.boolean().optional().describe("false = no automatic renewal from the wallet (default true)"),
|
|
35579
|
+
dryRun: dryRun2,
|
|
35580
|
+
idempotencyKey
|
|
35541
35581
|
},
|
|
35542
|
-
run: (
|
|
35582
|
+
run: ({ dryRun: dryRun3, idempotencyKey: idempotencyKey2, ...body }, api2) => api2.api("POST", "/vps", { body, query: dryQuery(dryRun3), idempotencyKey: purchaseKey(dryRun3, idempotencyKey2) })
|
|
35543
35583
|
}),
|
|
35544
35584
|
defineTool({
|
|
35545
35585
|
name: "vps_power",
|
|
@@ -35593,17 +35633,17 @@ var vpsTools = [
|
|
|
35593
35633
|
name: "renew_vps",
|
|
35594
35634
|
title: "Renew VPS",
|
|
35595
35635
|
kind: "write",
|
|
35596
|
-
description:
|
|
35597
|
-
input: { vpsId, billingPeriod: period },
|
|
35598
|
-
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/renew`, { body: { billingPeriod: a.billingPeriod } })
|
|
35636
|
+
description: `Extend a server's paid period. COSTS MONEY: call with dryRun=true first, show the price and the wallet after it, and get the user's OK. ${DRY}`,
|
|
35637
|
+
input: { vpsId, billingPeriod: period, dryRun: dryRun2, idempotencyKey },
|
|
35638
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/renew`, { body: { billingPeriod: a.billingPeriod }, query: dryQuery(a.dryRun), idempotencyKey: purchaseKey(a.dryRun, a.idempotencyKey) })
|
|
35599
35639
|
}),
|
|
35600
35640
|
defineTool({
|
|
35601
35641
|
name: "upgrade_vps",
|
|
35602
35642
|
title: "Upgrade VPS plan",
|
|
35603
35643
|
kind: "write",
|
|
35604
|
-
description:
|
|
35605
|
-
input: { vpsId, planId: exports_external.string() },
|
|
35606
|
-
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/upgrade`, { body: { planId: a.planId } })
|
|
35644
|
+
description: `Move a server to a larger plan in the same family and region. COSTS MONEY (the difference for the days left) and restarts the server. planId must be one listed by get_vps_upgrade_options. Call with dryRun=true first and get the user's OK. ${DRY} Servers with providerCode 2 only.`,
|
|
35645
|
+
input: { vpsId, planId: exports_external.string(), dryRun: dryRun2, idempotencyKey },
|
|
35646
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/upgrade`, { body: { planId: a.planId }, query: dryQuery(a.dryRun), idempotencyKey: purchaseKey(a.dryRun, a.idempotencyKey) })
|
|
35607
35647
|
}),
|
|
35608
35648
|
defineTool({
|
|
35609
35649
|
name: "get_vps_upgrade_options",
|
|
@@ -35630,11 +35670,20 @@ var vpsTools = [
|
|
|
35630
35670
|
input: { vpsId, range: exports_external.enum(["1h", "6h", "24h", "7d", "30d"]).optional() },
|
|
35631
35671
|
run: (a, api2) => api2.api("GET", `/vps/${a.vpsId}/metrics`, { query: { range: a.range } })
|
|
35632
35672
|
}),
|
|
35673
|
+
defineTool({
|
|
35674
|
+
name: "set_vps_auto_renew",
|
|
35675
|
+
title: "Set VPS auto-renew",
|
|
35676
|
+
kind: "write",
|
|
35677
|
+
idempotent: true,
|
|
35678
|
+
description: "Turn auto-renew on or off (sets the value, safe to repeat). With it off, the server is only renewed by renew_vps and expires otherwise.",
|
|
35679
|
+
input: { vpsId, autoRenew: exports_external.boolean() },
|
|
35680
|
+
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/auto-renew`, { body: { autoRenew: a.autoRenew } })
|
|
35681
|
+
}),
|
|
35633
35682
|
defineTool({
|
|
35634
35683
|
name: "toggle_vps_auto_renew",
|
|
35635
35684
|
title: "Toggle VPS auto-renew",
|
|
35636
35685
|
kind: "write",
|
|
35637
|
-
description: "Flip auto-renew
|
|
35686
|
+
description: "Flip auto-renew to the other value; the response gives the new one. Prefer set_vps_auto_renew to reach a given state.",
|
|
35638
35687
|
input: { vpsId },
|
|
35639
35688
|
run: (a, api2) => api2.api("POST", `/vps/${a.vpsId}/auto-renew-toggle`)
|
|
35640
35689
|
}),
|
|
@@ -35963,8 +36012,8 @@ var vpsTools = [
|
|
|
35963
36012
|
// src/tools/domains.ts
|
|
35964
36013
|
var domainId = exports_external.number().int().positive().describe("Domain id (number, from list_my_domains)");
|
|
35965
36014
|
var hostId = exports_external.number().int().positive().describe("Child nameserver id (from list_child_nameservers)");
|
|
35966
|
-
var
|
|
35967
|
-
var
|
|
36015
|
+
var dryRun3 = exports_external.boolean().optional().describe("true = return the exact price (IDR, VAT included) and the wallet balance after it; nothing is charged or registered");
|
|
36016
|
+
var DRY2 = "dryRun=true returns the price and walletBalanceAfter without charging or changing anything.";
|
|
35968
36017
|
var record3 = exports_external.object({
|
|
35969
36018
|
name: exports_external.string().describe('"@" for the domain itself, or the part before the domain, e.g. "www" or "_dmarc.mail". A full name like "www.example.com" is accepted and stored as "www"'),
|
|
35970
36019
|
type: exports_external.enum(["A", "AAAA", "MX", "MXE", "CNAME", "SPF", "TXT"]),
|
|
@@ -36040,12 +36089,12 @@ var domainTools = [
|
|
|
36040
36089
|
name: "register_domain",
|
|
36041
36090
|
title: "Register domain",
|
|
36042
36091
|
kind: "write",
|
|
36043
|
-
description: `Register a domain for 1 year. COSTS MONEY from the wallet. Check search_domain, and that the owner details are complete (check_registrant / update_registrant). ${
|
|
36092
|
+
description: `Register a domain for 1 year. COSTS MONEY from the wallet. Check search_domain, and that the owner details are complete (check_registrant / update_registrant). ${DRY2} The dry run includes WHOIS privacy when whoisProtection is true.`,
|
|
36044
36093
|
input: {
|
|
36045
36094
|
name: exports_external.string().describe("Full domain, e.g. tokosaya.id"),
|
|
36046
36095
|
nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(),
|
|
36047
36096
|
whoisProtection: exports_external.boolean().optional(),
|
|
36048
|
-
dryRun:
|
|
36097
|
+
dryRun: dryRun3
|
|
36049
36098
|
},
|
|
36050
36099
|
run: (a, api2) => api2.api("POST", "/domains/register", { body: { name: a.name, period: 1, nameservers: a.nameservers, whoisProtection: a.whoisProtection }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
36051
36100
|
}),
|
|
@@ -36053,16 +36102,16 @@ var domainTools = [
|
|
|
36053
36102
|
name: "transfer_domain",
|
|
36054
36103
|
title: "Transfer domain in",
|
|
36055
36104
|
kind: "write",
|
|
36056
|
-
description: `Transfer a domain from another registrar (adds 1 year). COSTS MONEY from the wallet. Needs the domain's auth code. ${
|
|
36057
|
-
input: { name: exports_external.string(), authCode: exports_external.string(), nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(), dryRun:
|
|
36105
|
+
description: `Transfer a domain from another registrar (adds 1 year). COSTS MONEY from the wallet. Needs the domain's auth code. ${DRY2}`,
|
|
36106
|
+
input: { name: exports_external.string(), authCode: exports_external.string(), nameservers: exports_external.array(exports_external.string()).min(2).max(5).optional(), dryRun: dryRun3 },
|
|
36058
36107
|
run: (a, api2) => api2.api("POST", "/domains/transfer", { body: { name: a.name, authCode: a.authCode, period: 1, nameservers: a.nameservers }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
36059
36108
|
}),
|
|
36060
36109
|
defineTool({
|
|
36061
36110
|
name: "renew_domain",
|
|
36062
36111
|
title: "Renew domain",
|
|
36063
36112
|
kind: "write",
|
|
36064
|
-
description: `Renew a domain for 1 year (plus WHOIS privacy when it is on). COSTS MONEY from the wallet. ${
|
|
36065
|
-
input: { domainId, dryRun:
|
|
36113
|
+
description: `Renew a domain for 1 year (plus WHOIS privacy when it is on). COSTS MONEY from the wallet. ${DRY2}`,
|
|
36114
|
+
input: { domainId, dryRun: dryRun3 },
|
|
36066
36115
|
run: (a, api2) => api2.api("POST", `/domains/${a.domainId}/renew`, { body: { period: 1 }, query: { dryRun: a.dryRun ? "true" : undefined } })
|
|
36067
36116
|
}),
|
|
36068
36117
|
defineTool({
|
|
@@ -36225,7 +36274,7 @@ var message = exports_external.object({
|
|
|
36225
36274
|
variables: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
36226
36275
|
idempotencyKey: exports_external.string().max(128).optional()
|
|
36227
36276
|
});
|
|
36228
|
-
var
|
|
36277
|
+
var dryRun4 = exports_external.boolean().optional().describe("true = return the price (IDR) and the wallet balance after it; nothing is charged or changed");
|
|
36229
36278
|
var idem2 = exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real purchase. Generated when omitted; pass the same value when retrying so it is never charged twice");
|
|
36230
36279
|
var MONEY = "COSTS MONEY from the wallet. dryRun=true returns the charge (IDR) and walletBalanceAfter without charging or changing anything.";
|
|
36231
36280
|
var planCode = exports_external.string().min(1).max(50).describe("Plan code from list_email_plans");
|
|
@@ -36261,7 +36310,7 @@ var emailTools = [
|
|
|
36261
36310
|
title: "Buy email plan",
|
|
36262
36311
|
kind: "write",
|
|
36263
36312
|
description: `Start an email plan for the project (a free plan activates without charge). Works for a project with no email yet: the real call also sets email up (result.setup). ${MONEY} The dry run's mode says purchase, activate_free or already_active.`,
|
|
36264
|
-
input: { projectId, planCode, months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional().describe("Billing cycle, default 1"), dryRun:
|
|
36313
|
+
input: { projectId, planCode, months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional().describe("Billing cycle, default 1"), dryRun: dryRun4, idempotencyKey: idem2 },
|
|
36265
36314
|
run: (a, api2) => api2.email("POST", "/plan", {
|
|
36266
36315
|
project: a.projectId,
|
|
36267
36316
|
body: { planCode: a.planCode, months: a.months },
|
|
@@ -36274,7 +36323,7 @@ var emailTools = [
|
|
|
36274
36323
|
title: "Renew email plan",
|
|
36275
36324
|
kind: "write",
|
|
36276
36325
|
description: `Renew the project's ended or expiring email plan (409 PLAN_ACTIVE while one is still running and cannot be extended). Repeats the last plan and cycle unless planCode / months are given. ${MONEY}`,
|
|
36277
|
-
input: { projectId, planCode: planCode.optional(), months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional(), dryRun:
|
|
36326
|
+
input: { projectId, planCode: planCode.optional(), months: exports_external.union([exports_external.literal(1), exports_external.literal(3), exports_external.literal(6), exports_external.literal(12)]).optional(), dryRun: dryRun4, idempotencyKey: idem2 },
|
|
36278
36327
|
run: (a, api2) => api2.email("POST", "/plan/renew", {
|
|
36279
36328
|
project: a.projectId,
|
|
36280
36329
|
body: { planCode: a.planCode, months: a.months },
|
|
@@ -36287,7 +36336,7 @@ var emailTools = [
|
|
|
36287
36336
|
title: "Change email plan",
|
|
36288
36337
|
kind: "write",
|
|
36289
36338
|
description: `Move the active email plan to another plan. An upgrade applies now and charges the prorated difference to the same end date; a downgrade is scheduled for the next cycle (no refund). ${MONEY}`,
|
|
36290
|
-
input: { projectId, planCode, dryRun:
|
|
36339
|
+
input: { projectId, planCode, dryRun: dryRun4, idempotencyKey: idem2 },
|
|
36291
36340
|
run: (a, api2) => api2.email("POST", "/plan/change", {
|
|
36292
36341
|
project: a.projectId,
|
|
36293
36342
|
body: { planCode: a.planCode },
|
|
@@ -36304,7 +36353,7 @@ var emailTools = [
|
|
|
36304
36353
|
projectId,
|
|
36305
36354
|
extraMailboxes: exports_external.number().int().min(0).max(50).describe("Total extra mailboxes wanted (0-50)"),
|
|
36306
36355
|
extraStorageGb: exports_external.number().int().min(0).max(1000).describe("Total extra inbox storage in GB (0-1000)"),
|
|
36307
|
-
dryRun:
|
|
36356
|
+
dryRun: dryRun4,
|
|
36308
36357
|
idempotencyKey: idem2
|
|
36309
36358
|
},
|
|
36310
36359
|
run: (a, api2) => api2.email("POST", "/plan/addons", {
|
|
@@ -36874,7 +36923,7 @@ var emailTools = [
|
|
|
36874
36923
|
// src/tools/databases.ts
|
|
36875
36924
|
var databaseId = exports_external.string().uuid().describe("Database id (from list_databases)");
|
|
36876
36925
|
var environmentId = exports_external.string().uuid().describe("Environment id (from list_projects). Omit for the primary (production) branch.");
|
|
36877
|
-
var
|
|
36926
|
+
var dryRun5 = exports_external.boolean().optional().describe("true = only check and show the result or price; nothing changes");
|
|
36878
36927
|
var databaseTools = [
|
|
36879
36928
|
defineTool({
|
|
36880
36929
|
name: "list_database_plans",
|
|
@@ -36968,7 +37017,7 @@ var databaseTools = [
|
|
|
36968
37017
|
minCu: exports_external.number().min(0.25).max(10).optional(),
|
|
36969
37018
|
maxCu: exports_external.number().min(0.25).max(10).optional(),
|
|
36970
37019
|
suspendTimeoutSeconds: exports_external.number().int().min(0).max(604800).optional().describe("0 = never suspend, or 60-604800"),
|
|
36971
|
-
dryRun:
|
|
37020
|
+
dryRun: dryRun5
|
|
36972
37021
|
},
|
|
36973
37022
|
run: (a, api2) => api2.api("PATCH", `/databases/${a.databaseId}/settings`, {
|
|
36974
37023
|
body: { minCu: a.minCu, maxCu: a.maxCu, suspendTimeoutSeconds: a.suspendTimeoutSeconds },
|
|
@@ -36980,7 +37029,7 @@ var databaseTools = [
|
|
|
36980
37029
|
title: "Upgrade database plan / top up",
|
|
36981
37030
|
kind: "write",
|
|
36982
37031
|
description: "Buy a paid plan or top up credits. COSTS MONEY from the wallet: call with dryRun first, show price and wallet balance after, and get the user's explicit OK.",
|
|
36983
|
-
input: { databaseId, plan: exports_external.string().describe("Plan code (e.g. STARTER) or id from list_database_plans"), dryRun:
|
|
37032
|
+
input: { databaseId, plan: exports_external.string().describe("Plan code (e.g. STARTER) or id from list_database_plans"), dryRun: dryRun5, idempotencyKey: exports_external.string().max(128).optional() },
|
|
36984
37033
|
run: (a, api2) => api2.api("POST", `/databases/${a.databaseId}/upgrade`, { body: { plan: a.plan }, query: { dryRun: a.dryRun ? "true" : undefined }, idempotencyKey: a.idempotencyKey })
|
|
36985
37034
|
}),
|
|
36986
37035
|
defineTool({
|
|
@@ -37238,7 +37287,7 @@ var accountTools = [
|
|
|
37238
37287
|
var projectId2 = exports_external.string().uuid().optional().describe("Limit to one project (a project key is always limited to its own)");
|
|
37239
37288
|
var keyId = exports_external.string().uuid().optional().describe("Limit to one AI key (id from list_ai_keys)");
|
|
37240
37289
|
var model = exports_external.string().max(100).optional().describe("Limit to one model id");
|
|
37241
|
-
var
|
|
37290
|
+
var dryRun6 = exports_external.boolean().optional().describe("true = only check and show the result; nothing is charged or changed");
|
|
37242
37291
|
var ACCOUNT_KEY2 = "Needs a whole-account key (a key limited to one project gets 403 ACCOUNT_KEY_REQUIRED).";
|
|
37243
37292
|
var imageProject = exports_external.string().uuid().optional().describe("Project the images belong to (required with a whole-account key; a project key uses its own)");
|
|
37244
37293
|
var INLINE_MAX_BYTES = 1500000;
|
|
@@ -37323,7 +37372,7 @@ var aiTools = [
|
|
|
37323
37372
|
n: exports_external.number().int().min(1).max(10).optional().describe("Images in this request (up to the model's maxN; default 1)"),
|
|
37324
37373
|
images: exports_external.array(exports_external.string().url().startsWith("https://")).max(10).optional().describe("Reference images as https:// links (only models with refImages > 0)"),
|
|
37325
37374
|
projectId: imageProject,
|
|
37326
|
-
dryRun:
|
|
37375
|
+
dryRun: dryRun6,
|
|
37327
37376
|
wait: exports_external.number().int().min(0).max(55).optional().describe("Seconds to wait for the result (default 50; 0 = return the id at once)"),
|
|
37328
37377
|
idempotencyKey: exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real request. Generated when omitted; pass the same value when retrying so it is never charged twice")
|
|
37329
37378
|
},
|
|
@@ -37373,7 +37422,7 @@ var aiTools = [
|
|
|
37373
37422
|
input: {
|
|
37374
37423
|
packId: exports_external.string().min(1).max(64).optional(),
|
|
37375
37424
|
amount: exports_external.number().min(1).max(1e9).optional().describe("IDR"),
|
|
37376
|
-
dryRun:
|
|
37425
|
+
dryRun: dryRun6,
|
|
37377
37426
|
idempotencyKey: exports_external.string().regex(/^[A-Za-z0-9_.:-]{8,128}$/).optional().describe("Idempotency-Key for the real top-up. Generated when omitted; pass the same value when retrying so it is never charged twice")
|
|
37378
37427
|
},
|
|
37379
37428
|
run: (a, api2) => {
|
|
@@ -37396,7 +37445,7 @@ var aiTools = [
|
|
|
37396
37445
|
enabled: exports_external.boolean(),
|
|
37397
37446
|
threshold: exports_external.number().min(1).optional().describe("Top up when the AI balance is below this (IDR)"),
|
|
37398
37447
|
amount: exports_external.number().min(1).optional().describe("How much to top up each time (IDR)"),
|
|
37399
|
-
dryRun:
|
|
37448
|
+
dryRun: dryRun6
|
|
37400
37449
|
},
|
|
37401
37450
|
run: (a, api2) => api2.api("PUT", "/ai/auto-topup", {
|
|
37402
37451
|
body: { enabled: a.enabled, threshold: a.threshold, amount: a.amount },
|
|
@@ -37432,7 +37481,7 @@ var generalTools = [
|
|
|
37432
37481
|
];
|
|
37433
37482
|
|
|
37434
37483
|
// src/server.ts
|
|
37435
|
-
var VERSION = "0.5.
|
|
37484
|
+
var VERSION = "0.5.10";
|
|
37436
37485
|
var INSTRUCTIONS = `Helipod is a cloud platform (Indonesia): containers, managed Postgres databases, VPS, domains, email and an AI gateway, billed from a prepaid wallet in Rupiah.
|
|
37437
37486
|
- Start with list_projects to find projects and environment ids. Account tools (get_wallet, invoices, statements, notifications, get_project_activity, support tickets) cover the account; AI tools (list_ai_models, get_ai_overview, get_ai_usage, AI keys, top-ups, generate_ai_image) cover the AI gateway.
|
|
37438
37487
|
- Anything that costs money (create/deploy/scale services, resize volumes, upgrade a database plan, create/renew/upgrade VPS, VPS backups, register/renew/transfer domains, email plans and inbox add-ons, AI top-ups and auto top-up, generating images): call it with dryRun=true first (or the price lookup when it has no dry run), tell the user the cost in IDR and the wallet balance after, and wait for an explicit yes before the real call. Never treat silence or an earlier general OK as a yes.
|
|
@@ -37442,9 +37491,10 @@ var INSTRUCTIONS = `Helipod is a cloud platform (Indonesia): containers, managed
|
|
|
37442
37491
|
- Databases: get_database_connection returns a password; put it in a secret variable (DATABASE_URL) instead of code or chat.
|
|
37443
37492
|
- Migrate (free): create_vps_import returns a one-time command for the USER to run as root on their old server (never run it yourself); before the first restore_vps_import, show fetchedIp and ask the user to confirm it is their server.
|
|
37444
37493
|
- Images from generate_ai_image are deleted after 7 days: tell the user and have them download the ones they keep.
|
|
37494
|
+
- Deploying from Git: public repos need nothing. For a private repo check get_git_connections / list_git_repos first; when GitHub or GitLab is not connected (or a call returns 409 GITHUB_NOT_CONNECTED / GITLAB_NOT_CONNECTED / REPO_NOT_ACCESSIBLE), give the user details.connectUrl to open in their browser and try again after they confirm. Never ask for a GitHub token.
|
|
37445
37495
|
- Deploys and VPS actions run in the background: poll get_deployment / get_vps until they settle; on a failed deploy read get_deployment_logs.
|
|
37446
37496
|
- Never print secrets (passwords, secret variable values, secret files) unless the user asks for them. Domain owner details are personal data: use only what the user gave.
|
|
37447
|
-
- Errors come back as { status, code, error }: 401/403 means the key lacks access (keys choose products and projects in Settings → API keys; wallet, invoices, tickets and AI money need a whole-account key: with a sign-in, reconnect and choose Whole account), 402 means plan limit or low balance.
|
|
37497
|
+
- Errors come back as { status, code, error, details? }: 401/403 means the key lacks access (keys choose products and projects in Settings → API keys; wallet, invoices, tickets and AI money need a whole-account key: with a sign-in, reconnect and choose Whole account), 402 means plan limit or low balance.
|
|
37448
37498
|
Docs: https://docs.helipod.io`;
|
|
37449
37499
|
var ALL_TOOLS = [...containerTools, ...databaseTools, ...vpsTools, ...domainTools, ...emailTools, ...accountTools, ...aiTools, ...generalTools];
|
|
37450
37500
|
function createHelipodServer(config2) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helipod-mcp",
|
|
3
3
|
"mcpName": "io.helipod/helipod",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.10",
|
|
5
5
|
"description": "MCP server for Helipod: containers, databases, VPS, domains and email from Claude Code, Codex, Cursor and other AI tools.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|