hostinger-api-mcp 3.30.0 → 3.30.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +4 -1
  3. package/gemini-extension.json +2 -1
  4. package/package.json +1 -1
  5. package/server.json +2 -2
  6. package/skills/headless/SKILL.md +7 -5
  7. package/skills/headless/VERSION +3 -3
  8. package/skills/headless/connect/SKILL.md +34 -10
  9. package/skills/headless/connect/bootstrap.mjs +25 -14
  10. package/skills/headless/connect/launch.mjs +42 -0
  11. package/skills/headless/connect/launch.sh +23 -0
  12. package/skills/headless/connect/tools/antigravity.md +5 -5
  13. package/skills/headless/connect/tools/claude-code.md +3 -3
  14. package/skills/headless/connect/tools/codex.md +7 -7
  15. package/skills/headless/connect/tools/cursor.md +9 -9
  16. package/skills/headless/connect/tools/devin.md +5 -5
  17. package/skills/headless/connect/tools/vscode.md +7 -7
  18. package/skills/headless/hostinger-mcp.mjs +4 -9
  19. package/skills/headless/steps/03-provision/ecommerce/SKILL.md +2 -2
  20. package/skills/headless/steps/03-provision/webapp/SKILL.md +1 -1
  21. package/skills/headless/steps/03-provision/wordpress/SKILL.md +2 -2
  22. package/skills/headless/steps/04-content-model/wordpress/SKILL.md +1 -1
  23. package/skills/headless/steps/08-deploy/SKILL.md +3 -3
  24. package/src/core/oauth.js +14 -4
  25. package/src/core/oauth.ts +14 -4
  26. package/src/core/runtime.js +6 -0
  27. package/src/core/runtime.ts +6 -0
  28. package/src/core/skills.js +59 -45
  29. package/src/core/skills.ts +59 -45
  30. package/src/servers/agency-hosting.js +1 -1
  31. package/src/servers/agency-hosting.ts +1 -1
  32. package/src/servers/agent-readiness.js +1 -1
  33. package/src/servers/agent-readiness.ts +1 -1
  34. package/src/servers/all.js +1 -1
  35. package/src/servers/all.ts +1 -1
  36. package/src/servers/billing.js +1 -1
  37. package/src/servers/billing.ts +1 -1
  38. package/src/servers/dns.js +1 -1
  39. package/src/servers/dns.ts +1 -1
  40. package/src/servers/domains.js +1 -1
  41. package/src/servers/domains.ts +1 -1
  42. package/src/servers/ecommerce.js +1 -1
  43. package/src/servers/ecommerce.ts +1 -1
  44. package/src/servers/gpu.js +1 -1
  45. package/src/servers/gpu.ts +1 -1
  46. package/src/servers/horizons.js +1 -1
  47. package/src/servers/horizons.ts +1 -1
  48. package/src/servers/hosting.js +1 -1
  49. package/src/servers/hosting.ts +1 -1
  50. package/src/servers/mail.js +1 -1
  51. package/src/servers/mail.ts +1 -1
  52. package/src/servers/reach.js +1 -1
  53. package/src/servers/reach.ts +1 -1
  54. package/src/servers/vps.js +1 -1
  55. package/src/servers/vps.ts +1 -1
  56. package/src/servers/wordpress.js +1 -1
  57. package/src/servers/wordpress.ts +1 -1
@@ -64,7 +64,7 @@ All operations below go through the Hostinger connector (`execute`).
64
64
  (if `<new>/` already exists, stop and ask instead of moving into it),
65
65
  update the domain in `brief.md`, and tell the user the new domain.
66
66
  Admin credentials are generated by the platform; never ask the user for a password.
67
- 3. Don't wait here. At the join, `node <skill>/wait.mjs setup <domain>` (see *Waiting on Hostinger* in
67
+ 3. Don't wait here. At the join, `cd "$HOME" && node <skill>/wait.mjs setup <domain>` (see *Waiting on Hostinger* in
68
68
  the top-level `SKILL.md`) returns once the setup is `completed`, usually at once by then. A `failed`
69
69
  setup → stop, point at hPanel.
70
70
 
@@ -95,7 +95,7 @@ install WordPress straight into its `/cms` directory. This is the onboarding han
95
95
  generated database counts against the plan's limit.
96
96
  3. The call is **asynchronous** — a success response only means the install job was **queued**. This is
97
97
  the *fire*: record `provision.in_progress` and return to prepare work. At the join,
98
- `node <skill>/wait.mjs cms <domain> <username>` returns the `/cms` install row (`directory: "cms"`,
98
+ `cd "$HOME" && node <skill>/wait.mjs cms <domain> <username>` returns the `/cms` install row (`directory: "cms"`,
99
99
  valid) once it exists, usually within 1–2 minutes of the install.
100
100
 
101
101
  ## Step 3 — Verify (all must pass)
@@ -78,7 +78,7 @@ else is refused, with the field named.
78
78
  ## Step 2 — Run the push
79
79
 
80
80
  ```bash
81
- node <skill>/push-content.mjs <domain>
81
+ cd "$HOME" && node <skill>/push-content.mjs <domain>
82
82
  ```
83
83
 
84
84
  It mints the token itself (never printed), removes WordPress's "Hello world!" post and "Sample Page",
@@ -15,13 +15,13 @@ This is an **instance-barrier** step: run it only after `provision.status == "co
15
15
  > **Connected to the hosted server (`mcp.hostinger.com`)?** Its `hosting_deploy` deploys Git
16
16
  > repositories only and cannot read a local `path`. Run this step through the local
17
17
  > `hostinger-api-mcp` server instead (see the connect step:
18
- > `npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp`).
18
+ > `<command> <launcher>`).
19
19
 
20
20
  > **With a shell and the Hostinger CLI installed**, the same deploy is one command, with the build
21
21
  > settings passed exactly as the table below says. Run it from the project, since it links the current directory:
22
22
  > `cd ~/.hostinger/<domain>/src && hostinger up --domain <domain> --type nodejs --app-type <appType> --output-directory <dir> --build-script build --node-version 22 --package-manager npm --yes --format json`.
23
23
  > It uploads, builds, waits and returns `data.buildUuid` and `data.buildState`; add `--no-wait` to
24
- > return at once and wait with `node <skill>/wait.mjs build <domain> <uuid>`. Then continue at
24
+ > return at once and wait with `cd "$HOME" && node <skill>/wait.mjs build <domain> <uuid>`. Then continue at
25
25
  > "Verify" below. Recent CLI versions see that the site is headless (`data.headless: true`) and
26
26
  > deploy only its Node.js frontend, leaving `/cms` alone; still pass the settings above.
27
27
 
@@ -156,7 +156,7 @@ keeps the root from serving 403 (see the rule above).
156
156
  Wait for it in one command (see *Waiting on Hostinger* in the top-level `SKILL.md`):
157
157
 
158
158
  ```bash
159
- node <skill>/wait.mjs build <domain> <buildUuid>
159
+ cd "$HOME" && node <skill>/wait.mjs build <domain> <buildUuid>
160
160
  ```
161
161
 
162
162
  It waits for `hosting_get-deployment` to report the build `completed`, then for `https://<domain>/` to
package/src/core/oauth.js CHANGED
@@ -85,11 +85,21 @@ function parseIssuer(raw) {
85
85
  return u.origin;
86
86
  }
87
87
 
88
+ // Keeps the absolute PATH entries outside any node_modules folder. npx run in a project puts its
89
+ // node_modules/.bin (and each parent's) first on PATH, and a relative entry resolves against the project,
90
+ // so either would let the project supply xdg-open.
91
+ export function safePath(value, delimiter = path.delimiter) {
92
+ return value
93
+ .split(delimiter)
94
+ .filter((p) => path.isAbsolute(p) && !p.split(/[\\/]/).includes("node_modules"))
95
+ .join(delimiter);
96
+ }
97
+
88
98
  // No shell: the URL is a single argv entry, never parsed by sh or cmd.
89
- // Windows resolves a bare program name from the working directory before PATH,
90
- // so rundll32 is launched by absolute path to never pick up a planted copy.
99
+ // rundll32 and macOS open are launched by absolute path, so neither a PATH entry nor (on Windows,
100
+ // which looks a bare name up in the working directory first) a planted copy can stand in for them.
91
101
  export function browserCommand(platform, url, systemRoot = process.env.SystemRoot) {
92
- if (platform === "darwin") return ["open", [url]];
102
+ if (platform === "darwin") return ["/usr/bin/open", [url]];
93
103
  if (platform === "win32") {
94
104
  return [
95
105
  path.win32.join(systemRoot || "C:\\Windows", "System32", "rundll32.exe"),
@@ -435,7 +445,7 @@ export class OAuthProvider {
435
445
  "[OAuth] If the browser does not open, copy the URL above into one manually.\n\n",
436
446
  );
437
447
  const [cmd, args] = browserCommand(process.platform, url);
438
- execFile(cmd, args, (err) => {
448
+ execFile(cmd, args, { cwd: os.homedir(), env: { ...process.env, PATH: safePath(process.env.PATH ?? "") } }, (err) => {
439
449
  if (err) {
440
450
  process.stderr.write(
441
451
  `[OAuth] Could not auto-launch browser: ${err.message}\n`,
package/src/core/oauth.ts CHANGED
@@ -88,11 +88,21 @@ function parseIssuer(raw: string): string {
88
88
  return u.origin;
89
89
  }
90
90
 
91
+ // Keeps the absolute PATH entries outside any node_modules folder. npx run in a project puts its
92
+ // node_modules/.bin (and each parent's) first on PATH, and a relative entry resolves against the project,
93
+ // so either would let the project supply xdg-open.
94
+ export function safePath(value: string, delimiter: string = path.delimiter): string {
95
+ return value
96
+ .split(delimiter)
97
+ .filter((p) => path.isAbsolute(p) && !p.split(/[\\/]/).includes('node_modules'))
98
+ .join(delimiter);
99
+ }
100
+
91
101
  // No shell: the URL is a single argv entry, never parsed by sh or cmd.
92
- // Windows resolves a bare program name from the working directory before PATH,
93
- // so rundll32 is launched by absolute path to never pick up a planted copy.
102
+ // rundll32 and macOS open are launched by absolute path, so neither a PATH entry nor (on Windows,
103
+ // which looks a bare name up in the working directory first) a planted copy can stand in for them.
94
104
  export function browserCommand(platform: string, url: string, systemRoot = process.env.SystemRoot): [string, string[]] {
95
- if (platform === 'darwin') return ['open', [url]];
105
+ if (platform === 'darwin') return ['/usr/bin/open', [url]];
96
106
  if (platform === 'win32') {
97
107
  return [
98
108
  path.win32.join(systemRoot || 'C:\\Windows', 'System32', 'rundll32.exe'),
@@ -396,7 +406,7 @@ export class OAuthProvider {
396
406
  process.stderr.write(`\n[OAuth] Opening browser for sign-in:\n ${url}\n`);
397
407
  process.stderr.write('[OAuth] If the browser does not open, copy the URL above into one manually.\n\n');
398
408
  const [cmd, args] = browserCommand(process.platform, url);
399
- execFile(cmd, args, (err) => {
409
+ execFile(cmd, args, { cwd: os.homedir(), env: { ...process.env, PATH: safePath(process.env.PATH ?? '') } }, (err) => {
400
410
  if (err) {
401
411
  process.stderr.write(`[OAuth] Could not auto-launch browser: ${err.message}\n`);
402
412
  }
@@ -4109,6 +4109,12 @@ class MCPServer {
4109
4109
  }
4110
4110
 
4111
4111
  export async function startServer({ name, version, tools, instructions, skills }) {
4112
+ // The headless skill's launcher starts this server from the home folder (npx run in the project would
4113
+ // put the project's node_modules/.bin first on PATH) and names the project here, so relative paths in
4114
+ // tool arguments still resolve against it. Everything that runs from PATH is resolved by now.
4115
+ if (process.env.MCP_PROJECT_DIR) {
4116
+ try { process.chdir(process.env.MCP_PROJECT_DIR); } catch { /* stay in the home folder */ }
4117
+ }
4112
4118
  const argv = minimist(process.argv.slice(2), {
4113
4119
  string: ['host'],
4114
4120
  boolean: ['stdio', 'http', 'help', 'version', 'login', 'logout'],
@@ -4170,6 +4170,12 @@ class MCPServer {
4170
4170
  }
4171
4171
 
4172
4172
  export async function startServer({ name, version, tools, instructions, skills }: { name: string; version: string; tools: OpenApiTool[]; instructions?: string; skills?: Skill[] }): Promise<void> {
4173
+ // The headless skill's launcher starts this server from the home folder (npx run in the project would
4174
+ // put the project's node_modules/.bin first on PATH) and names the project here, so relative paths in
4175
+ // tool arguments still resolve against it. Everything that runs from PATH is resolved by now.
4176
+ if (process.env.MCP_PROJECT_DIR) {
4177
+ try { process.chdir(process.env.MCP_PROJECT_DIR); } catch { /* stay in the home folder */ }
4178
+ }
4173
4179
  const argv = minimist(process.argv.slice(2), {
4174
4180
  string: ['host'],
4175
4181
  boolean: ['stdio', 'http', 'help', 'version', 'login', 'logout'],