hostinger-api-mcp 3.24.1 → 3.24.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 (45) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/gemini-extension.json +1 -1
  3. package/package.json +1 -1
  4. package/server.json +2 -2
  5. package/skills/headless/SKILL.md +16 -0
  6. package/skills/headless/VERSION +3 -0
  7. package/skills/headless/connect/SKILL.md +15 -2
  8. package/skills/headless/connect/tools/antigravity.md +6 -4
  9. package/skills/headless/connect/tools/claude-code.md +2 -2
  10. package/skills/headless/connect/tools/codex.md +6 -4
  11. package/skills/headless/connect/tools/cursor.md +6 -4
  12. package/skills/headless/connect/tools/devin.md +6 -4
  13. package/skills/headless/connect/tools/vscode.md +6 -4
  14. package/skills/headless/run-log.mjs +2 -1
  15. package/skills/headless/steps/03-provision/SKILL.md +21 -0
  16. package/skills/headless/steps/03-provision/webapp/SKILL.md +7 -1
  17. package/skills/headless/steps/08-deploy/SKILL.md +13 -5
  18. package/src/core/skills.js +36 -36
  19. package/src/core/skills.ts +36 -36
  20. package/src/servers/agency-hosting.js +1 -1
  21. package/src/servers/agency-hosting.ts +1 -1
  22. package/src/servers/agent-readiness.js +1 -1
  23. package/src/servers/agent-readiness.ts +1 -1
  24. package/src/servers/all.js +1 -1
  25. package/src/servers/all.ts +1 -1
  26. package/src/servers/billing.js +1 -1
  27. package/src/servers/billing.ts +1 -1
  28. package/src/servers/dns.js +1 -1
  29. package/src/servers/dns.ts +1 -1
  30. package/src/servers/domains.js +1 -1
  31. package/src/servers/domains.ts +1 -1
  32. package/src/servers/ecommerce.js +1 -1
  33. package/src/servers/ecommerce.ts +1 -1
  34. package/src/servers/horizons.js +1 -1
  35. package/src/servers/horizons.ts +1 -1
  36. package/src/servers/hosting.js +1 -1
  37. package/src/servers/hosting.ts +1 -1
  38. package/src/servers/mail.js +1 -1
  39. package/src/servers/mail.ts +1 -1
  40. package/src/servers/reach.js +1 -1
  41. package/src/servers/reach.ts +1 -1
  42. package/src/servers/vps.js +1 -1
  43. package/src/servers/vps.ts +1 -1
  44. package/src/servers/wordpress.js +1 -1
  45. package/src/servers/wordpress.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ Generated at release time from the diff between the previous and current
4
4
  build. Tool changes are listed individually; everything else is summarised
5
5
  by area.
6
6
 
7
+ ## v3.24.2 — 2026-11-03
8
+
9
+ ### Also in this release
10
+
11
+ - Dependencies: `package-lock.json`
12
+ - Bundled agent skills: 13 files
13
+ - Other files: `src/core/skills.js`, `src/core/skills.ts`
14
+
7
15
  ## v3.24.1 — 2026-10-30
8
16
 
9
17
  ### Also in this release
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.24.1",
3
+ "version": "3.24.2",
4
4
  "description": "Hostinger API — manage domains, DNS, hosting, VPS, billing and more from Gemini CLI.",
5
5
  "mcpServers": {
6
6
  "hostinger": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.24.1",
3
+ "version": "3.24.2",
4
4
  "mcpName": "io.github.hostinger/hostinger-api-mcp",
5
5
  "description": "MCP server for Hostinger API",
6
6
  "repository": {
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/hostinger/api-mcp-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.24.1",
9
+ "version": "3.24.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@hostinger/mcp",
14
- "version": "3.24.1",
14
+ "version": "3.24.2",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -141,6 +141,22 @@ written in English, sets the site's language (refine records it with the must-ha
141
141
  stay in English. When the latest message gives nothing to go by (a "yes", a link, only pasted text),
142
142
  keep the language you were using.
143
143
 
144
+ ### One instance per headless site (the core invariant)
145
+
146
+ > **A headless site is exactly one website.** The frontend is served at the site root and WordPress
147
+ > lives at `/cms` **on the same domain** — one instance, one domain. There is **never** a second
148
+ > website for the same build and **never** a separate CMS domain: the CMS is always the `/cms` path of
149
+ > the site's own domain (`https://<domain>/cms`), not `cms.<domain>` or any other host. Provision
150
+ > therefore **adopts and swaps** an existing headless shell rather than creating another site, and a
151
+ > headless frontend is always deployed as a Node.js app (`type: "nodejs"`) — **never** `type: "static"`,
152
+ > which serves the build as plain files over the document root and overwrites `/cms`.
153
+ >
154
+ > The deleted legacy flow that put WordPress on a separate `cms.<domain>` subdomain with a
155
+ > `type:"static"` frontend on the main domain (two instances, recorded as `cms_domain` + `type:"static"`
156
+ > in `site.json`) is **gone and forbidden**. If you ever see `cms_domain` or `type:"static"` in a
157
+ > workspace's `site.json`, you are running a stale/legacy skill copy — stop and re-pull the latest skills
158
+ > (see `connect/SKILL.md`) before continuing.
159
+
144
160
  ### Background provision & the instance barrier
145
161
 
146
162
  **Provision always runs — what it does depends on what the domain already has.** Often onboarding on
@@ -0,0 +1,3 @@
1
+ version=3.24.2
2
+ commit=5297fe2d84a8
3
+ built=2026-11-03
@@ -88,13 +88,24 @@ Credentials live in `~/.config/hostinger-mcp/credentials.json` (macOS/Linux) or
88
88
  If the user's tool isn't listed yet, connect it the generic way (register the Hostinger MCP server
89
89
  for that tool, or drive `npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp` over stdio) and continue.
90
90
 
91
+ ### Always pull the latest skills (never run a stale copy)
92
+
93
+ The tool route above downloads the `headless/` skill bundle. **Do this at the start of every run and let
94
+ it overwrite any existing local `headless/` folder** — a build must never run on a stale copy, because an
95
+ outdated local bundle is how a deleted, legacy flow (e.g. a separate CMS domain + a `type:"static"`
96
+ frontend — two instances) ends up executing. The bundle ships a `headless/VERSION` stamp
97
+ (`version=<semver>` on line 1, then `commit` and `built`). After pulling, read it; if you want to confirm
98
+ it is current, compare line 1 against the published marker at
99
+ `https://raw.githubusercontent.com/hostinger/api-mcp-server/main/skills/headless/VERSION` and re-pull if
100
+ they differ. Carry the version into `connect.json` (Phase 3) so the build report records which skills ran.
101
+
91
102
  ## Phase 3 - Write `connect.json`
92
103
 
93
104
  Once the tool is connected, write `~/.hostinger/<domain>/connect.json` (create the folder if it is
94
105
  missing) in exactly this shape:
95
106
 
96
107
  ```json
97
- { "tool": "claude-code", "mcp": "hostinger-api-mcp 3.8.0", "auth": "oauth_cached",
108
+ { "tool": "claude-code", "mcp": "hostinger-api-mcp 3.8.0", "skills": "3.9.0", "auth": "oauth_cached",
98
109
  "order_id": null, "plan": null, "connected_at": "2026-10-28T10:46:12Z" }
99
110
  ```
100
111
 
@@ -103,11 +114,13 @@ missing) in exactly this shape:
103
114
  passed to `run-start --tool`.
104
115
  - `mcp`: one string, `hostinger-api-mcp <version>`, with the `version` from the `mcp_ok` event.
105
116
  Never an object.
117
+ - `skills`: the `version=` value from the `headless/VERSION` stamp you just pulled — the skills bundle
118
+ version this run used. `"unknown"` if the stamp is absent (an old bundle predating the stamp).
106
119
  - `auth`: the `method` from the `logged_in` event (`api_token`, `oauth_cached` or `oauth`).
107
120
  - `order_id`, `plan`: the active hosting plan's order id and name when you looked them up, else `null`.
108
121
  - `connected_at`: the current time in UTC, ISO 8601 to the second.
109
122
 
110
- Extra keys are allowed, but keep these six as above: the build report reads `tool` and `mcp`.
123
+ Extra keys are allowed, but keep these seven as above: the build report reads `tool`, `mcp` and `skills`.
111
124
 
112
125
  ## Phase 4 - Continue to Headless Hosting steps
113
126
 
@@ -41,9 +41,11 @@ quit and reopen Antigravity once so it loads:
41
41
 
42
42
  ## Step 2 — Install the skills and hand off
43
43
 
44
- Download the Hostinger skills locally so your agent reads the files directly with no further network
45
- calls. The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials (see
46
- `connect/tools/claude-code.md` for the full tarball command):
44
+ Download the Hostinger skills locally **at the start of every run** so your agent then reads the files
45
+ directly with no further network calls during the run. **Always pull the latest and overwrite any
46
+ existing local `headless/` copy** so a run never uses a stale skill version. The repo is **public**, so
47
+ fetch just the skill folder over HTTPS — no git, no credentials (see `connect/tools/claude-code.md` for
48
+ the full tarball command):
47
49
 
48
50
  ```bash
49
51
  # macOS/Linux — downloads only skills/headless from the public repo
@@ -51,4 +53,4 @@ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/head
51
53
  | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
52
54
  ```
53
55
 
54
- Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
56
+ Then read the `headless/VERSION` stamp (record it in `connect.json`), open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -26,7 +26,7 @@ process alive for the whole run, and use it wherever a stage calls the connector
26
26
 
27
27
  ## Step 2 — Install the skills and hand off
28
28
 
29
- Download the Hostinger skills locally so your agent reads the files directly with no further network calls. The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials:
29
+ Download the Hostinger skills locally **at the start of every run** so your agent then reads the files directly with no further network calls during the run. **Always pull the latest and let it overwrite any existing local `headless/` folder** — a build must never run on a stale skill copy (an outdated local copy is how a deleted, legacy flow ends up executing). The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials:
30
30
 
31
31
  ```bash
32
32
  # macOS/Linux — downloads only skills/headless from the public repo
@@ -40,7 +40,7 @@ curl.exe -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/
40
40
  tar -xf headless-skill.tar.gz --strip-components=2 'api-mcp-server-main/skills/headless'
41
41
  ```
42
42
 
43
- This leaves a local `headless/` folder with the full skill set. If the tarball is ever blocked, browse the public folder at `https://github.com/hostinger/api-mcp-server/tree/main/skills/headless` and save each file under a local `headless/` directory, preserving the paths.
43
+ This leaves a local `headless/` folder with the full skill set. The bundle carries a `headless/VERSION` stamp (`version=<semver>`, commit, build date) — after pulling, read it and tell the user which skills version this run uses; it is the value to record in `connect.json`. If the tarball is ever blocked, browse the public folder at `https://github.com/hostinger/api-mcp-server/tree/main/skills/headless` and save each file under a local `headless/` directory, preserving the paths.
44
44
 
45
45
  Then open `headless/SKILL.md` and follow the steps on it. That skill owns the rest of the run — it resolves the operations sequence.
46
46
 
@@ -35,9 +35,11 @@ args = ["-y", "@hostinger/mcp@latest"]
35
35
 
36
36
  ## Step 2 — Install the skills and hand off
37
37
 
38
- Download the Hostinger skills locally so your agent reads the files directly with no further network
39
- calls. The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials (see
40
- `connect/tools/claude-code.md` for the full tarball command):
38
+ Download the Hostinger skills locally **at the start of every run** so your agent then reads the files
39
+ directly with no further network calls during the run. **Always pull the latest and overwrite any
40
+ existing local `headless/` copy** so a run never uses a stale skill version. The repo is **public**, so
41
+ fetch just the skill folder over HTTPS — no git, no credentials (see `connect/tools/claude-code.md` for
42
+ the full tarball command):
41
43
 
42
44
  ```bash
43
45
  # macOS/Linux — downloads only skills/headless from the public repo
@@ -45,4 +47,4 @@ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/head
45
47
  | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
46
48
  ```
47
49
 
48
- Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
50
+ Then read the `headless/VERSION` stamp (record it in `connect.json`), open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -96,9 +96,11 @@ and speak newline-delimited JSON-RPC 2.0 over its stdin/stdout (`initialize` →
96
96
 
97
97
  ## Step 4 — Install the skills and hand off
98
98
 
99
- Download the Hostinger skills locally so your agent reads the files directly with no further network
100
- calls. The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials (see
101
- `connect/tools/claude-code.md` for the full tarball command):
99
+ Download the Hostinger skills locally **at the start of every run** so your agent then reads the files
100
+ directly with no further network calls during the run. **Always pull the latest and overwrite any
101
+ existing local `headless/` copy** so a run never uses a stale skill version. The repo is **public**, so
102
+ fetch just the skill folder over HTTPS — no git, no credentials (see `connect/tools/claude-code.md` for
103
+ the full tarball command):
102
104
 
103
105
  ```bash
104
106
  # macOS/Linux — downloads only skills/headless from the public repo
@@ -106,4 +108,4 @@ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/head
106
108
  | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
107
109
  ```
108
110
 
109
- Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
111
+ Then read the `headless/VERSION` stamp (record it in `connect.json`), open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -37,9 +37,11 @@ over stdio instead: spawn it and speak newline-delimited JSON-RPC 2.0 over its s
37
37
 
38
38
  ## Step 2 — Install the skills and hand off
39
39
 
40
- Download the Hostinger skills locally so your agent reads the files directly with no further network
41
- calls. The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials (see
42
- `connect/tools/claude-code.md` for the full tarball command):
40
+ Download the Hostinger skills locally **at the start of every run** so your agent then reads the files
41
+ directly with no further network calls during the run. **Always pull the latest and overwrite any
42
+ existing local `headless/` copy** so a run never uses a stale skill version. The repo is **public**, so
43
+ fetch just the skill folder over HTTPS — no git, no credentials (see `connect/tools/claude-code.md` for
44
+ the full tarball command):
43
45
 
44
46
  ```bash
45
47
  # macOS/Linux — downloads only skills/headless from the public repo
@@ -47,4 +49,4 @@ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/head
47
49
  | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
48
50
  ```
49
51
 
50
- Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
52
+ Then read the `headless/VERSION` stamp (record it in `connect.json`), open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -44,9 +44,11 @@ over stdio instead: spawn it and speak newline-delimited JSON-RPC 2.0 over its s
44
44
 
45
45
  ## Step 2 — Install the skills and hand off
46
46
 
47
- Download the Hostinger skills locally so your agent reads the files directly with no further network
48
- calls. The repo is **public**, so fetch just the skill folder over HTTPS — no git, no credentials (see
49
- `connect/tools/claude-code.md` for the full tarball command):
47
+ Download the Hostinger skills locally **at the start of every run** so your agent then reads the files
48
+ directly with no further network calls during the run. **Always pull the latest and overwrite any
49
+ existing local `headless/` copy** so a run never uses a stale skill version. The repo is **public**, so
50
+ fetch just the skill folder over HTTPS — no git, no credentials (see `connect/tools/claude-code.md` for
51
+ the full tarball command):
50
52
 
51
53
  ```bash
52
54
  # macOS/Linux — downloads only skills/headless from the public repo
@@ -54,4 +56,4 @@ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/head
54
56
  | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
55
57
  ```
56
58
 
57
- Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
59
+ Then read the `headless/VERSION` stamp (record it in `connect.json`), open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -129,7 +129,7 @@ function readConnect(ws) {
129
129
  const mcp = connect.mcp ?? connect.mcp_version ?? null;
130
130
  let version = mcp;
131
131
  if (mcp !== null && typeof mcp !== 'string') version = mcp.name || mcp.version ? [mcp.name, mcp.version].filter(Boolean).join(' ') : JSON.stringify(mcp);
132
- return { tool: typeof connect.tool === 'string' ? connect.tool : null, mcp: version };
132
+ return { tool: typeof connect.tool === 'string' ? connect.tool : null, mcp: version, skills: typeof connect.skills === 'string' ? connect.skills : null };
133
133
  }
134
134
 
135
135
  function runStart(ws, flags) {
@@ -348,6 +348,7 @@ function buildReport(ws, { outcome, tokens } = {}) {
348
348
  os: process.platform,
349
349
  node: process.version,
350
350
  mcp: connect.mcp,
351
+ skills: connect.skills,
351
352
  backend: site.backend ?? null,
352
353
  frontend: frontendStack(state.frontend ?? {}, ws.dir),
353
354
  outcome: resolvedOutcome,
@@ -77,6 +77,13 @@ So provision has **two entry shapes**, and each subfolder's *detect* step picks
77
77
  > flow — it is only triggered by experimental actions — so it **ignores headless instances entirely**:
78
78
  > it never detects, adopts or swaps an empty headless shell, and provisions its own **Node.js app host**
79
79
  > exactly as `webapp/SKILL.md` defines today. The swap below is **WordPress and Ecommerce only**.
80
+ >
81
+ > **But webapp must still never create a second instance for this build.** Only route here when the
82
+ > brief's backend is `webapp` — a `wordpress` or `ecommerce` brief is never provisioned as a webapp. And
83
+ > if this build's domain already has a headless shell/site (an onboarding `headless_empty`, or any row
84
+ > from the single-instance gate below), **do not** spin up a separate Node.js host on another domain:
85
+ > stop and tell the user the domain already has a headless instance, rather than leaving the build split
86
+ > across two sites.
80
87
 
81
88
  **How to tell an empty shell from an already-provisioned backend** (both read `website_type: headless`):
82
89
 
@@ -96,6 +103,20 @@ asynchronous — fire it, record `provision.in_progress`, and join at the barrie
96
103
 
97
104
  ## Step 2 — Fire (don't block)
98
105
 
106
+ > **Single-instance gate — pass all four before you create anything:**
107
+ > 1. **Exact-match the domain** in `hosting_websites_list` (substring filter — match the exact `domain`).
108
+ > 2. **A `headless` row already exists → adopt + swap it, never create.** Install the backend into that
109
+ > same site (WordPress → `wordpress_installations_install { type: "headless" }` into `/cms`; Ecommerce
110
+ > → adopt as the storefront host). **Do not call `start-setup` again** — that makes a second site.
111
+ > 3. **No row at all → create one fresh** with the backend's own `start-setup` type. Create it for **this
112
+ > build's domain only** — never provision the backend on a different domain than the frontend (the CMS
113
+ > is the `/cms` path of the same site, never a separate `cms.<domain>`).
114
+ > 4. **A row of a different kind** (`website_type` not `headless`) → **stop and tell the user**; never
115
+ > overwrite it.
116
+ >
117
+ > This is the whole of *Onboarding handoff* above, as one checklist. See it for how to tell an empty
118
+ > shell from an already-provisioned backend.
119
+
99
120
  Follow the chosen subfolder's `SKILL.md` through **detect + create** (its "start-setup" call). The
100
121
  moment the create is accepted and queued, record it in `state.json` and **return** — do not sit on the
101
122
  readiness poll:
@@ -31,7 +31,13 @@ All website/database operations below go through the Hostinger connector (`execu
31
31
  - `running` → skip to Step 2 (poll).
32
32
  - `failed` → tell the user and point them at hPanel; do **not** call start-setup again on your own.
33
33
  3. If the site exists but is a different kind (`website_type` is `headless`, or a WordPress/store site),
34
- stop and tell the user — this domain already hosts something else.
34
+ stop and tell the user — this domain already hosts something else. **Never create a second site.**
35
+ 4. **Only provision a webapp for a `webapp` brief.** A `wordpress` or `ecommerce` brief belongs in those
36
+ subfolders (installed into one headless instance's `/cms`) — never spin up a separate Node.js host for
37
+ it. And if this build already has a headless shell/site (a recorded `site.json → website_type:
38
+ "headless"`, or a `headless`/`headless_empty` row for the project's domain), do **not** create a new
39
+ website on another domain: stop and tell the user, so the build never ends up split across two
40
+ instances.
35
41
 
36
42
  ## Step 2 — Create (only when nothing exists)
37
43
 
@@ -124,7 +124,8 @@ build output must already be absent).
124
124
 
125
125
  `hosting_deploy` uploads the source and triggers `npm install` + the build **end-to-end** — do not call
126
126
  any upload or build operation yourself. It returns a build `buildUuid` at once. This **overwrites the
127
- website root** (expected) and keeps `/cms` intact. Passing `appType`/`outputDirectory` explicitly is what
127
+ website root** (expected) and keeps `/cms` intact. `type` is always `"nodejs"` for a headless site —
128
+ **never `"static"`** (see the gate below). Passing `appType`/`outputDirectory` explicitly is what
128
129
  keeps the root from serving 403 (see the rule above).
129
130
 
130
131
  ## Step 4 — Poll to completion
@@ -199,10 +200,17 @@ Update `state.json` (`stage` → `done`), then continue to Step 9 (done).
199
200
 
200
201
  ---
201
202
 
202
- ## Note — one deploy path, and never `type: "static"`
203
+ ## Gate — a headless deploy is always `type: "nodejs"`, never `type: "static"`
204
+
205
+ **Hard rule, check it before every deploy:** a headless site is deployed **only** with
206
+ `type: "nodejs"` plus the explicit `appType`/`outputDirectory`/`nodeVersion`/`buildScript`/
207
+ `packageManager`/`rootDirectory` from the table. **Never pass `type: "static"` on a headless site** — it
208
+ serves the build as plain files over the document root and **overwrites `/cms`**, destroying the
209
+ WordPress backend (this is the "accidentally cleared cms" failure). A static-built SPA (Vite/React/Vue)
210
+ still deploys as `type: "nodejs"` with its `appType` — the framework's static output is served correctly
211
+ that way, and `/cms` is preserved. If a flow ever tells you to deploy a headless site as `type:
212
+ "static"`, you are on a stale/legacy skill copy — stop and re-pull the latest skills.
203
213
 
204
214
  `hosting_deploy` on the local server is the only path: give its `path` either the source **directory** (it archives it for
205
215
  you) or a local **archive** (`zip`, `tar`, `tar.gz`, `tgz`, `7z`) — there is no separate upload or build
206
- step to fall back to. Either way pass the explicit `appType`/`outputDirectory`/`nodeVersion`/
207
- `buildScript`/`packageManager`/`rootDirectory` from the table. Never deploy a headless site with
208
- `type: "static"` — it serves the directory as plain files and can overwrite `/cms`.
216
+ step to fall back to.