@hostinger/mcp 3.2.2 → 3.3.1

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 (65) hide show
  1. package/CHANGELOG.md +14 -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 +245 -36
  6. package/skills/headless/connect/SKILL.md +98 -0
  7. package/skills/headless/{entry → connect}/bootstrap.mjs +8 -3
  8. package/skills/headless/connect/tools/antigravity.md +54 -0
  9. package/skills/headless/connect/tools/claude-code.md +46 -0
  10. package/skills/headless/connect/tools/codex.md +48 -0
  11. package/skills/headless/connect/tools/cursor.md +109 -0
  12. package/skills/headless/connect/tools/devin.md +50 -0
  13. package/skills/headless/connect/tools/vscode.md +57 -0
  14. package/skills/headless/report.schema.json +149 -0
  15. package/skills/headless/run-log.mjs +662 -0
  16. package/skills/headless/steps/01-check-state/SKILL.md +209 -0
  17. package/skills/headless/steps/02-refine/SKILL.md +273 -0
  18. package/skills/headless/steps/03-provision/SKILL.md +117 -0
  19. package/skills/headless/steps/03-provision/ecommerce/SKILL.md +142 -0
  20. package/skills/headless/steps/03-provision/webapp/SKILL.md +154 -0
  21. package/skills/headless/steps/03-provision/wordpress/SKILL.md +249 -0
  22. package/skills/headless/steps/04-content-model/SKILL.md +228 -0
  23. package/skills/headless/steps/04-content-model/ecommerce/SKILL.md +75 -0
  24. package/skills/headless/steps/04-content-model/wordpress/SKILL.md +223 -0
  25. package/skills/headless/steps/04-content-model/wordpress/woocommerce.md +153 -0
  26. package/skills/headless/steps/05-design/SKILL.md +464 -0
  27. package/skills/headless/steps/05-design/logo-kit.mjs +201 -0
  28. package/skills/headless/steps/06-frontend/SKILL.md +160 -0
  29. package/skills/headless/steps/07-validate/SKILL.md +56 -0
  30. package/skills/headless/steps/08-deploy/SKILL.md +179 -0
  31. package/skills/headless/steps/09-done/SKILL.md +157 -0
  32. package/src/core/skills.js +171 -24
  33. package/src/core/skills.ts +171 -24
  34. package/src/servers/agency-hosting.js +1 -1
  35. package/src/servers/agency-hosting.ts +1 -1
  36. package/src/servers/agent-readiness.js +1 -1
  37. package/src/servers/agent-readiness.ts +1 -1
  38. package/src/servers/all.js +1 -1
  39. package/src/servers/all.ts +1 -1
  40. package/src/servers/billing.js +1 -1
  41. package/src/servers/billing.ts +1 -1
  42. package/src/servers/dns.js +1 -1
  43. package/src/servers/dns.ts +1 -1
  44. package/src/servers/domains.js +1 -1
  45. package/src/servers/domains.ts +1 -1
  46. package/src/servers/ecommerce.js +1 -1
  47. package/src/servers/ecommerce.ts +1 -1
  48. package/src/servers/horizons.js +1 -1
  49. package/src/servers/horizons.ts +1 -1
  50. package/src/servers/hosting.js +1 -1
  51. package/src/servers/hosting.ts +1 -1
  52. package/src/servers/mail.js +1 -1
  53. package/src/servers/mail.ts +1 -1
  54. package/src/servers/reach.js +1 -1
  55. package/src/servers/reach.ts +1 -1
  56. package/src/servers/vps.js +1 -1
  57. package/src/servers/vps.ts +1 -1
  58. package/src/servers/wordpress.js +1 -1
  59. package/src/servers/wordpress.ts +1 -1
  60. package/skills/headless/entry/skill.md +0 -79
  61. package/skills/headless/references/DATABASE.md +0 -49
  62. package/skills/headless/references/DEPLOYMENT.md +0 -34
  63. package/skills/headless/references/SETUP.md +0 -35
  64. package/skills/headless/references/STORE.md +0 -52
  65. package/skills/headless/references/WORDPRESS.md +0 -51
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: headless-connect-codex
3
+ description: "Specific Codex Hostinger MCP Server connection instructions for the Hostinger Headless flow."
4
+ ---
5
+
6
+ ## Goals
7
+
8
+ - Make Hostinger MCP tools and Skills available in Codex.
9
+ - Don't provision hosting, create stores, install WordPress, or deploy by hand here — the skill does all of that. This entry stops at signed in and checking that Hostinger MCP and skills are reachable.
10
+
11
+ ## Step 1 — Make the connector callable (no restart needed)
12
+
13
+ The later stages drive the Hostinger connector. If its Hostinger tools already respond in this
14
+ session, use them and move on.
15
+
16
+ If they don't, **don't rely on registering the server and restarting** — Codex loads MCP servers when
17
+ it starts, and you can't restart it mid-run. The Hostinger MCP runs as a local **stdio** process and the
18
+ bootstrap already signed you in, so talk to it directly for this run: spawn `npx -y @hostinger/mcp@latest`
19
+ and speak newline-delimited JSON-RPC 2.0 over its stdin/stdout (`initialize` →
20
+ `notifications/initialized` → `tools/call`). It reuses your cached sign-in automatically
21
+ (`~/.config/hostinger-mcp/credentials.json`, or `HOSTINGER_API_TOKEN`) — no tokens to handle. It
22
+ exposes `search`, `execute`, `multi-execute`; everything the stages need goes through `execute`, and a
23
+ result is in `reply.result.content[0].text`. Write the little client yourself (~20 lines), keep one
24
+ process alive for the whole run, and use it wherever a stage calls the connector.
25
+
26
+ **To persist it for future Codex sessions** (optional), register the server with
27
+ `codex mcp add hostinger -- npx -y @hostinger/mcp@latest`, or add it to `~/.codex/config.toml`, then
28
+ restart Codex so it loads:
29
+
30
+ ```toml
31
+ [mcp_servers.hostinger]
32
+ command = "npx"
33
+ args = ["-y", "@hostinger/mcp@latest"]
34
+ ```
35
+
36
+ ## Step 2 — Install the skills and hand off
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):
41
+
42
+ ```bash
43
+ # macOS/Linux — downloads only skills/headless from the public repo
44
+ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/heads/main \
45
+ | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
46
+ ```
47
+
48
+ Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: headless-connect-cursor
3
+ description: "Specific Cursor Hostinger MCP Server connection instructions for the Hostinger Headless flow."
4
+ ---
5
+
6
+ ## Goals
7
+
8
+ - Install (or reach) the Hostinger MCP in Cursor.
9
+ - Sign the user in with OAuth 2.0 PKCE — the MCP opens a browser so they only need to log in.
10
+ - Don't provision hosting, create stores, install WordPress, or deploy by hand here — the skill does all of that. This entry stops at signed in and checking that Hostinger MCP and skills are reachable.
11
+
12
+ ## Step 1 — Install / reach Hostinger MCP
13
+
14
+ **Prerequisite:** Node.js 20 or newer on `PATH` (`node -v`). The published package engines require `>=20`; use Node 24 if you follow the package README.
15
+
16
+ The Hostinger MCP is the npm package `@hostinger/mcp`. You do **not** need a global install — Cursor (and this session) can run it through `npx`. Prefer the unified binary `hostinger-api-mcp` (every operation). Scoped binaries such as `hostinger-hosting-mcp` are optional.
17
+
18
+ ### Option A — no global install (recommended)
19
+
20
+ ```bash
21
+ # Verify the package/binary is reachable
22
+ npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp --version
23
+ ```
24
+
25
+ ### Option B — global install
26
+
27
+ ```bash
28
+ npm install -g @hostinger/mcp
29
+ # or: yarn global add @hostinger/mcp
30
+ # or: pnpm add -g @hostinger/mcp
31
+
32
+ hostinger-api-mcp --version
33
+ ```
34
+
35
+ ### Persist for future Cursor sessions (optional)
36
+
37
+ Register the server in `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global), then fully quit and reopen Cursor once so it loads. **Do not** put `HOSTINGER_API_TOKEN` in this file when you want OAuth — leave the token unset so stdio OAuth can run:
38
+
39
+ ```json
40
+ {
41
+ "mcpServers": {
42
+ "hostinger": {
43
+ "command": "npx",
44
+ "args": ["--yes", "--package=@hostinger/mcp@latest", "hostinger-api-mcp"]
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ If Hostinger MCP tools are already in this session (`mcp__hostinger__*` / `mcp__hostinger-*__*`), skip ahead to Step 2 only if you still need sign-in; otherwise go to Step 3.
51
+
52
+ ## Step 2 — Authenticate with OAuth (browser opens)
53
+
54
+ Prefer OAuth for interactive Cursor use. OAuth works only in **stdio** mode (Cursor's default for this local server). Skip this step if `HOSTINGER_API_TOKEN` is already set in the environment (that bypasses OAuth entirely).
55
+
56
+ If the connect bootstrap already emitted `logged_in` / `success`, credentials are already on disk — continue to Step 3.
57
+
58
+ Otherwise run the login command. It registers a dynamic OAuth client (once per machine), **opens the user's browser** to Hostinger's authorization page, listens on a localhost callback, stores tokens, and exits:
59
+
60
+ ```bash
61
+ npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp --login
62
+ ```
63
+
64
+ (With a global install: `hostinger-api-mcp --login`.)
65
+
66
+ What to tell the user:
67
+
68
+ 1. A browser window should open automatically for Hostinger sign-in.
69
+ 2. If it does not, the process prints `[OAuth] Opening browser for sign-in:` plus the URL on stderr — show that URL and ask them to open it on **this same machine** (the callback is `http://127.0.0.1:<ephemeral-port>/oauth/callback`).
70
+ 3. Wait until the command prints that sign-in succeeded and exits 0.
71
+
72
+ Credentials are stored and reused automatically:
73
+
74
+ - macOS / Linux: `~/.config/hostinger-mcp/credentials.json` (mode 0600)
75
+ - Windows: `%APPDATA%\hostinger-mcp\credentials.json`
76
+
77
+ They are shared across every Hostinger MCP binary. Expired access tokens refresh on their own; a revoked refresh token re-triggers the browser flow.
78
+
79
+ To sign out later:
80
+
81
+ ```bash
82
+ npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp --logout
83
+ ```
84
+
85
+ **API token (optional, CI / scripts):** set `HOSTINGER_API_TOKEN` in the environment before launching Cursor. When present it always wins and no OAuth code runs. Do not commit the token.
86
+
87
+ ## Step 3 — Use the connector in this run (no Cursor restart)
88
+
89
+ Cursor only loads registered MCP servers when the editor starts, so a mid-run `.cursor/mcp.json` change will not attach tools to **this** session. For the rest of this run, talk to the local stdio server directly: spawn
90
+
91
+ ```bash
92
+ npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp
93
+ ```
94
+
95
+ and speak newline-delimited JSON-RPC 2.0 over its stdin/stdout (`initialize` → `notifications/initialized` → `tools/call`). It reuses the cached sign-in from Step 2 (or `HOSTINGER_API_TOKEN`) — no tokens to handle in chat. It exposes `search`, `execute`, and `multi-execute`; everything the stages need goes through `execute`, and a result is in `reply.result.content[0].text`. Keep one process alive for the whole run.
96
+
97
+ ## Step 4 — Install the skills and hand off
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):
102
+
103
+ ```bash
104
+ # macOS/Linux — downloads only skills/headless from the public repo
105
+ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/heads/main \
106
+ | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
107
+ ```
108
+
109
+ Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: headless-connect-devin
3
+ description: "Specific Devin Hostinger MCP Server connection instructions for the Hostinger Headless flow."
4
+ ---
5
+
6
+ ## Goals
7
+
8
+ - Make Hostinger MCP tools and Skills available in Devin.
9
+ - Don't provision hosting, create stores, install WordPress, or deploy by hand here — the skill does all of that. This entry stops at signed in and checking that Hostinger MCP and skills are reachable.
10
+
11
+ ## Step 1 — Make the connector callable
12
+
13
+ The later stages drive the Hostinger connector. If its Hostinger tools already respond in this
14
+ session, use them and move on.
15
+
16
+ If they don't, register the Hostinger MCP server for Devin. The local MCP runs as a **stdio** process
17
+ and the bootstrap already signed you in, so it reuses your cached sign-in automatically
18
+ (`~/.config/hostinger-mcp/credentials.json`, or `HOSTINGER_API_TOKEN`) — no tokens to handle.
19
+
20
+ - **Devin CLI:** `devin mcp add hostinger -- npx -y @hostinger/mcp@latest`
21
+ - **Devin app:** Settings → MCP Marketplace → **Add Your Own**, transport **STDIO**, with:
22
+
23
+ ```json
24
+ {
25
+ "command": "npx",
26
+ "args": ["-y", "@hostinger/mcp@latest"]
27
+ }
28
+ ```
29
+
30
+ On Devin Desktop, fully quit and reopen the app once after adding the server so it loads.
31
+
32
+ If you can't reach the registered server from this run, drive `npx -y @hostinger/mcp@latest` directly
33
+ over stdio instead: spawn it and speak newline-delimited JSON-RPC 2.0 over its stdin/stdout
34
+ (`initialize` → `notifications/initialized` → `tools/call`). It exposes `search`, `execute`,
35
+ `multi-execute`; everything the stages need goes through `execute`, and a result is in
36
+ `reply.result.content[0].text`.
37
+
38
+ ## Step 2 — Install the skills and hand off
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):
43
+
44
+ ```bash
45
+ # macOS/Linux — downloads only skills/headless from the public repo
46
+ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/heads/main \
47
+ | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
48
+ ```
49
+
50
+ Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: headless-connect-vscode
3
+ description: "Specific VS Code Hostinger MCP Server connection instructions for the Hostinger Headless flow."
4
+ ---
5
+
6
+ ## Goals
7
+
8
+ - Make Hostinger MCP tools and Skills available in VS Code (GitHub Copilot / agent mode).
9
+ - Don't provision hosting, create stores, install WordPress, or deploy by hand here — the skill does all of that. This entry stops at signed in and checking that Hostinger MCP and skills are reachable.
10
+
11
+ ## Step 1 — Make the connector callable
12
+
13
+ The later stages drive the Hostinger connector. If its Hostinger tools already respond in this
14
+ session, use them and move on.
15
+
16
+ If they don't, register the Hostinger MCP server for VS Code. The local MCP runs as a **stdio**
17
+ process and the bootstrap already signed you in, so it reuses your cached sign-in automatically
18
+ (`~/.config/hostinger-mcp/credentials.json`, or `HOSTINGER_API_TOKEN`) — no tokens to handle. Add it to
19
+ `.vscode/mcp.json` (workspace) or your user `settings.json` under `mcp`:
20
+
21
+ ```json
22
+ // .vscode/mcp.json
23
+ {
24
+ "servers": {
25
+ "hostinger": {
26
+ "type": "stdio",
27
+ "command": "npx",
28
+ "args": ["-y", "@hostinger/mcp@latest"]
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ Or add it in one command: `code --add-mcp '{"name":"hostinger","command":"npx","args":["-y","@hostinger/mcp@latest"]}'`.
35
+ VS Code picks up the server and its tools become available immediately — no editor restart needed.
36
+ (Alternatively, the official Hostinger Connector extension installs the same server:
37
+ `code --install-extension hostinger-official.hostinger-connector`.)
38
+
39
+ If you can't reach the registered server from this run, drive `npx -y @hostinger/mcp@latest` directly
40
+ over stdio instead: spawn it and speak newline-delimited JSON-RPC 2.0 over its stdin/stdout
41
+ (`initialize` → `notifications/initialized` → `tools/call`). It exposes `search`, `execute`,
42
+ `multi-execute`; everything the stages need goes through `execute`, and a result is in
43
+ `reply.result.content[0].text`.
44
+
45
+ ## Step 2 — Install the skills and hand off
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):
50
+
51
+ ```bash
52
+ # macOS/Linux — downloads only skills/headless from the public repo
53
+ curl -fsSL https://codeload.github.com/hostinger/api-mcp-server/tar.gz/refs/heads/main \
54
+ | tar -xz --strip-components=2 'api-mcp-server-main/skills/headless'
55
+ ```
56
+
57
+ Then open `headless/SKILL.md` and follow its steps. That skill owns the rest of the run.
@@ -0,0 +1,149 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Hostinger Headless build report",
4
+ "description": "Written by run-log.mjs at the end of every run (including early stops) to ~/.hostinger/<domain>/reports/<run>.json.",
5
+ "type": "object",
6
+ "required": ["schema_version", "generated_at", "consent", "run", "info", "timing", "tokens", "issues", "user_feedback", "skill_gaps", "what_went_well", "previous_runs"],
7
+ "properties": {
8
+ "schema_version": { "type": "string", "enum": ["1"] },
9
+ "generated_at": { "type": "string" },
10
+ "consent": {
11
+ "type": "object",
12
+ "required": ["sent"],
13
+ "properties": { "sent": { "type": "boolean" }, "note": { "type": "string" } }
14
+ },
15
+ "run": {
16
+ "type": "object",
17
+ "required": ["id", "kind"],
18
+ "properties": {
19
+ "id": { "type": "string" },
20
+ "kind": { "type": "string", "enum": ["build", "resume", "redesign", "iterate"] },
21
+ "skill": { "type": ["string", "null"] },
22
+ "follow_ups": {
23
+ "type": "array",
24
+ "items": {
25
+ "type": "object",
26
+ "required": ["resumed_at"],
27
+ "properties": { "resumed_at": { "type": "string" }, "after_report_at": { "type": ["string", "null"] }, "reason": { "type": ["string", "null"] } }
28
+ }
29
+ }
30
+ }
31
+ },
32
+ "info": {
33
+ "type": "object",
34
+ "required": ["domain", "tool", "outcome"],
35
+ "properties": {
36
+ "domain": { "type": "string" },
37
+ "tool": { "type": ["string", "null"] },
38
+ "model": { "type": ["string", "null"] },
39
+ "os": { "type": "string" },
40
+ "node": { "type": "string" },
41
+ "mcp": { "type": ["string", "null"] },
42
+ "backend": { "type": ["string", "null"] },
43
+ "frontend": { "type": ["string", "null"] },
44
+ "outcome": { "type": "string", "enum": ["live", "stopped", "failed", "abandoned"] },
45
+ "stopped_at": { "type": ["string", "null"] },
46
+ "live_url": { "type": ["string", "null"] },
47
+ "admin_url": { "type": ["string", "null"] }
48
+ }
49
+ },
50
+ "timing": {
51
+ "type": "object",
52
+ "required": ["started_at", "ended_at", "minutes_total", "stages"],
53
+ "properties": {
54
+ "started_at": { "type": "string" },
55
+ "ended_at": { "type": "string" },
56
+ "live_at": { "type": ["string", "null"] },
57
+ "minutes_total": { "type": ["number", "null"] },
58
+ "minutes_to_live": { "type": ["number", "null"] },
59
+ "stages": {
60
+ "type": "array",
61
+ "items": {
62
+ "type": "object",
63
+ "required": ["stage", "started_at", "ended_at", "result"],
64
+ "properties": {
65
+ "stage": { "type": "string", "enum": ["connect", "check_state", "refine", "provision", "content_model", "design", "frontend", "validate", "deploy", "done"] },
66
+ "phase": { "type": ["string", "null"] },
67
+ "started_at": { "type": "string" },
68
+ "ended_at": { "type": ["string", "null"] },
69
+ "result": { "type": ["string", "null"], "enum": ["ok", "ok_after_retries", "ok_with_fixups", "failed", "skipped", "stopped", null] },
70
+ "note": { "type": ["string", "null"] },
71
+ "minutes": { "type": ["number", "null"] },
72
+ "start_estimated": { "type": "boolean" }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ },
78
+ "tokens": {
79
+ "description": "Only when the tool reports its own usage. Never read the user's transcripts to get it.",
80
+ "type": ["object", "null"],
81
+ "properties": {
82
+ "source": { "type": "string" },
83
+ "requests": { "type": "integer" },
84
+ "input": { "type": "integer" },
85
+ "output": { "type": "integer" },
86
+ "cache_read": { "type": "integer" },
87
+ "cache_write": { "type": "integer" },
88
+ "est_cost_usd": { "type": "number" }
89
+ }
90
+ },
91
+ "issues": {
92
+ "type": "array",
93
+ "items": {
94
+ "type": "object",
95
+ "required": ["stage", "symptom", "severity", "resolved", "user_had_to_intervene"],
96
+ "properties": {
97
+ "stage": { "type": "string" },
98
+ "symptom": { "type": "string" },
99
+ "cause": { "type": "string" },
100
+ "workaround": { "type": "string" },
101
+ "severity": { "type": "string", "enum": ["high", "medium", "low"] },
102
+ "resolved": { "type": "boolean" },
103
+ "user_had_to_intervene": { "type": "boolean" },
104
+ "logged_at": { "type": "string" }
105
+ }
106
+ }
107
+ },
108
+ "user_feedback": {
109
+ "type": "array",
110
+ "items": {
111
+ "type": "object",
112
+ "required": ["stage", "category", "paraphrase"],
113
+ "properties": { "stage": { "type": "string" }, "category": { "type": "string" }, "paraphrase": { "type": "string" }, "logged_at": { "type": "string" } }
114
+ }
115
+ },
116
+ "skill_gaps": {
117
+ "type": "array",
118
+ "items": {
119
+ "type": "object",
120
+ "required": ["skill", "gap"],
121
+ "properties": { "skill": { "type": "string" }, "gap": { "type": "string" }, "stage": { "type": "string" }, "logged_at": { "type": "string" } }
122
+ }
123
+ },
124
+ "what_went_well": {
125
+ "type": "array",
126
+ "items": {
127
+ "type": "object",
128
+ "required": ["text"],
129
+ "properties": { "text": { "type": "string" }, "stage": { "type": "string" }, "logged_at": { "type": "string" } }
130
+ }
131
+ },
132
+ "logging_gaps": {
133
+ "description": "Where the run log is missing or unsure: unfinished stages, estimated starts, zero-length entries, stages never logged on a live build.",
134
+ "type": "array",
135
+ "items": {
136
+ "type": "object",
137
+ "required": ["stage", "problem"],
138
+ "properties": { "stage": { "type": "string" }, "phase": { "type": ["string", "null"] }, "problem": { "type": "string" } }
139
+ }
140
+ },
141
+ "previous_runs": {
142
+ "type": "array",
143
+ "items": {
144
+ "type": "object",
145
+ "properties": { "run": { "type": ["string", "null"] }, "kind": { "type": ["string", "null"] }, "outcome": { "type": ["string", "null"] }, "minutes": { "type": ["number", "null"] }, "html": { "type": "string" } }
146
+ }
147
+ }
148
+ }
149
+ }