@awesomate/hosting-mcp 0.11.0 → 0.12.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.
- package/dist/index.js +58 -4
- package/package.json +1 -1
- package/skill/awesomate-app-builder/SKILL.md +21 -7
- package/skill/awesomate-github/SKILL.md +27 -1
- package/skill/awesomate-github/scripts/vc-healthcheck.mjs +102 -0
- package/skill/awesomate-hosting/SKILL.md +39 -8
- package/skill/awesomate-hosting/scripts/bootstrap.mjs +13 -7
- package/skill/awesomate-hosting/scripts/deploy.sh +1 -1
- package/skill/awesomate-hosting/scripts/pull-live.sh +1 -1
package/dist/index.js
CHANGED
|
@@ -40114,9 +40114,9 @@ readTool(
|
|
|
40114
40114
|
var PLAN_LADDER_FALLBACK = {
|
|
40115
40115
|
note: "Live per-account limits come from awesomate_get_limits \u2014 this is the plan ladder reference (static fallback).",
|
|
40116
40116
|
plans: [
|
|
40117
|
-
{ name: "Essentials", purchasable: false, monthlyPriceUsd: 75, maxSites: 1, maxCustomDomains:
|
|
40118
|
-
{ name: "Support Plus", purchasable: true, monthlyPriceUsd: 175, maxSites: 2, maxCustomDomains:
|
|
40119
|
-
{ name: "Pro", purchasable: true, monthlyPriceUsd: 375, maxSites: 10, maxCustomDomains:
|
|
40117
|
+
{ name: "Essentials", purchasable: false, monthlyPriceUsd: 75, maxSites: 1, maxCustomDomains: 1, maxApps: 0, cpanelAccess: true, shellAccess: false, appBuilder: false },
|
|
40118
|
+
{ name: "Support Plus", purchasable: true, monthlyPriceUsd: 175, maxSites: 2, maxCustomDomains: 5, maxApps: 5, cpanelAccess: true, shellAccess: true, appBuilder: true },
|
|
40119
|
+
{ name: "Pro", purchasable: true, monthlyPriceUsd: 375, maxSites: 10, maxCustomDomains: 20, maxApps: 20, cpanelAccess: true, shellAccess: true, appBuilder: true },
|
|
40120
40120
|
{ name: "Embedded", purchasable: false, monthlyPriceUsd: null, maxSites: 100, maxCustomDomains: 100, maxApps: 100, cpanelAccess: true, shellAccess: true, appBuilder: true, note: "Not generally available yet" }
|
|
40121
40121
|
],
|
|
40122
40122
|
upgradePath: "Essentials \u2192 Support Plus \u2192 Pro \u2192 Embedded; upgrades at hub.awesomate.ai/billing (only Support Plus and Pro are purchasable)"
|
|
@@ -40147,7 +40147,7 @@ server.registerTool(
|
|
|
40147
40147
|
{
|
|
40148
40148
|
description: "Snapshot a WordPress site (files + database) BEFORE any risky change \u2014 an AI edit, a deploy, a plugin/theme/core update. Returns a snapshotId you can roll back to. ALWAYS snapshot before mutating a live site. Requires shell access (Support Plus+).",
|
|
40149
40149
|
inputSchema: {
|
|
40150
|
-
domain: external_exports.string().describe("The site domain (as shown by awesomate_list_sites), e.g. mysite.awesomate.
|
|
40150
|
+
domain: external_exports.string().describe("The site domain (as shown by awesomate_list_sites), e.g. mysite.awesomate.site"),
|
|
40151
40151
|
reason: external_exports.string().optional().describe('Why (stored in the snapshot list), e.g. "before deploy"')
|
|
40152
40152
|
}
|
|
40153
40153
|
},
|
|
@@ -40194,6 +40194,60 @@ server.registerTool(
|
|
|
40194
40194
|
}
|
|
40195
40195
|
}
|
|
40196
40196
|
);
|
|
40197
|
+
server.registerTool(
|
|
40198
|
+
"awesomate_site_staging_create",
|
|
40199
|
+
{
|
|
40200
|
+
description: "Create a staging copy of a WordPress site on the client's private awesomate.dev address (files + database cloned, URLs rewritten). Use this BEFORE making user-facing changes so the user can review at the staging URL first \u2014 post to dev, review, then awesomate_site_staging_promote. The staging site is hidden from search engines and AI crawlers by policy; anyone with the link can view it. One staging copy per site \u2014 a 409 with code 'staging_exists' means promote or discard the existing one first. Cloning can take a few minutes on large sites. Requires shell access (Support Plus+).",
|
|
40201
|
+
inputSchema: {
|
|
40202
|
+
domain: external_exports.string().describe("The LIVE site domain (as shown by awesomate_list_sites), e.g. mysite.awesomate.site")
|
|
40203
|
+
}
|
|
40204
|
+
},
|
|
40205
|
+
async ({ domain }) => {
|
|
40206
|
+
try {
|
|
40207
|
+
return textResult(
|
|
40208
|
+
await hubPost(requireConfig(), `/api/hosting-access/sites/${encodeURIComponent(domain)}/staging`, {})
|
|
40209
|
+
);
|
|
40210
|
+
} catch (err) {
|
|
40211
|
+
return errorResult(err);
|
|
40212
|
+
}
|
|
40213
|
+
}
|
|
40214
|
+
);
|
|
40215
|
+
server.registerTool(
|
|
40216
|
+
"awesomate_site_staging_promote",
|
|
40217
|
+
{
|
|
40218
|
+
description: "Publish the staging copy to the LIVE site (overwrites live files + database with staging). The live site is auto-snapshotted first \u2014 the result includes preSnapshotId, which awesomate_rollback_site can restore if anything looks wrong. **Confirm with the user before promoting \u2014 it replaces the live site.** Requires shell access (Support Plus+).",
|
|
40219
|
+
inputSchema: {
|
|
40220
|
+
domain: external_exports.string().describe("The LIVE site domain whose staging copy should go live")
|
|
40221
|
+
}
|
|
40222
|
+
},
|
|
40223
|
+
async ({ domain }) => {
|
|
40224
|
+
try {
|
|
40225
|
+
return textResult(
|
|
40226
|
+
await hubPost(requireConfig(), `/api/hosting-access/sites/${encodeURIComponent(domain)}/staging/promote`, {})
|
|
40227
|
+
);
|
|
40228
|
+
} catch (err) {
|
|
40229
|
+
return errorResult(err);
|
|
40230
|
+
}
|
|
40231
|
+
}
|
|
40232
|
+
);
|
|
40233
|
+
server.registerTool(
|
|
40234
|
+
"awesomate_site_staging_discard",
|
|
40235
|
+
{
|
|
40236
|
+
description: "Delete the staging copy of a site (staging WP install + its awesomate.dev address; the live site is untouched). **Confirm with the user before discarding \u2014 unpromoted staging changes are lost.** Requires shell access (Support Plus+).",
|
|
40237
|
+
inputSchema: {
|
|
40238
|
+
domain: external_exports.string().describe("The LIVE site domain whose staging copy should be discarded")
|
|
40239
|
+
}
|
|
40240
|
+
},
|
|
40241
|
+
async ({ domain }) => {
|
|
40242
|
+
try {
|
|
40243
|
+
return textResult(
|
|
40244
|
+
await hubDelete(requireConfig(), `/api/hosting-access/sites/${encodeURIComponent(domain)}/staging`)
|
|
40245
|
+
);
|
|
40246
|
+
} catch (err) {
|
|
40247
|
+
return errorResult(err);
|
|
40248
|
+
}
|
|
40249
|
+
}
|
|
40250
|
+
);
|
|
40197
40251
|
readTool(
|
|
40198
40252
|
"awesomate_app_context",
|
|
40199
40253
|
"Call FIRST before any app-builder work. Returns the connected account's plan, whether the app builder is unlocked (capability.appBuilder \u2014 Support Plus+), whether they have a cPanel hosting account yet, their existing apps, firstRun, and capability-aware next-step suggestions to offer the user. If appBuilder is false, relay the upgrade suggestion rather than attempting to build.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/hosting-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -87,12 +87,22 @@ target; never touch prod without an explicit ask.**
|
|
|
87
87
|
[references/node-recipes.md](references/node-recipes.md) has the recipes
|
|
88
88
|
(add a table/endpoint, env vars, connection strings, promote/rollback).
|
|
89
89
|
Handle **secrets** only via the **awesomate-credentials** skill
|
|
90
|
-
(encrypted + injected, never committed/echoed).
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
(encrypted + injected, never committed/echoed). **Version control is not
|
|
91
|
+
optional**: as soon as the scaffold exists, run the awesomate-github setup
|
|
92
|
+
(repo + first commit + push-to-deploy) — ask only the project name and
|
|
93
|
+
private-y/n, in plain words ("I'll back your work up as we go"). From then
|
|
94
|
+
on, **auto-checkpoint**: commit after every working change with a message
|
|
95
|
+
you write, and run the github skill's `vc-healthcheck.mjs` at session start
|
|
96
|
+
and before every deploy. If it needs email/lookup/AI, attach n8n (§"when to
|
|
97
|
+
use n8n").
|
|
98
|
+
6. **Testing — always ask "live or dev?" before posting anything.** When the
|
|
99
|
+
user asks to publish/change something user-facing, ask: *"Want this on your
|
|
100
|
+
live site, or on your dev site (awesomate.dev) to review and test first?"*
|
|
101
|
+
Recommend dev. Deploy to **dev** (`git push` to `dev` — the dev site lives
|
|
102
|
+
at `{app}.{slug}.awesomate.dev`, hidden from search engines and AI crawlers
|
|
103
|
+
by policy), then `awesomate_app_health` to confirm it came up (Node:
|
|
104
|
+
`/api/ready`). Show the user the live dev URL and let them try it. Iterate
|
|
105
|
+
on dev until they're happy.
|
|
96
106
|
7. **Wrap-up / promote** — only when the user approves, promote **dev → staging
|
|
97
107
|
→ main** (merge + push per branch). `awesomate_app_deploy` reports the
|
|
98
108
|
branch→env map + last-deploy state. Prod is `main`. **Before merging to
|
|
@@ -113,7 +123,11 @@ files directly (no build step).
|
|
|
113
123
|
- Non-technical user: explain in plain words, one or two short questions at a
|
|
114
124
|
time, no unexplained jargon. Recommend; don't quiz them on architecture.
|
|
115
125
|
- Confirm the stack + name before `awesomate_app_create`. Default the target
|
|
116
|
-
to **dev**; never push to prod without an explicit ask
|
|
126
|
+
to **dev**; never push to prod without an explicit ask — and when they ask
|
|
127
|
+
to "post"/"publish" something, ask **"live or dev?"** first.
|
|
128
|
+
- You are the user's version-control expert (they don't know what a repo is):
|
|
129
|
+
set up GitHub right after the first build, auto-commit as you go, and run
|
|
130
|
+
the github skill's vc-healthcheck at session start + before deploys.
|
|
117
131
|
- A `403` on a write = plan gate (Support Plus+). Offer an upgrade, don't retry.
|
|
118
132
|
- A `409` with code `app_limit` = the plan's app allowance is full (Support
|
|
119
133
|
Plus 5, Pro 20 — `awesomate_app_context.limits` has the live numbers).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: awesomate-github
|
|
3
|
-
description: Set up GitHub version control for the user's app with zero Git knowledge required — connect their GitHub once, then create the repo, .gitignore, first commit and push-to-deploy for them. Use when the user says "connect GitHub", "back up my app", "save my work", "set up version control", "put this on GitHub", or after building an app when it should be version-controlled. Companion to awesomate-app-builder.
|
|
3
|
+
description: Set up GitHub version control for the user's app with zero Git knowledge required — connect their GitHub once, then create the repo, .gitignore, first commit and push-to-deploy for them. Use when the user says "connect GitHub", "back up my app", "save my work", "set up version control", "put this on GitHub", or after building an app when it should be version-controlled — and proactively: run its vc-healthcheck at session start and before deploys to keep commits/pushes/deploys healthy for users who do not know Git. Companion to awesomate-app-builder.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Awesomate GitHub — version control for people who don't know Git
|
|
@@ -62,6 +62,32 @@ Explain it as *"save your work = it goes live"* — don't lecture on branches.
|
|
|
62
62
|
- "Put it live" → push to the right branch (dev/staging/main) and tell them the URL.
|
|
63
63
|
- Always write clear commit messages **for** them; don't ask them to.
|
|
64
64
|
|
|
65
|
+
## 4. Be the version-control guardian (proactive, not reactive)
|
|
66
|
+
|
|
67
|
+
The user is ~99% likely to have no idea what a repo is. YOU own their version
|
|
68
|
+
control — they should never have to think about it:
|
|
69
|
+
|
|
70
|
+
- **Health check at session start.** Before touching an app folder, run:
|
|
71
|
+
```
|
|
72
|
+
node ~/.claude/skills/awesomate-github/scripts/vc-healthcheck.mjs <project-dir>
|
|
73
|
+
```
|
|
74
|
+
It prints JSON (`problems[]`: `no_repo`, `no_remote`, `uncommitted_changes`,
|
|
75
|
+
`unpushed_commits`, `env_file_tracked`, `last_deploy_failed`, …). Fix what
|
|
76
|
+
you can silently (commit + push loose work with a message you write); for
|
|
77
|
+
`no_repo`/`no_remote`, offer setup (§1) in plain words: *"your last changes
|
|
78
|
+
aren't backed up anywhere — want me to set that up? Takes a minute."*
|
|
79
|
+
`env_file_tracked` is urgent: untrack it, .gitignore it, and route the
|
|
80
|
+
secrets through awesomate-credentials.
|
|
81
|
+
- **Auto-checkpoint.** After every meaningful working change (feature works,
|
|
82
|
+
bug fixed, content updated), commit with a plain-English message — don't
|
|
83
|
+
wait for "save my work", and never ask them to write a message. Push at
|
|
84
|
+
natural pauses so their backup is never behind.
|
|
85
|
+
- **Health check before every deploy/publish.** Re-run the script; never push
|
|
86
|
+
to a deploy branch with a failing prior run you haven't explained.
|
|
87
|
+
- **Report in their language.** "Your work is backed up" / "your last 3
|
|
88
|
+
changes were never saved — I've saved them now" — never "you're 2 commits
|
|
89
|
+
ahead of origin/main".
|
|
90
|
+
|
|
65
91
|
## Hard rules
|
|
66
92
|
- Never commit a secret or a `.env`. The script's secret guard is a backstop,
|
|
67
93
|
not a licence to skip checking. If you spot a secret, route it through the
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Version-control health check for an Awesomate app folder.
|
|
4
|
+
*
|
|
5
|
+
* Run from (or pass) the project directory. Prints a JSON report Claude uses
|
|
6
|
+
* to keep the user's version control healthy WITHOUT them knowing Git:
|
|
7
|
+
* - repo/remote wiring, uncommitted + unpushed work
|
|
8
|
+
* - branch → deploy-env mapping (dev → awesomate.dev, main → live)
|
|
9
|
+
* - last GitHub Actions deploy run (when `gh` is authed)
|
|
10
|
+
*
|
|
11
|
+
* Exit code 0 always (reporting tool, not a gate) — Claude decides what to
|
|
12
|
+
* fix based on the JSON.
|
|
13
|
+
*/
|
|
14
|
+
import { execSync } from 'node:child_process';
|
|
15
|
+
import { existsSync } from 'node:fs';
|
|
16
|
+
import { resolve } from 'node:path';
|
|
17
|
+
|
|
18
|
+
const dir = resolve(process.argv[2] ?? '.');
|
|
19
|
+
const report = {
|
|
20
|
+
dir,
|
|
21
|
+
gitInstalled: false,
|
|
22
|
+
repoInitialized: false,
|
|
23
|
+
remote: null,
|
|
24
|
+
branch: null,
|
|
25
|
+
uncommittedFiles: 0,
|
|
26
|
+
unpushedCommits: null, // null = unknown (no upstream)
|
|
27
|
+
hasUpstream: false,
|
|
28
|
+
envTracked: false,
|
|
29
|
+
ghAuthed: false,
|
|
30
|
+
lastDeployRun: null,
|
|
31
|
+
problems: [],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function sh(cmd) {
|
|
35
|
+
return execSync(cmd, { cwd: dir, stdio: ['ignore', 'pipe', 'pipe'], timeout: 15_000 })
|
|
36
|
+
.toString()
|
|
37
|
+
.trim();
|
|
38
|
+
}
|
|
39
|
+
function trySh(cmd) {
|
|
40
|
+
try {
|
|
41
|
+
return sh(cmd);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (trySh('git --version') === null) {
|
|
48
|
+
report.problems.push('git_not_installed');
|
|
49
|
+
} else {
|
|
50
|
+
report.gitInstalled = true;
|
|
51
|
+
report.repoInitialized = trySh('git rev-parse --is-inside-work-tree') === 'true';
|
|
52
|
+
if (!report.repoInitialized) {
|
|
53
|
+
report.problems.push('no_repo');
|
|
54
|
+
} else {
|
|
55
|
+
report.branch = trySh('git branch --show-current') || '(detached)';
|
|
56
|
+
report.remote = trySh('git remote get-url origin');
|
|
57
|
+
if (!report.remote) report.problems.push('no_remote');
|
|
58
|
+
|
|
59
|
+
const status = trySh('git status --porcelain') ?? '';
|
|
60
|
+
report.uncommittedFiles = status ? status.split('\n').length : 0;
|
|
61
|
+
if (report.uncommittedFiles > 0) report.problems.push('uncommitted_changes');
|
|
62
|
+
|
|
63
|
+
// .env must never be tracked — the single most dangerous drift.
|
|
64
|
+
const tracked = trySh('git ls-files .env */.env') ?? '';
|
|
65
|
+
report.envTracked = tracked.length > 0;
|
|
66
|
+
if (report.envTracked) report.problems.push('env_file_tracked');
|
|
67
|
+
|
|
68
|
+
const upstream = trySh('git rev-parse --abbrev-ref @{upstream}');
|
|
69
|
+
report.hasUpstream = !!upstream;
|
|
70
|
+
if (upstream) {
|
|
71
|
+
const ahead = trySh('git rev-list --count @{upstream}..HEAD');
|
|
72
|
+
report.unpushedCommits = ahead === null ? null : Number(ahead);
|
|
73
|
+
if (report.unpushedCommits > 0) report.problems.push('unpushed_commits');
|
|
74
|
+
} else if (report.remote) {
|
|
75
|
+
report.problems.push('branch_not_pushed');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (report.remote && trySh('gh auth status') !== null) {
|
|
79
|
+
report.ghAuthed = true;
|
|
80
|
+
const runs = trySh(
|
|
81
|
+
'gh run list --limit 1 --json displayTitle,conclusion,headBranch,updatedAt',
|
|
82
|
+
);
|
|
83
|
+
try {
|
|
84
|
+
const parsed = JSON.parse(runs ?? '[]');
|
|
85
|
+
if (parsed[0]) {
|
|
86
|
+
report.lastDeployRun = parsed[0];
|
|
87
|
+
if (parsed[0].conclusion && parsed[0].conclusion !== 'success') {
|
|
88
|
+
report.problems.push('last_deploy_failed');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
/* no runs / not parseable — fine */
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!existsSync(resolve(dir, '.gitignore')) && report.repoInitialized) {
|
|
99
|
+
report.problems.push('no_gitignore');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log(JSON.stringify(report, null, 2));
|
|
@@ -3,7 +3,7 @@ name: awesomate-hosting
|
|
|
3
3
|
description: >
|
|
4
4
|
Manage, build, and grow your Awesomate WordPress hosting from Claude. Use when
|
|
5
5
|
the user mentions their Awesomate site or hosting, cPanel, a site on
|
|
6
|
-
*.awesomate.io or a custom domain hosted with Awesomate, WordPress admin,
|
|
6
|
+
*.awesomate.site (or legacy *.site.awesomate.io) or a custom domain hosted with Awesomate, WordPress admin,
|
|
7
7
|
installing a plugin/theme, running WP-CLI, "my site is slow / out of space /
|
|
8
8
|
broke", snapshotting or rolling back a site, deploying from a local WordPress
|
|
9
9
|
Studio site to live, checking hosting stats or how close they are to a plan
|
|
@@ -11,7 +11,9 @@ description: >
|
|
|
11
11
|
plan. Trigger phrases: "my awesomate site", "connect my hosting", "spin up a
|
|
12
12
|
wordpress site", "install wordpress", "add my domain", "why is my site slow",
|
|
13
13
|
"am I near my limit", "snapshot my site", "roll back my site", "deploy to
|
|
14
|
-
live", "run wp-cli", "upgrade my plan", "how many sites can I have"
|
|
14
|
+
live", "run wp-cli", "upgrade my plan", "how many sites can I have",
|
|
15
|
+
"create a staging site", "test changes before going live", "publish staging",
|
|
16
|
+
"post this to my dev site".
|
|
15
17
|
---
|
|
16
18
|
|
|
17
19
|
# Awesomate Hosting
|
|
@@ -170,25 +172,34 @@ Allowed: `awesomate_get_context`, `_get_hosting_status`, `_get_hosting_account`,
|
|
|
170
172
|
`_get_hosting_stats`, `_get_grafana_url`, `_get_credit_balance`, the billing
|
|
171
173
|
preview/deep-link tools, and 1-click WP-admin / cPanel SSO links.
|
|
172
174
|
|
|
173
|
-
Never attempt SSH, WP-CLI, snapshot/rollback, deploy, multi-site
|
|
174
|
-
|
|
175
|
+
Never attempt SSH, WP-CLI, snapshot/rollback, staging, deploy, multi-site —
|
|
176
|
+
those tools will 403. Instead, surface the specific limit and what
|
|
175
177
|
Support Plus/Pro unlocks (see §4), and offer to preview the upgrade.
|
|
176
178
|
|
|
177
179
|
### Support Plus and above (shell) — full workflow
|
|
178
180
|
|
|
179
181
|
You additionally have: jailed SSH to the client's own cPanel account, WP-CLI
|
|
180
182
|
(`awesomate_run_wp_cli` or raw SSH via `scripts/ssh-connect.sh`),
|
|
181
|
-
snapshot/rollback,
|
|
183
|
+
snapshot/rollback, **WP staging on awesomate.dev** (§5a), and the local-first
|
|
184
|
+
deploy flow (§5). Golden rule, always:
|
|
182
185
|
|
|
183
186
|
> **Local first, live never — and snapshot before you touch live.**
|
|
184
187
|
|
|
188
|
+
**Ask "live or dev?" before posting anything user-facing.** When the user asks
|
|
189
|
+
you to change/publish something on their WordPress site, ask: *"Want me to put
|
|
190
|
+
this on your live site, or on your private dev copy (awesomate.dev) so you can
|
|
191
|
+
review it first?"* Default suggestion: dev first, publish after they've looked
|
|
192
|
+
at it. Their dev copy is invisible to Google and AI crawlers by policy.
|
|
193
|
+
|
|
185
194
|
## 3. Safety rules (non-negotiable)
|
|
186
195
|
|
|
187
196
|
- **Before ANY change to a live site** — plugin/theme/core update, `search-replace`,
|
|
188
197
|
bulk edit, deploy — call **`awesomate_snapshot_site`** first and tell the user the
|
|
189
198
|
`snapshotId`. If it goes wrong, `awesomate_rollback_site` restores files + DB.
|
|
190
199
|
- **Confirm before destructive actions**: `awesomate_uninstall_site`,
|
|
191
|
-
`awesomate_rollback_site`,
|
|
200
|
+
`awesomate_rollback_site`, `awesomate_site_staging_promote` (replaces live),
|
|
201
|
+
`awesomate_site_staging_discard` (loses unpublished staging work), dropping
|
|
202
|
+
tables, `wp db reset`, deleting content.
|
|
192
203
|
State exactly what will be lost and wait for an explicit "yes".
|
|
193
204
|
- Prefer building/testing in **WordPress Studio locally**, then deploy (§5).
|
|
194
205
|
- Dry-run risky WP-CLI where the command supports it before the real run.
|
|
@@ -214,8 +225,8 @@ one command — `scripts/deploy.sh`, which **snapshots live first** (so a bad
|
|
|
214
225
|
deploy is one rollback away), pushes files, then optionally the DB:
|
|
215
226
|
|
|
216
227
|
```
|
|
217
|
-
scripts/deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.
|
|
218
|
-
scripts/deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.
|
|
228
|
+
scripts/deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.site # files only
|
|
229
|
+
scripts/deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.site --with-db # + database
|
|
219
230
|
```
|
|
220
231
|
|
|
221
232
|
- **Always files-first is the safe default.** `--with-db` also exports the
|
|
@@ -230,6 +241,26 @@ scripts/deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.io --with-db
|
|
|
230
241
|
Never deploy without confirming with the user first, and always report the
|
|
231
242
|
snapshot id and the verified live status.
|
|
232
243
|
|
|
244
|
+
## 5a. Staging on awesomate.dev (Support Plus+)
|
|
245
|
+
|
|
246
|
+
The middle tier between "edit live" and "local Studio": a private full copy of
|
|
247
|
+
the site at `{name}.{slug}.awesomate.dev`, noindexed at the edge (no Google, no
|
|
248
|
+
AI crawlers — anyone with the link can view, perfect for client review).
|
|
249
|
+
|
|
250
|
+
- `awesomate_site_staging_create <live domain>` — clones files + DB, rewrites
|
|
251
|
+
URLs. One staging copy per site (409 `staging_exists` → promote or discard
|
|
252
|
+
first). Takes a few minutes on large sites.
|
|
253
|
+
- Make the changes ON the staging domain (WP-CLI / wp-admin / deploy.sh with
|
|
254
|
+
`--domain <staging domain>`), send the user the staging URL to review.
|
|
255
|
+
- `awesomate_site_staging_promote <live domain>` — publishes staging over live.
|
|
256
|
+
Live is auto-snapshotted first; report the returned `preSnapshotId` as the
|
|
257
|
+
undo handle (`awesomate_rollback_site`). **Confirm before promoting.**
|
|
258
|
+
- `awesomate_site_staging_discard <live domain>` — deletes the staging copy;
|
|
259
|
+
live untouched. **Confirm — unpublished staging changes are lost.**
|
|
260
|
+
|
|
261
|
+
Prefer this flow over editing live whenever the change is user-visible
|
|
262
|
+
(theme/layout/content restructures, plugin experiments, redesigns).
|
|
263
|
+
|
|
233
264
|
## 6. Version control with GitHub (optional)
|
|
234
265
|
|
|
235
266
|
Awesomate's snapshots are your safety net, so Git isn't required — but for real
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
31
|
-
import { existsSync, mkdirSync, writeFileSync, chmodSync, readFileSync, cpSync, readdirSync, renameSync, statSync } from 'node:fs';
|
|
31
|
+
import { existsSync, mkdirSync, writeFileSync, chmodSync, readFileSync, cpSync, readdirSync, renameSync, statSync, realpathSync } from 'node:fs';
|
|
32
32
|
import { homedir, hostname } from 'node:os';
|
|
33
|
-
import { join, dirname, resolve } from 'node:path';
|
|
33
|
+
import { join, dirname, resolve, basename } from 'node:path';
|
|
34
34
|
import { fileURLToPath } from 'node:url';
|
|
35
35
|
|
|
36
36
|
function arg(name, fallback) {
|
|
@@ -273,19 +273,25 @@ function writePin(slug) {
|
|
|
273
273
|
* failure here never aborts the rest of setup.
|
|
274
274
|
*/
|
|
275
275
|
function installSkill() {
|
|
276
|
-
|
|
276
|
+
// realpathSync: npx runs the bin through a symlink (or a shim on Windows) —
|
|
277
|
+
// resolve to the file's true location inside the package before walking up,
|
|
278
|
+
// or the walk lands in the npx cache's .bin dir. basename() (never
|
|
279
|
+
// endsWith('/skill')): Windows paths use '\', which broke the layout check
|
|
280
|
+
// and made every Windows bootstrap report "Skill files not found".
|
|
281
|
+
let selfPath = fileURLToPath(import.meta.url);
|
|
282
|
+
try { selfPath = realpathSync(selfPath); } catch { /* keep unresolved path */ }
|
|
283
|
+
const hostingSkill = dirname(dirname(selfPath));
|
|
277
284
|
const skillRoot = dirname(hostingSkill);
|
|
285
|
+
const isPackageLayout = basename(skillRoot) === 'skill';
|
|
278
286
|
// Only the package layout (skill/<name>/) has bundled siblings; from an
|
|
279
287
|
// installed copy the parent is the user's skills folder full of unrelated
|
|
280
288
|
// skills, so fall back to just this skill.
|
|
281
|
-
const bundled = skillRoot
|
|
282
|
-
? readdirSync(skillRoot)
|
|
283
|
-
: [hostingSkill.split('/').pop()];
|
|
289
|
+
const bundled = isPackageLayout ? readdirSync(skillRoot) : [basename(hostingSkill)];
|
|
284
290
|
// Package version, stamped into each installed skill as .installed-version.
|
|
285
291
|
// The MCP server (always latest via unpinned npx) compares it against its own
|
|
286
292
|
// version and reports skill.updateAvailable in awesomate_get_context.
|
|
287
293
|
let pkgVersion = null;
|
|
288
|
-
if (
|
|
294
|
+
if (isPackageLayout) {
|
|
289
295
|
try {
|
|
290
296
|
pkgVersion = JSON.parse(readFileSync(join(dirname(skillRoot), 'package.json'), 'utf8')).version ?? null;
|
|
291
297
|
} catch { /* non-fatal — marker just won't be written */ }
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Awesomate site. SNAPSHOTS LIVE FIRST via the hub (so a bad deploy is one
|
|
5
5
|
# rollback away), then pushes files, then optionally the database.
|
|
6
6
|
#
|
|
7
|
-
# deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.
|
|
7
|
+
# deploy.sh --from ~/Studio/mysite --domain mysite.awesomate.site [options]
|
|
8
8
|
#
|
|
9
9
|
# Options:
|
|
10
10
|
# --docroot PATH Live docroot (default: /home/<cpanel-user>/public_html)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# from an existing live site). Read-only against live — it never changes the
|
|
5
5
|
# live site. Copies files + exports the live DB.
|
|
6
6
|
#
|
|
7
|
-
# pull-live.sh --domain mysite.awesomate.
|
|
7
|
+
# pull-live.sh --domain mysite.awesomate.site --to ~/Studio/mysite [--docroot PATH]
|
|
8
8
|
#
|
|
9
9
|
# Then import the files into a new WordPress Studio site and load db.sql.
|
|
10
10
|
# Client-side deps: bash, ssh, rsync, scp.
|