You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Share connected WP.com sites between Studio app and CLI (#3227)
## Related issues
- Related to #
## How AI was used in this PR
Opus 4.7 scoped the refactor, wrote the new shared helpers, the
migration, and the Desktop/CLI wiring. I (the author) steered the
data-model decision (cli.json sites property, per-user keying preserved)
and reviewed each hunk. The diff is roughly 520 lines added / 135
removed across 12 files — mostly mechanical once the data layout was
settled.
## Proposed Changes
Connected WP.com sites used to live in `app.json` as a top-level
`connectedWpcomSites: { [userId]: SyncSite[] }` — Desktop-only state.
This moves the list into per-site entries in `cli.json` so both Desktop
and the CLI share a single source of truth, and wires up the CLI
push/pull flows to auto-connect on success.
- **Shared data layer** (`tools/common/`)
- `syncSiteSchema` zod schema added next to the `SyncSite` type, which
is now inferred from it.
- New `tools/common/lib/connected-sites.ts` with read/write helpers
against `cli.json`: `getConnectedWpcomSitesForLocalSite`,
`getAllConnectedWpcomSitesForCurrentUser`, `addConnectedWpcomSite`,
`removeConnectedWpcomSite`, `updateConnectedWpcomSites`,
`markConnectedWpcomSiteSynced`. Uses the existing `cli.json.lock`
lockfile and a permissive passthrough schema so Desktop and CLI can
evolve their `cli.json` site entries independently without corrupting
each other's fields.
- **Storage schemas**
- CLI `siteSchema` now carries an optional `connectedWpcomSites: {
[userId]: SyncSite[] }` map per site.
- `connectedWpcomSites` removed from the `app.json` `UserData` type.
- **Migration 04** copies
`app.json.connectedWpcomSites[userId][].{localSiteId}` into `cli.json
sites[].connectedWpcomSites[userId]`, deduping by remote id. It stamps
`connectedWpcomSitesMigratedToCli: true` on `app.json` and leaves the
legacy field in place for this release so older Studio versions keep
working — a follow-up migration will strip it.
- **Desktop IPC handlers** now delegate through the shared helpers
instead of reading/writing `app.json`:
- `connectWpcomSites`, `disconnectWpcomSites`,
`updateConnectedWpcomSites`, `getConnectedWpcomSites` in
`apps/studio/src/modules/sync/lib/ipc-handlers.ts`
- `reconcileSessionEnvironmentBeforeRun` and `setSessionEnvironment` in
`apps/studio/src/ipc-handlers.ts`
- **CLI auto-connect**: `apps/cli/commands/push.ts` and
`apps/cli/commands/pull.ts` call `addConnectedWpcomSite` +
`markConnectedWpcomSiteSynced` after a successful run.
- **AI agent push workflow**: the `studio code` agent gained a
`site_connected_remote_sites` MCP tool plus a new system-prompt section
instructing it to resolve the target before pushing — 1 attached site →
confirm, many → `AskUserQuestion` list, 0 → open-ended question.
## Testing Instructions
- Back up `~/.studio/app.json` and `~/.studio/cli.json`.
- **Migration:** with `app.json.connectedWpcomSites` populated, launch
the Desktop app. Expect `cli.json sites[].connectedWpcomSites[userId]`
to be populated, and `app.json.connectedWpcomSitesMigratedToCli: true`
to be added. The legacy `app.json.connectedWpcomSites` should still be
present.
- **Desktop:** open a site with a connection — publish picker + site
dropdown + session environment switcher should show the connection as
before.
- **Desktop connect/disconnect:** from the sync modal, connect and
disconnect a WordPress.com site — the entry should appear/disappear in
`cli.json` without further app.json writes.
- **CLI auto-connect:** run `studio push` or `studio pull` for a site
with no connections yet — after success, verify the remote site shows up
under `cli.json sites[].connectedWpcomSites` and that Desktop's site
dropdown reflects it.
- **CLI AI agent:** run `studio code`, ask it to "push my site". It
should call `site_connected_remote_sites`, then either confirm (single
attached), show a picker (many), or ask open-ended (none) before calling
`site_push`.
## Pre-merge Checklist
- [x] Have you checked for TypeScript, React or other console errors?
(`npm run typecheck` clean across workspaces; `npm test -- apps/cli
apps/studio` — 1042 passing)
- [ ] Manual Desktop smoke test of connect/disconnect UI
- [ ] Manual CLI push/pull to verify auto-connect
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>
Copy file name to clipboardExpand all lines: apps/cli/ai/system-prompt.ts
+13-1Lines changed: 13 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -183,6 +183,7 @@ One \`Write\` or \`Edit\` per turn (read-only \`site_info\`, \`site_list\`, \`wp
183
183
- take_screenshot: Take a full-page screenshot of a URL (supports desktop and mobile viewports). Use this to visually check the site after building it.
184
184
- need_for_speed: Measure frontend performance metrics (TTFB, FCP, LCP, CLS, page weight, DOM size, JS/CSS/image/font asset breakdown) for a running site. Use this to identify performance bottlenecks and guide optimization.
185
185
- rank_me_up: Run an on-page SEO audit (title/meta tags, headings, image alt text, OpenGraph/Twitter cards, JSON-LD structured data, robots.txt and sitemap.xml availability) for a running site. Use this to identify on-page SEO issues and guide fixes.
186
+
- site_connected_remote_sites: List the WordPress.com sites already attached to a local site. Call this before site_push to decide how to ask the user which remote site to target.
186
187
- site_push: Push a local site to a WordPress.com site. Requires authentication (studio auth login). Specify the remote site URL or ID and sync options (all, sqls, uploads, plugins, themes, contents).
187
188
- site_pull: Pull a WordPress.com site to a local site. Requires authentication. Specify the remote site URL or ID and sync options.
188
189
- site_import: Import a backup file (.zip, .tar.gz, .sql, .wpress) into a local site.
@@ -198,7 +199,18 @@ One \`Write\` or \`Edit\` per turn (read-only \`site_info\`, \`site_list\`, \`wp
198
199
- Always enqueue the theme's style.css on the frontend from functions.php.
199
200
- For theme and page content custom CSS, put the styles in the main style.css of the theme. No custom stylesheets.
200
201
- Scroll animations must use progressive enhancement: CSS defines elements in their **final visible state** by default (full opacity, final position). JavaScript on the frontend adds the initial hidden state (e.g. \`opacity: 0\`, \`transform\`) and scroll-triggered transitions. This ensures elements are fully visible in the block editor (which loads theme CSS but not custom JS).
201
-
- All animations and transitions must respect \`prefers-reduced-motion\`. Add a \`@media (prefers-reduced-motion: reduce)\` block that disables or simplifies animations (e.g. \`animation: none; transition: none; scroll-behavior: auto;\`).`;
202
+
- All animations and transitions must respect \`prefers-reduced-motion\`. Add a \`@media (prefers-reduced-motion: reduce)\` block that disables or simplifies animations (e.g. \`animation: none; transition: none; scroll-behavior: auto;\`).
203
+
204
+
## Push workflow
205
+
206
+
When the user asks to push a site to WordPress.com, you MUST resolve the target remote site before calling \`site_push\`:
207
+
208
+
1. Call \`site_connected_remote_sites\` with the local site's name or path to get the list of already-attached WordPress.com sites.
209
+
2. Branch on how many remote sites are attached:
210
+
- **Exactly one attached site**: Use \`AskUserQuestion\` to confirm pushing to that site. Present two options labeled "Yes" and "No" with a description that includes the remote site's name and URL. Only call \`site_push\` if the user confirms.
211
+
- **Multiple attached sites**: Use \`AskUserQuestion\` with one question whose options are the attached sites (label = site name, description = URL). Then call \`site_push\` with the chosen site's ID or URL as \`remoteSite\`.
212
+
- **No attached sites**: Do NOT use \`AskUserQuestion\`. Ask an open-ended question in plain text for the URL or ID of the WordPress.com site to push to, then wait for the user's reply before calling \`site_push\`.
213
+
3. Never call \`site_push\` without explicit user confirmation of the target — even when only one site is attached.`;
0 commit comments