Merge trunk into release/1.18.0 - #4536
Conversation
…4461) ## Related issues - Fixes STU-2202 ## How AI was used in this PR Claude traced the existing "Open Studio Logs" flow in the classic UI and the connector/capability seam in `apps/ui`, then wrote the change and the tests. I verified the behaviour in the running desktop app (see screenshot below) and reviewed the diff. ## Proposed Changes When a pull from live fails, the Agentic UI tells you to "check Studio Logs for details" and then leaves you to find them yourself. The classic UI has always offered an **Open Studio Logs** button on its error dialog; this brings that to the Agentic UI's error card. Where the host has no Studio log file to open — `studio ui` in a browser, and the hosted target — the button is hidden and the "check Studio Logs" sentence is dropped, so we don't point people at logs they can't reach. The CLI's only log directory holds per-site PHP server output, which is not where a sync failure lands, so opening it there would be misleading. <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/01b4e4a8-9e3f-4c05-bce0-eb2057d99e35" /> ## Testing Instructions Requires a site connected to a WordPress.com site. 1. `npm start`, then force a pull failure — easiest is to temporarily make `usePullSiteFromLive`'s `mutationFn` reject 2. The error card should show an **Open Studio Logs** button; clicking it opens today's `~/Library/Logs/Studio/studio-*.log`. 3. Check both light and dark. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
Merging `release/1.18.0` into `trunk`.
Via intermediate branch `merge/release-1.18.0-into-trunk`, to help fix
conflicts if any:
```
release/1.18.0 ----o-- - - -
\
merge/release-1.18.0-into-trunk `---.
\
trunk ------------x- - -
```
…ent shape (#4443) ## Related issues - None (split out of the `stu-2162-site-header-actions` exploration) ## How AI was used in this PR Claude Code cherry-picked this fix out of a larger exploration branch and verified it (the regression test, lint, typecheck) in isolation. ## Proposed Changes Fixes a crash that occurred when an app toast was updated in place and its content shape changed — for example, a running-sync toast transitioning into its success or failure result, where the result gains or loses a description. Previously React tried to update the existing `Notice` across that shape change and crashed; now the `Notice` re-mounts cleanly instead, so the toast transitions smoothly with no crash. ## Testing Instructions 1. Run the included regression test: `npm test -- apps/ui/src/components/app-toasts/index.test.tsx` — it exercises the toast-shape transition directly and must pass. 2. Manual repro (optional): trigger a toast that starts in a running state with a description (e.g. a sync in progress), then let it transition to a result state without a description (e.g. success/failure), and confirm the toast updates cleanly with no crash. ## Pre-merge Checklist - [ ] Have you checked for TypeScript, React or other console errors? Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d of the focused webview (#4442) View ▸ Reload / Force Reload / Toggle DevTools used Electron's role-based "focused webContents" target. With a site preview visible, clicking into the preview would shift focus to the guest page, so Reload reloaded the site preview instead of the app — leaving no way to reload the Studio renderer itself from the menu. These menu items now target the app window's webContents explicitly, and are relabelled "Reload App" / "Force Reload App" to make that explicit. In agentic mode, Reload App drops its ⌘R accelerator so ⌘R still reloads the preview (the renderer's own "Reload preview" shortcut); Force Reload App keeps ⌘⇧R.
Merging `release/1.18.0` into `trunk`.
Via intermediate branch `merge/release-1.18.0-into-trunk`, to help fix
conflicts if any:
```
release/1.18.0 ----o-- - - -
\
merge/release-1.18.0-into-trunk `---.
\
trunk ------------x- - -
```
---------
Co-authored-by: bcotrim <bernardo.cotrim@a8c.com>
…85 (#4475) Bumps [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action) from 1.0.183 to 1.0.185. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/anthropics/claude-code-action/releases">anthropics/claude-code-action's releases</a>.</em></p> <blockquote> <h2>v1.0.185</h2> <h2>What's Changed</h2> <ul> <li>Derive trigger timestamps for issues and pull_request events by <a href="https://github.com/ashwin-ant"><code>@ashwin-ant</code></a> in <a href="https://redirect.github.com/anthropics/claude-code-action/pull/1592">anthropics/claude-code-action#1592</a></li> <li>Pin bun config for MCP server processes by <a href="https://github.com/ashwin-ant"><code>@ashwin-ant</code></a> in <a href="https://redirect.github.com/anthropics/claude-code-action/pull/1589">anthropics/claude-code-action#1589</a></li> <li>Match downloaded images to their source URLs by asset identifier by <a href="https://github.com/ashwin-ant"><code>@ashwin-ant</code></a> in <a href="https://redirect.github.com/anthropics/claude-code-action/pull/1588">anthropics/claude-code-action#1588</a></li> <li>Check collaborator permissions for workflow_run events by <a href="https://github.com/ashwin-ant"><code>@ashwin-ant</code></a> in <a href="https://redirect.github.com/anthropics/claude-code-action/pull/1590">anthropics/claude-code-action#1590</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/anthropics/claude-code-action/compare/v1...v1.0.185">https://github.com/anthropics/claude-code-action/compare/v1...v1.0.185</a></p> <h2>v1.0.184</h2> <p><strong>Full Changelog</strong>: <a href="https://github.com/anthropics/claude-code-action/compare/v1...v1.0.184">https://github.com/anthropics/claude-code-action/compare/v1...v1.0.184</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/anthropics/claude-code-action/commit/9db594c7a0e82298c121c18b7f08aa1579ce7341"><code>9db594c</code></a> chore: bump Claude Code to 2.1.222 and Agent SDK to 0.3.222</li> <li><a href="https://github.com/anthropics/claude-code-action/commit/acb0385805f08d88fa4906025a41975ee6122e32"><code>acb0385</code></a> Check collaborator permissions for workflow_run events (<a href="https://redirect.github.com/anthropics/claude-code-action/issues/1590">#1590</a>)</li> <li><a href="https://github.com/anthropics/claude-code-action/commit/b80a0f042f2ff42ebd031d911263a059bdd9bd85"><code>b80a0f0</code></a> Match downloaded images to their source URLs by asset identifier (<a href="https://redirect.github.com/anthropics/claude-code-action/issues/1588">#1588</a>)</li> <li><a href="https://github.com/anthropics/claude-code-action/commit/6fb6bb685891c44ad1313dedad3640bcd1f485c9"><code>6fb6bb6</code></a> Pin bun config for MCP server processes (<a href="https://redirect.github.com/anthropics/claude-code-action/issues/1589">#1589</a>)</li> <li><a href="https://github.com/anthropics/claude-code-action/commit/b2963b9127309fd8ef897bb24a5d79761d566111"><code>b2963b9</code></a> Derive trigger timestamps for issues and pull_request events (<a href="https://redirect.github.com/anthropics/claude-code-action/issues/1592">#1592</a>)</li> <li><a href="https://github.com/anthropics/claude-code-action/commit/86180fa9e4d311eed10c9cc49854c53dab5d517a"><code>86180fa</code></a> chore: bump Claude Code to 2.1.221 and Agent SDK to 0.3.221</li> <li>See full diff in <a href="https://github.com/anthropics/claude-code-action/compare/be7b93b1907a4abad570368f3c74b6fe3807510b...9db594c7a0e82298c121c18b7f08aa1579ce7341">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the electron group with 2 updates: [electron](https://github.com/electron/electron) and [electron-to-chromium](https://github.com/Kilian/electron-to-chromium). Updates `electron` from 43.2.0 to 43.3.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/electron/electron/releases">electron's releases</a>.</em></p> <blockquote> <h2>electron v43.3.0</h2> <h1>Release Notes for v43.3.0</h1> <h2>Features</h2> <ul> <li>Added <code>available</code> to <code>process.getSystemMemoryInfo()</code> on Linux, exposing <code>proc/meminfo</code> MemAvailable. <a href="https://redirect.github.com/electron/electron/pull/52379">#52379</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52378">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52380">44</a>)<!-- raw HTML omitted --></li> </ul> <h2>Fixes</h2> <ul> <li>Fixed <code>BrowserWindow</code> size corruption on Windows when created with explicit <code>x</code>/<code>y</code> on a secondary monitor whose DPI differs from the primary. <a href="https://redirect.github.com/electron/electron/pull/52501">#52501</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52500">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52499">44</a>)<!-- raw HTML omitted --></li> <li>Fixed <code>Dirent.parentPath</code> being <code>undefined</code> for <code>fs.readdir</code>, <code>fs.readdirSync</code>, <code>fs.glob</code>, and <code>fs.globSync</code> with <code>withFileTypes: true</code> inside asar archives. <a href="https://redirect.github.com/electron/electron/pull/52505">#52505</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52506">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52507">44</a>)<!-- raw HTML omitted --></li> <li>Fixed <code>dialog.showOpenDialog</code>/<code>dialog.showSaveDialog</code> opening at an unusable location on Linux when <code>defaultPath</code> is a bare filename without a directory. <a href="https://redirect.github.com/electron/electron/pull/52401">#52401</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52402">44</a>)<!-- raw HTML omitted --></li> <li>Fixed a UAF with <code>protocol.registerStreamProtocol</code> when an error is emitted during a read. <a href="https://redirect.github.com/electron/electron/pull/52514">#52514</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52513">41</a>, <a href="https://redirect.github.com/electron/electron/pull/52516">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52515">44</a>)<!-- raw HTML omitted --></li> <li>Fixed a crash that could occur when closing DevTools while the host WebContents was being destroyed. <a href="https://redirect.github.com/electron/electron/pull/52510">#52510</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52512">41</a>, <a href="https://redirect.github.com/electron/electron/pull/52511">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52509">44</a>)<!-- raw HTML omitted --></li> <li>Fixed a graphical glitch on Linux where thin borders appeared past the drop shadows on frameless windows when multiple windows were created. <a href="https://redirect.github.com/electron/electron/pull/52607">#52607</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52606">44</a>)<!-- raw HTML omitted --></li> <li>Fixed an issue where loading ICO files from ASAR archives on Windows left temporary icon files behind. <a href="https://redirect.github.com/electron/electron/pull/52478">#52478</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52479">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52477">44</a>)<!-- raw HTML omitted --></li> <li>Fixed an issue where some values passed into <code>requestSingleInstanceLock</code> could result in a crash. <a href="https://redirect.github.com/electron/electron/pull/52471">#52471</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52470">44</a>)<!-- raw HTML omitted --></li> </ul> <h2>Other Changes</h2> <ul> <li>Fixed bindings for MV3 service workers. <a href="https://redirect.github.com/electron/electron/pull/52503">#52503</a></li> <li>Improved the error message when an asar integrity check fails to name the entry that failed. <a href="https://redirect.github.com/electron/electron/pull/52622">#52622</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52623">42</a>, <a href="https://redirect.github.com/electron/electron/pull/52624">44</a>)<!-- raw HTML omitted --></li> <li>Updated Chromium to 150.0.7871.212. <a href="https://redirect.github.com/electron/electron/pull/52524">#52524</a></li> <li>Updated Node.js to v24.18.1. <a href="https://redirect.github.com/electron/electron/pull/52552">#52552</a></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/electron/electron/commit/1aa21d231aeaf5634880a6e60187256e9f2fd4f9"><code>1aa21d2</code></a> chore: include the asar entry in integrity-check failure messages (<a href="https://redirect.github.com/electron/electron/issues/52622">#52622</a>)</li> <li><a href="https://github.com/electron/electron/commit/e94835eede65ad58f1924c74b96643c13c678a3f"><code>e94835e</code></a> fix: remove shadow artifacts that appear when multiple windows are created on...</li> <li><a href="https://github.com/electron/electron/commit/3bbd302e690a20ebb152808865899b20a0f8706b"><code>3bbd302</code></a> build: update PGO profiles (<a href="https://redirect.github.com/electron/electron/issues/52596">#52596</a>)</li> <li><a href="https://github.com/electron/electron/commit/8c0629ae5dde822903f5190bfe1dbc4fc8f917fc"><code>8c0629a</code></a> chore: bump node to v24.18.1 (43-x-y) (<a href="https://redirect.github.com/electron/electron/issues/52552">#52552</a>)</li> <li><a href="https://github.com/electron/electron/commit/e4976eda3553ff10ed108ccc6ab7a2bd028586c8"><code>e4976ed</code></a> ci: trigger PGO generation when a chromium roll lands on a release branch (<a href="https://redirect.github.com/electron/electron/issues/5">#5</a>...</li> <li><a href="https://github.com/electron/electron/commit/75c1164cb1603f9f45fa8a2ed1de0c2ab508a428"><code>75c1164</code></a> chore: remove dead code in autofill_popup_view.cc (<a href="https://redirect.github.com/electron/electron/issues/52549">#52549</a>)</li> <li><a href="https://github.com/electron/electron/commit/ad8aa5470eb7b6a474774f33a071a7e811b5dd3f"><code>ad8aa54</code></a> chore: bump chromium to 150.0.7871.212 (43-x-y) (<a href="https://redirect.github.com/electron/electron/issues/52524">#52524</a>)</li> <li><a href="https://github.com/electron/electron/commit/b822de9a5734ae77f90cce8e75e2df6451c6e50d"><code>b822de9</code></a> build: add extensions_renderer_generated_resources.pak (<a href="https://redirect.github.com/electron/electron/issues/52503">#52503</a>)</li> <li><a href="https://github.com/electron/electron/commit/67e5bc4bc9a3358798e3d4cbfca3bb2c8fc9f196"><code>67e5bc4</code></a> ci: enable LSan on existing Linux ASan build job (<a href="https://redirect.github.com/electron/electron/issues/52527">#52527</a>)</li> <li><a href="https://github.com/electron/electron/commit/815a20707c32014514c8fbc822326ad10c64035d"><code>815a207</code></a> fix: refactor to avoid UAF in NodeStreamLoader (<a href="https://redirect.github.com/electron/electron/issues/52514">#52514</a>)</li> <li>Additional commits viewable in <a href="https://github.com/electron/electron/compare/v43.2.0...v43.3.0">compare view</a></li> </ul> </details> <br /> Updates `electron-to-chromium` from 1.5.399 to 1.5.401 <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/Kilian/electron-to-chromium/commit/d397f68a3296a4c92d70dfdea2d83f8160e4d85e"><code>d397f68</code></a> 1.5.401</li> <li><a href="https://github.com/Kilian/electron-to-chromium/commit/2d2ec05302f38c73dcd4019afb8f4d4ee69ede03"><code>2d2ec05</code></a> generate new version</li> <li><a href="https://github.com/Kilian/electron-to-chromium/commit/f67fd9d28a32c94a0d6fd2c0d51793f40d58607b"><code>f67fd9d</code></a> 1.5.400</li> <li><a href="https://github.com/Kilian/electron-to-chromium/commit/fd0a153e8476bebf9d3baffad2d5c1717dd22c8e"><code>fd0a153</code></a> generate new version</li> <li>See full diff in <a href="https://github.com/Kilian/electron-to-chromium/compare/v1.5.399...v1.5.401">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…eslint group (#4477) Bumps the eslint group with 1 update: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint). Updates `typescript-eslint` from 8.65.0 to 8.66.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/releases">typescript-eslint's releases</a>.</em></p> <blockquote> <h2>v8.66.0</h2> <h2>8.66.0 (2026-08-03)</h2> <h3>🚀 Features</h3> <ul> <li><strong>typescript-estree:</strong> handle import.defer() as ImportExpression (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12609">#12609</a>)</li> </ul> <h3>🩹 Fixes</h3> <ul> <li><strong>eslint-plugin:</strong> [no-unnecessary-type-conversion] ignore shadowed built-ins (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12590">#12590</a>)</li> <li><strong>eslint-plugin:</strong> [prefer-nullish-coalescing] handle shadowed Boolean calls (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12591">#12591</a>)</li> <li><strong>eslint-plugin:</strong> [no-useless-default-assignment] don't report defaults used by other overloads (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12607">#12607</a>)</li> <li><strong>eslint-plugin:</strong> [no-unnecessary-type-parameters] check MappedType key remapping (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12588">#12588</a>)</li> <li><strong>eslint-plugin:</strong> [class-literal-property-style] preserve type annotations and don't drop decorators (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12617">#12617</a>)</li> <li><strong>website:</strong> list <code>onUnsupportedTypeScriptVersion</code> in parser options (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12585">#12585</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Evyatar Daud <a href="https://github.com/StyleShit"><code>@StyleShit</code></a></li> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> <li>Steffen Schroeder</li> <li>송재욱</li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.66.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md">typescript-eslint's changelog</a>.</em></p> <blockquote> <h2>8.66.0 (2026-08-03)</h2> <p>This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.</p> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.66.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/e51b11ba3ab31837762c675f62f0d4dcb1abc4fb"><code>e51b11b</code></a> chore(release): publish 8.66.0</li> <li>See full diff in <a href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.66.0/packages/typescript-eslint">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
….3 in the testing group (#4478) Bumps the testing group with 1 update: [@testing-library/user-event](https://github.com/testing-library/user-event). Updates `@testing-library/user-event` from 14.6.1 to 14.6.3 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/testing-library/user-event/releases">@testing-library/user-event's releases</a>.</em></p> <blockquote> <h2>v14.6.3</h2> <h2><a href="https://github.com/testing-library/user-event/compare/v14.6.2...v14.6.3">14.6.3</a> (2026-08-03)</h2> <h3>Bug Fixes</h3> <ul> <li><strong>release:</strong> manually release a patch version (<a href="https://redirect.github.com/testing-library/user-event/issues/1321">#1321</a>) (<a href="https://github.com/testing-library/user-event/commit/1d18b1fae589eeed8e08838672a4c2de0dcc2b36">1d18b1f</a>), closes <a href="https://redirect.github.com/testing-library/user-event/issues/1317">#1317</a></li> </ul> <h2>v14.6.2</h2> <h2><a href="https://github.com/testing-library/user-event/compare/v14.6.1...v14.6.2">14.6.2</a> (2026-08-03)</h2> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/testing-library/user-event/commit/1d18b1fae589eeed8e08838672a4c2de0dcc2b36"><code>1d18b1f</code></a> fix(release): manually release a patch version (<a href="https://redirect.github.com/testing-library/user-event/issues/1321">#1321</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/232f3e6f4f92459c02161d156a70bddd13a59eaa"><code>232f3e6</code></a> docs: add migration note and clean up README badges (<a href="https://redirect.github.com/testing-library/user-event/issues/1320">#1320</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/83e2b2261b40f5f08296eaf5af3d42018e6681ed"><code>83e2b22</code></a> ci: remove deprecated CodeSandbox CI (<a href="https://redirect.github.com/testing-library/user-event/issues/1318">#1318</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/e8da81953bd9b48512a1e4ce9b73cc36aeaeee37"><code>e8da819</code></a> ci: publish to npm via OIDC trusted publishing (<a href="https://redirect.github.com/testing-library/user-event/issues/1317">#1317</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/13fa4bc1f0dedeb866a8730fa357229832437418"><code>13fa4bc</code></a> ci: stop lint errors from blocking release (<a href="https://redirect.github.com/testing-library/user-event/issues/1316">#1316</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/c3cec1832f180b6d1dcb7c5d2b0771339dd5e848"><code>c3cec18</code></a> chore(ci): make releases work with full git history (<a href="https://redirect.github.com/testing-library/user-event/issues/1315">#1315</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/ebab6c6e81e7022af7afa5aacd07d01626895eb8"><code>ebab6c6</code></a> add Liadshiran as a contributor for doc (<a href="https://redirect.github.com/testing-library/user-event/issues/1300">#1300</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/ec470bfd55ab7a741ce2a5b71e98c0f5686ac915"><code>ec470bf</code></a> docs: fix wrong default enum value (<a href="https://redirect.github.com/testing-library/user-event/issues/1298">#1298</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/ba79c2f9a58d5927725fee506210d279fde218b5"><code>ba79c2f</code></a> chore: upgrade node version in csb (<a href="https://redirect.github.com/testing-library/user-event/issues/1299">#1299</a>)</li> <li><a href="https://github.com/testing-library/user-event/commit/63ac399e06bd8f2397a6c581915acd29235f2d38"><code>63ac399</code></a> fix: allow reassignment of <code>HTMLElement.prototype.focus</code> and <code>.blur</code> (<a href="https://redirect.github.com/testing-library/user-event/issues/1265">#1265</a>)</li> <li>Additional commits viewable in <a href="https://github.com/testing-library/user-event/compare/v14.6.1...v14.6.3">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for <code>@testing-library/user-event</code> since your current version.</p> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Related issues - Fixes [STU-2115](https://linear.app/a8c/issue/STU-2115/tracks-site-lifecycle-and-open-actions) - Part of [STU-2036](https://linear.app/a8c/issue/STU-2036/add-initial-tracks-analytics) ## How AI was used in this PR Claude Code (Opus 4.8) explored the existing Tracks infrastructure, proposed the emit-locus strategy, wrote the implementation and tests, and ran lint/typecheck/tests plus a CLI dev-smoke. I reviewed each emit point, the `failure_reason` classifier, and the stop-all counting semantics, and drove the design decisions (CLI vs Main vs renderer placement, classic-theme `entry_point` values, stop-all one-event-per-site). Then tested thoroughly and kept iterating to ensure all events are triggered correctly. ## Proposed Changes Adds the largest group of Tracks events — day-to-day site operations — so product can see how people actually use their local sites. This runs in parallel with the existing MC Stats, anonymous and opt-out-gated, following the patterns established in the initial Tracks work. It **extends** the live `studio_site_start` event with `success`, `time_ms`, `running_site_count`, and (on failure) a coarse `failure_reason`, and **adds** ten events: `studio_site_stop`, `studio_site_delete`, the "open in…" affordances (`open_in_browser`/`open_in_editor`/`open_in_terminal`/`open_wp_admin`/`open_customize`/`open_phpmyadmin`/`open_folder`), and `studio_panel_opened`. Each event is emitted at the single surface that funnels every user path exactly once: - **Start / stop / delete → the CLI.** The desktop delegates all three to the CLI, so emitting there counts standalone-CLI usage too (mirrors `studio_site_created`). - **Open in editor / terminal → Desktop Main.** These launch a local app and are the shared funnel for both the classic renderer and the agentic UI. - **The remaining open actions + panel switches → the renderer**, since they route through generic IPC that Main can't attribute. No site names, paths, or URLs are ever sent — only enumerated prop values (e.g. `entry_point`, `panel`, resolved `editor`/`terminal`). `failure_reason` is a classified low-cardinality string, never the raw error. There is **no user-visible behavior change** — the affordances behave exactly as before; they now also record analytics (subject to the existing opt-out). ## Testing Instructions 1. Start Studio: `npm start` 2. Confirm different events surface as `Would have recorded…` in the main-process terminal as you exercise the UI. **Follow-up (not in this PR):** register each new event and all its eventprops (incl. the wrapper-attached common props) via the Tracks Registration tool — documentation/CI only; it does not gate ingestion. ## Pre-merge Checklist - [ ] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… UI (#4421) - When typing a site name in the agentic UI create-site form, the **Create site** button blinked on every keystroke: each letter kicks off the async local-path suggestion, and the button was disabled for the few milliseconds until it resolved, then re-enabled. - The button now stays enabled while the path suggestion is pending. If the user submits (click or <kbd>Enter</kbd>) inside that window, the submit is queued and fires as soon as the path resolves, so a site is never created with a stale or empty path. Editing any field cancels the queued submit. - No visual/style changes — behavior only, identical in light and dark themes.
…Anthropic API key (#4480) - Copies the thinking metadata (`compat`, `thinkingLevelMap`) from pi-ai's bundled Anthropic catalog into Studio's model definition, so requests use `thinking: { type: "adaptive" }`. The values stay in sync with pi-ai upgrades, and a new test fails if a future Studio model is missing from the catalog. - Passes `allowNetwork: false` when setting the runtime API key — the implicit default triggered an awaited, unguarded network fetch of remote model catalogs on every direct-key turn (which also hung the new tests on a CI agent with slow egress). Studio hand-builds its models, so the fetch was pure latency.
…-patch group (#4486) Bumps the ruby-minor-and-patch group with 1 update: [rubocop](https://github.com/rubocop/rubocop). Updates `rubocop` from 1.88.2 to 1.89.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/rubocop/rubocop/releases">rubocop's releases</a>.</em></p> <blockquote> <h2>RuboCop v1.89.0</h2> <h3>New features</h3> <ul> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15492">#15492</a>: Add AllCops/ProjectIndexIncludesGems for bundle-wide indexing. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15498">#15498</a>: Add <code>DelegatingMethods</code> option to <code>Lint/DuplicateMethods</code> to register custom <code>delegate</code>-shaped methods. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15042">#15042</a>: Add <code>DisallowedCops</code> configuration option to <code>Style/DisableCopsWithinSourceCodeDirective</code>. ([<a href="https://github.com/hammadxcm"><code>@hammadxcm</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15441">#15441</a>: Add new <code>AllowYARDCommentBlockSeparator</code> option to <code>Layout/LeadingCommentSpace</code>. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15466">#15466</a>: Add new <code>Lint/DeprecatedReference</code> cop to detect references to methods and constants documented as <code>@deprecated</code>, powered by the project index. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15491">#15491</a>: Add new <code>Lint/NameTypo</code> cop. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15468">#15468</a>: Add new <code>Lint/UnusedPrivateMethod</code> cop for project-wide dead-code detection via the project index (disabled by default). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/14598">#14598</a>: Make <code>Style/DisableCopsWithinSourceCodeDirective</code> impossible to disable via directive comments when explicitly enabled with <code>Enabled: true</code>. ([<a href="https://github.com/rafaelfranca"><code>@rafaelfranca</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15511">#15511</a>: Support <code>textDocument/codeAction</code> requests in the built-in language server, so LSP clients that request code actions (Eglot, Helix, Flycheck, ...) can apply RuboCop's autocorrects, not only clients that read them off the published diagnostic. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/8565">#8565</a>: Support <code>NewCops</code> in department configuration to enable pending cops per department, including cops added up to a specific version (e.g. <code>Style: NewCops: '1.19'</code>). ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/9373">#9373</a>: Support autocorrection for tab indentation in <code>Layout/IndentationWidth</code> and <code>Style/ClassAndModuleChildren</code>. ([<a href="https://github.com/ioquatix"><code>@ioquatix</code></a>][], [<a href="https://github.com/koic"><code>@koic</code></a>][])</li> </ul> <h3>Bug fixes</h3> <ul> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15257">#15257</a>: Fix a false negative for <code>Lint/ToEnumArguments</code> when explicit extra keyword arguments are passed (e.g. <code>def m(x:); to_enum(:m, x: x, y: 1); end</code>), which raises <code>ArgumentError</code> when the enumerator is used. ([<a href="https://github.com/RedZapdos123"><code>@RedZapdos123</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15452">#15452</a>: Fix a false positive for <code>Layout/HashAlignment</code> when using <code>EnforcedHashRocketStyle: table</code> and a hash key spans multiple lines. ([<a href="https://github.com/dduugg"><code>@dduugg</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/12269">#12269</a>: Fix a false positive for <code>Lint/UselessAssignment</code> with modifier conditions. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/13786">#13786</a>: Fix a false positive for <code>Lint/Void</code> with setter methods. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15507">#15507</a>: Fix a false positive for <code>Naming/VariableNumber</code> when using an empty symbol hash key. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15284">#15284</a>: Fix a false positive for <code>Style/MutableConstant</code> with <code>Data.define</code>. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15483">#15483</a>: Fix a false positive for <code>Style/MissingRespondToMissing</code> when <code>respond_to_missing?</code> is defined in a reopening of the class and <code>UseProjectIndex</code> is enabled. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15500">#15500</a>: Fix an error for <code>Lint/LiteralAsCondition</code> when a literal condition has an empty branch. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15499">#15499</a>: Fix an error for <code>Lint/UselessRuby2Keywords</code> when <code>ruby2_keywords</code> is used with a symbol but no method definition is found. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15453">#15453</a>: Fix an error for <code>Metrics/MethodLength</code> when a method contains a heredoc and <code>__ENCODING__</code>. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15442">#15442</a>: Fix an error for <code>Style/ArrayIntersect</code> cop when the block-based check calls <code>member?</code>/<code>include?</code> without an explicit receiver. ([<a href="https://github.com/dduugg"><code>@dduugg</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15434">#15434</a>: Fix an error for <code>Style/NegativeArrayIndex</code> cop. ([<a href="https://github.com/viralpraxis"><code>@viralpraxis</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15469">#15469</a>: Fix an error for <code>Style/RedundantFormat</code> when a format string uses a positional argument number beyond the 64-bit range. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15454">#15454</a>: Fix an error for <code>Style/RedundantFormat</code> when the argument for a positional variable width is missing. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15298">#15298</a>: Fix an incorrect autocorrect for <code>Lint/LiteralInInterpolation</code>. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15515">#15515</a>: Fix an incorrect autocorrect for <code>Style/ArrayIntersect</code> when using safe navigation <code>none?</code> with a block. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15364">#15364</a>: Fix an incorrect autocorrect for <code>Style/MultipleComparison</code> that dropped an allowed method comparison appearing between the compared values. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15367">#15367</a>: Fix an incorrect autocorrect for <code>Style/RedundantFileExtensionInRequire</code> that produced invalid Ruby when a backslash preceded the <code>.rb</code> extension. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/12017">#12017</a>: Fix <code>Lint/Void</code> to no longer autocorrect a constant used in a void context, since removing it can change behavior through constant autoloading side effects. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/14797">#14797</a>: Avoid cache writes during server checks. ([<a href="https://github.com/sjh9714"><code>@sjh9714</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15484">#15484</a>: Fix false negatives for <code>Lint/InheritException</code> when <code>Exception</code> is inherited indirectly through a project class (<code>UseProjectIndex</code>). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15357">#15357</a>: Fix a false negative for <code>Lint/AmbiguousAssignment</code> when using attribute or index assignment. ([<a href="https://github.com/sngsmz"><code>@sngsmz</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/9571">#9571</a>: Fix false negatives in <code>Layout/ClassStructure</code> when class body elements are wrapped in <code>begin</code> blocks. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/9570">#9570</a>: Fix false negatives in <code>Layout/ClassStructure</code> when using <code>private_class_method</code> or <code>public_class_method</code> def modifiers. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15438">#15438</a>: Fix false positives in <code>Style/ArrayIntersect</code> when the receiver of <code>include?</code> in a block is not an array literal. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15445">#15445</a>: Fix false positives in <code>Style/MultilineIfThen</code> when using the Prism parser engine and an <code>elsif</code> without <code>then</code> follows a branch using <code>then</code> with a body on the same line. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15058">#15058</a>: Fix false positives in <code>Lint/DuplicateMethods</code> for anonymous classes (<code>Class.new</code>) passed as arguments to the same named-receiver method call (e.g. <code>T.cast</code>). Each <code>Class.new</code> block is an independent class, so methods defined in different blocks should not be treated as duplicates. ([<a href="https://github.com/rafaelfranca"><code>@rafaelfranca</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15486">#15486</a>: Fix false negatives for <code>Style/RedundantConstantBase</code> inside namespaces when the constant provably resolves identically without <code>::</code> (<code>UseProjectIndex</code>). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15505">#15505</a>: Fix incompatible autocorrect between <code>Style/Lambda</code> and <code>Style/SymbolProc</code> producing a syntax error like <code>->(x)(&:method)</code> when both cops run on <code>lambda { |x| x.method }</code>. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15481">#15481</a>: Fix cross-file offenses depending on which files are inspected: the project index now always covers the whole project (<code>UseProjectIndex</code>). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/13794">#13794</a>: Fix <code>Layout/LineLength</code> autocorrection for endless methods with block bodies. ([<a href="https://github.com/hervetatche"><code>@hervetatche</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15462">#15462</a>: Fix an error for <code>Lint/ConstantReassignment</code> when a built-in constant name is assigned and <code>UseProjectIndex</code> is enabled. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15321">#15321</a>: Fix <code>Style/ClassAndModuleChildren</code> ignoring <code>EnforcedStyleForClasses</code> and <code>EnforcedStyleForModules</code>, and skip autocorrection when mixed per-type styles make the result ambiguous. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md">rubocop's changelog</a>.</em></p> <blockquote> <h2>1.89.0 (2026-08-04)</h2> <h3>New features</h3> <ul> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15492">#15492</a>: Add AllCops/ProjectIndexIncludesGems for bundle-wide indexing. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15498">#15498</a>: Add <code>DelegatingMethods</code> option to <code>Lint/DuplicateMethods</code> to register custom <code>delegate</code>-shaped methods. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15042">#15042</a>: Add <code>DisallowedCops</code> configuration option to <code>Style/DisableCopsWithinSourceCodeDirective</code>. ([<a href="https://github.com/hammadxcm"><code>@hammadxcm</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15441">#15441</a>: Add new <code>AllowYARDCommentBlockSeparator</code> option to <code>Layout/LeadingCommentSpace</code>. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15466">#15466</a>: Add new <code>Lint/DeprecatedReference</code> cop to detect references to methods and constants documented as <code>@deprecated</code>, powered by the project index. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15491">#15491</a>: Add new <code>Lint/NameTypo</code> cop. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15468">#15468</a>: Add new <code>Lint/UnusedPrivateMethod</code> cop for project-wide dead-code detection via the project index (disabled by default). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/14598">#14598</a>: Make <code>Style/DisableCopsWithinSourceCodeDirective</code> impossible to disable via directive comments when explicitly enabled with <code>Enabled: true</code>. ([<a href="https://github.com/rafaelfranca"><code>@rafaelfranca</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15511">#15511</a>: Support <code>textDocument/codeAction</code> requests in the built-in language server, so LSP clients that request code actions (Eglot, Helix, Flycheck, ...) can apply RuboCop's autocorrects, not only clients that read them off the published diagnostic. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/8565">#8565</a>: Support <code>NewCops</code> in department configuration to enable pending cops per department, including cops added up to a specific version (e.g. <code>Style: NewCops: '1.19'</code>). ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/9373">#9373</a>: Support autocorrection for tab indentation in <code>Layout/IndentationWidth</code> and <code>Style/ClassAndModuleChildren</code>. ([<a href="https://github.com/ioquatix"><code>@ioquatix</code></a>][], [<a href="https://github.com/koic"><code>@koic</code></a>][])</li> </ul> <h3>Bug fixes</h3> <ul> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15257">#15257</a>: Fix a false negative for <code>Lint/ToEnumArguments</code> when explicit extra keyword arguments are passed (e.g. <code>def m(x:); to_enum(:m, x: x, y: 1); end</code>), which raises <code>ArgumentError</code> when the enumerator is used. ([<a href="https://github.com/RedZapdos123"><code>@RedZapdos123</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15452">#15452</a>: Fix a false positive for <code>Layout/HashAlignment</code> when using <code>EnforcedHashRocketStyle: table</code> and a hash key spans multiple lines. ([<a href="https://github.com/dduugg"><code>@dduugg</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/12269">#12269</a>: Fix a false positive for <code>Lint/UselessAssignment</code> with modifier conditions. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/13786">#13786</a>: Fix a false positive for <code>Lint/Void</code> with setter methods. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15507">#15507</a>: Fix a false positive for <code>Naming/VariableNumber</code> when using an empty symbol hash key. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15284">#15284</a>: Fix a false positive for <code>Style/MutableConstant</code> with <code>Data.define</code>. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15483">#15483</a>: Fix a false positive for <code>Style/MissingRespondToMissing</code> when <code>respond_to_missing?</code> is defined in a reopening of the class and <code>UseProjectIndex</code> is enabled. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15500">#15500</a>: Fix an error for <code>Lint/LiteralAsCondition</code> when a literal condition has an empty branch. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15499">#15499</a>: Fix an error for <code>Lint/UselessRuby2Keywords</code> when <code>ruby2_keywords</code> is used with a symbol but no method definition is found. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15453">#15453</a>: Fix an error for <code>Metrics/MethodLength</code> when a method contains a heredoc and <code>__ENCODING__</code>. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15442">#15442</a>: Fix an error for <code>Style/ArrayIntersect</code> cop when the block-based check calls <code>member?</code>/<code>include?</code> without an explicit receiver. ([<a href="https://github.com/dduugg"><code>@dduugg</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15434">#15434</a>: Fix an error for <code>Style/NegativeArrayIndex</code> cop. ([<a href="https://github.com/viralpraxis"><code>@viralpraxis</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15469">#15469</a>: Fix an error for <code>Style/RedundantFormat</code> when a format string uses a positional argument number beyond the 64-bit range. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15454">#15454</a>: Fix an error for <code>Style/RedundantFormat</code> when the argument for a positional variable width is missing. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15298">#15298</a>: Fix an incorrect autocorrect for <code>Lint/LiteralInInterpolation</code>. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15515">#15515</a>: Fix an incorrect autocorrect for <code>Style/ArrayIntersect</code> when using safe navigation <code>none?</code> with a block. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15364">#15364</a>: Fix an incorrect autocorrect for <code>Style/MultipleComparison</code> that dropped an allowed method comparison appearing between the compared values. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15367">#15367</a>: Fix an incorrect autocorrect for <code>Style/RedundantFileExtensionInRequire</code> that produced invalid Ruby when a backslash preceded the <code>.rb</code> extension. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/12017">#12017</a>: Fix <code>Lint/Void</code> to no longer autocorrect a constant used in a void context, since removing it can change behavior through constant autoloading side effects. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/14797">#14797</a>: Avoid cache writes during server checks. ([<a href="https://github.com/sjh9714"><code>@sjh9714</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15484">#15484</a>: Fix false negatives for <code>Lint/InheritException</code> when <code>Exception</code> is inherited indirectly through a project class (<code>UseProjectIndex</code>). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15357">#15357</a>: Fix a false negative for <code>Lint/AmbiguousAssignment</code> when using attribute or index assignment. ([<a href="https://github.com/sngsmz"><code>@sngsmz</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/9571">#9571</a>: Fix false negatives in <code>Layout/ClassStructure</code> when class body elements are wrapped in <code>begin</code> blocks. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/9570">#9570</a>: Fix false negatives in <code>Layout/ClassStructure</code> when using <code>private_class_method</code> or <code>public_class_method</code> def modifiers. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15438">#15438</a>: Fix false positives in <code>Style/ArrayIntersect</code> when the receiver of <code>include?</code> in a block is not an array literal. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15445">#15445</a>: Fix false positives in <code>Style/MultilineIfThen</code> when using the Prism parser engine and an <code>elsif</code> without <code>then</code> follows a branch using <code>then</code> with a body on the same line. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/15058">#15058</a>: Fix false positives in <code>Lint/DuplicateMethods</code> for anonymous classes (<code>Class.new</code>) passed as arguments to the same named-receiver method call (e.g. <code>T.cast</code>). Each <code>Class.new</code> block is an independent class, so methods defined in different blocks should not be treated as duplicates. ([<a href="https://github.com/rafaelfranca"><code>@rafaelfranca</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15486">#15486</a>: Fix false negatives for <code>Style/RedundantConstantBase</code> inside namespaces when the constant provably resolves identically without <code>::</code> (<code>UseProjectIndex</code>). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15505">#15505</a>: Fix incompatible autocorrect between <code>Style/Lambda</code> and <code>Style/SymbolProc</code> producing a syntax error like <code>->(x)(&:method)</code> when both cops run on <code>lambda { |x| x.method }</code>. ([<a href="https://github.com/koic"><code>@koic</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15481">#15481</a>: Fix cross-file offenses depending on which files are inspected: the project index now always covers the whole project (<code>UseProjectIndex</code>). ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/issues/13794">#13794</a>: Fix <code>Layout/LineLength</code> autocorrection for endless methods with block bodies. ([<a href="https://github.com/hervetatche"><code>@hervetatche</code></a>][])</li> <li><a href="https://redirect.github.com/rubocop/rubocop/pull/15462">#15462</a>: Fix an error for <code>Lint/ConstantReassignment</code> when a built-in constant name is assigned and <code>UseProjectIndex</code> is enabled. ([<a href="https://github.com/bbatsov"><code>@bbatsov</code></a>][])</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/rubocop/rubocop/commit/65854e6bbfe45f2f0c7f1cf33ca922a0ce82fb55"><code>65854e6</code></a> Cut 1.89</li> <li><a href="https://github.com/rubocop/rubocop/commit/f5dbd7424f63a53e48928871d47d32211c4ef446"><code>f5dbd74</code></a> Update Changelog</li> <li><a href="https://github.com/rubocop/rubocop/commit/2f96cd7afbd3a337dfdfa8371a7740c936d1043b"><code>2f96cd7</code></a> Add new Lint/NameTypo cop</li> <li><a href="https://github.com/rubocop/rubocop/commit/9a91e2bfdff2a58401aaba60e373871bd513a1e0"><code>9a91e2b</code></a> Promote the resolved-ancestry guard to ProjectIndexHelp</li> <li><a href="https://github.com/rubocop/rubocop/commit/e917b65dd3b4fbbcd97a59e7ba2e5773bf037ca0"><code>e917b65</code></a> Merge pull request <a href="https://redirect.github.com/rubocop/rubocop/issues/15522">#15522</a> from joklek-vinted/fix/mise-toml-with-single-quotes</li> <li><a href="https://github.com/rubocop/rubocop/commit/619e3d2b4bfa9b4db5d636842b594dbc6033100b"><code>619e3d2</code></a> Fix Ruby version detection from mise.toml with single quotes</li> <li><a href="https://github.com/rubocop/rubocop/commit/7999d1adf6d51e5d08015f4f15b4ca8ccb0955c8"><code>7999d1a</code></a> [Fix <a href="https://redirect.github.com/rubocop/rubocop/issues/15501">#15501</a>] Improve <code>Style/RedundantLineContinuation</code> performance on adjacen...</li> <li><a href="https://github.com/rubocop/rubocop/commit/63d936157714d38cbcf09058d1a8212e8f72427f"><code>63d9361</code></a> Advertise executeCommandProvider in the language server</li> <li><a href="https://github.com/rubocop/rubocop/commit/893a02f681e0ad75f555001f45c9ef42d52ad6c1"><code>893a02f</code></a> Cache the LSP project index across requests</li> <li><a href="https://github.com/rubocop/rubocop/commit/3b9755f3dc50d81b28ed00fc343872ca218eb2de"><code>3b9755f</code></a> Merge pull request <a href="https://redirect.github.com/rubocop/rubocop/issues/15516">#15516</a> from koic/fix_a_flaky_line_length_spec_timeout_on_j...</li> <li>Additional commits viewable in <a href="https://github.com/rubocop/rubocop/compare/v1.88.2...v1.89.0">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Related issues - Fixes [STU-2119](https://linear.app/a8c/issue/STU-2119/tracks-preview-site-events) ## How AI was used in this PR Claude Code explored the existing Tracks patterns (the sibling STU-2115/STU-2116 work), drafted and verified the plan, and implemented the events, tests, and docs. I reviewed the emitter loci, the CLI-vs-renderer split, and the delete-all decision, and verified the emit paths myself (unit tests + a CLI smoke test confirming channel attribution). ## Proposed Changes Preview-site sharing (WordPress.com hosted previews) had no analytics, so we couldn't tell how many users share their work via preview links, or how reliable create/update is in the field. This adds Tracks events across the preview-site lifecycle: - `studio_preview_site_create` / `studio_preview_site_update` — with `success`, `failure_reason`, and `time_ms`, so we get both adoption and a success/latency funnel. - `studio_preview_site_delete` — a single preview deleted. - `studio_preview_site_delete_all` — the "delete all" action, carrying a `count` of previews removed. - `studio_preview_site_open` — a user opening a preview URL to visit it. Create/update/delete/delete-all all fire from the **CLI**, which is the sole funnel: the desktop Previews tab delegates every one of these actions to the app-spawned CLI, so each action is counted exactly once whether it originated in the UI or standalone, and is attributed to the right surface via `channel`/`ui_version`. `open` has no CLI equivalent and fires from the renderer. No PII is ever sent — no site names, paths, or URLs; `failure_reason` is a coarse, low-cardinality bucket and the raw error is never included. ## Testing Instructions 1. Start Studio `npm start` 2. Open a site's **Previews** tab. 3. Create, Update, Delete, and Delete-all a preview site; confirm the console logs `Would have recorded Tracks event: studio_preview_site_*` with `channel: studio-ui` and the correct `ui_version`, and that each action logs exactly once. 4. Click a preview's URL and confirm `studio_preview_site_open` logs. 5. Confirm CLI paths: `studio preview create/update/delete [--all]` log the same events with `channel: studio-cli`. ## Follow-up (issue DoD, not code) Each event and all its eventprops (including the wrapper-attached common props) still need registering via the Tracks Registration tool — documentation/CI integrity, separate from ingestion. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## Related issues - Related to [STU-2016](https://linear.app/automattic/issue/STU-2016/workbench-orientation-an-orientation-guide-a-getting-started-checklist) ## How AI was used in this PR Implemented with Claude Code; Reviewed and tested manually. ## Proposed Changes Adds a first-run orientation guide to the agentic UI — a focused three-page modal that introduces the sidebar, Studio Code, and the live preview. It opens once on first arrival in the workbench and can be reopened anytime from **Help ▸ Getting Started**. The copy adapts to the user: - **New vs migrating** (page 1): a fresh install is welcomed to Studio; someone coming from classic Studio is reassured their sites and files carried over. - **Studio Code available vs not** (pages 2–3): when chat is on, the guide teaches building by asking and the realtime preview; when it isn't — signed out, offline, or turned off in Settings → AI — it points to the site overview and the plain preview instead. Seen-state persists (desktop `app.json`, browser `localStorage`) and is versioned, so it never nags but can be re-shown after a redesign. | Step 1 | Step 2 | Step 3 | |--------|--------|--------| | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/15cfd803-c7c5-4e24-93cb-58c6668b57af" /> | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/81e1314f-9d6e-4c53-9989-499de99b210a" /> | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/ae05f13a-3167-4e58-9556-3b88dfb0c7d4" /> | | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/48aa70f7-affc-4bba-87d0-07cff44f14b3" /> | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/8a9e43da-88e2-4180-9531-f155c8e5b673" /> | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/23d51e7c-abbe-46e1-ac7d-91aa50e4a23f" /> | ## Testing Instructions 1. Enable the **Agentic UI** beta feature and open a site's workbench. 2. Choose **Help ▸ Getting Started** — the guide opens. 3. Page through it: **Back** appears from page 2, the dots stay centered, the last button (**Let's go**) closes it. Confirm **Esc** and the **✕ Skip** button also close it. 4. Signed in with Studio Code on, pages 2–3 read *Build by asking* / *See your site update in realtime*. 5. Turn agentic features off in **Settings → AI** (or sign out), reopen from Help — pages 2–3 now read *Manage your site* / *See your site inline*. 6. Verify in both light and dark mode. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: Shaun Andrews <shaun@automattic.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## Related issues - None ## How AI was used in this PR AI assisted with implementation, iterative UI refinement, test coverage, and verification. The final behavior and visual treatment were reviewed interactively in the desktop app. ## Proposed Changes <img width="286" height="196" alt="image" src="https://github.com/user-attachments/assets/51425d97-ad93-46e0-b055-7f6f72b217fa" /> <img width="290" height="251" alt="image" src="https://github.com/user-attachments/assets/f0686bd6-fe5c-4528-884b-e1d90161c44b" /> - Add a compact BETA affordance above Settings so people can identify the agentic Studio experience without competing with sidebar messages or onboarding tasks. - Let people switch back to Studio Classic or send feedback from an anchored menu. - Show the running Studio version in the menu to make feedback and troubleshooting more useful. - Keep the affordance accessible with stable filled active states and an offset keyboard-focus outline. ## Testing Instructions 1. Start Studio with the agentic UI enabled. 2. Confirm the BETA badge appears above Settings and does not overlap sidebar messages. 3. Open the badge menu and verify “Switch to Studio Classic,” “Send feedback,” and the current Studio version. 4. Verify the badge remains blue while the menu is open and shows an offset outline for keyboard focus. 5. Check both light and dark appearance modes. ### Screenshots <!-- SCREENSHOT_MENU --> <!-- SCREENSHOT_DEFAULT --> ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: bcotrim <bernardo.cotrim@a8c.com>
## Related issues - Related to STU-1988 ## How AI was used in this PR Claude wrote the code, taking legacy UI as the baseline. I manually reviewed and tested it. ## Proposed Changes The "What's New" announcements now appear in the agentic UI. | Light | Dark | |--------|--------| | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/bec8a336-cf76-4fd0-b5b9-e7a1413a715d" /> | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/464c2834-5cc1-480d-a209-af8c9064908c" /> | ## Testing Instructions 1. Edit `~/.studio/app.json` and remove `lastSeenVersion` 2. `npm start` 3. What's new should be displayed 4. Closing the app and restarting should not show What's new again 5. Navigate to the menu **Help —> What's new** and confirm the modal is shown again 6. Test in both light and dark modes ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
…le (#4336) This adds a lint rule that catches the mistake at author time and makes the existing offenders lazy so they react to language changes: - New `studio/no-module-level-translations` ESLint rule flags `__()`, `_x()`, `_n()`, and `_nx()` calls that run at module scope. It allows translations wrapped in a function (evaluated at render/call time) and ignores bare discarded statements used only to feed the translation extractor. - The rule is turned off where a stale string is impossible: `apps/cli` (one-shot process that loads its locale before importing modules) and `apps/ui` (the agentic UI reloads the window on language change). It stays enforced for the long-lived desktop renderer and the shared `packages/common` code it imports. - Documents the convention in `AGENTS.md`. - Makes all flagged strings lazy (widget/control labels, settings, skills constants, shared `packages/common` helpers, etc.), so they now follow the active language after a runtime switch. Shared config labels (e.g. `supportedEditorConfig[ … ].label`, `terminalConfig[ … ].name`) became functions, and all their consumers — including code that landed on trunk while this branch was open — were updated to call them. No user-visible text changes; the user-facing effect is that affected labels now translate correctly when the language is changed without a restart.
## Related issues - Related to #4462 ## How AI was used in this PR AI helped extract the Open in experience and overview shortcut styling from the larger site-overview prototype into an independently reviewable change. I reviewed the resulting diff and verified it independently. ## Proposed Changes <img width="1051" height="661" alt="SCR-20260806-nord" src="https://github.com/user-attachments/assets/54308c36-1dd1-4d0c-afc0-71cbb8afb709" /> - Bring the familiar Open in actions onto the Agentic UI site overview so users can hand a site off to Finder, their configured editor, or their terminal without first opening the preview menu. - Keep phpMyAdmin alongside those local development tools, matching the workflow available in the Classic Studio overview. - Present Customize, Open in…, and Manage as consistent responsive button grids that expand to three columns and collapse cleanly with the preview open. - Hide actions that are unavailable in the current host or have not been configured, avoiding controls that cannot complete successfully. - Match Classic's terminal failure handling with console logging, Sentry reporting, and a user-facing alert. ## Testing Instructions 1. Open a local site's Overview tab and confirm an Open in… section appears between Customize and Manage. 2. Confirm Finder, the configured editor, Terminal, and phpMyAdmin open the expected destination. 3. Clear the preferred editor and confirm its shortcut is omitted while the remaining actions stay available. 4. Hide and show the preview panel. Confirm all three shortcut sections use equal-width columns and reflow without clipping or wrapping labels. 5. Run the hosted UI and confirm the entire Open in… section is omitted where local OS integration is unavailable. 6. Check the overview in both Light and Dark appearances. Automated verification: - `npx eslint --fix` on all modified files - `npm run typecheck` - `npm test -- apps/ui/src/components/open-in-menu/index.test.tsx apps/ui/src/components/site-overview-view/index.test.tsx` - `npm run cli:build:ui` ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: bcotrim <bernardo.cotrim@a8c.com>
## Related issues - Related to #4462 - Stacked on #4469 ## How AI was used in this PR Codex helped extract this focused slice from the larger proof of concept, add the responsive layout and tests, and run the verification workflow. I reviewed the resulting scope and tested the UI in wide and narrow panels in both light and dark themes. ## Proposed Changes <img width="1392" height="782" alt="image" src="https://github.com/user-attachments/assets/2b47da15-6a20-4cd3-875c-785bbfb24207" /> <img width="1035" height="757" alt="image" src="https://github.com/user-attachments/assets/d0cbd1f2-4099-48a4-9b11-c4dc2c39c803" /> <img width="378" height="158" alt="image" src="https://github.com/user-attachments/assets/3d3148e1-913d-4cbc-af1f-43c3b4817ac9" /> - Give each local site a compact About summary with its cached site thumbnail, full active-theme name, and WordPress/PHP versions on one secondary line. - Restore Classic's browser affordance by making the thumbnail open the site externally, including an always-visible fallback action when no screenshot has been captured yet. - Introduce a responsive two-column Overview layout so site information sits beside its actions on wide panels while actions remain first when the preview narrows the panel. - Keep disk usage out of this PR so its filesystem measurement and breakdown can be reviewed as a separate, independently useful follow-up. ## Testing Instructions 1. Open a local site's Overview with the preview hidden and confirm About appears beside Customize, Open in…, and Manage. 2. Open the preview and confirm the action sections remain first, with About below them. 3. Confirm the theme name wraps instead of truncating and the versions read as `WP v… • PHP v…`. 4. Click the thumbnail and confirm the site opens in the external browser. Repeat with a site that has no cached screenshot and confirm the empty frame still offers “Open site.” 5. Repeat in light and dark appearance modes. Automated verification: - `npx eslint --fix` on all modified TypeScript/TSX files (CSS files are not covered by the ESLint configuration) - `npm test -- apps/ui/src/components/site-overview-view/index.test.tsx` (25 tests) - `npm run typecheck` - `npm run cli:build:ui` ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: bcotrim <bernardo.cotrim@a8c.com>
## Related issues - Related to #4462 ## How AI was used in this PR AI helped extract this focused slice from the larger overview exploration, implement the filesystem measurement and connector plumbing, and add tests. I reviewed the resulting diff and manually verified the rendered overview in both light and dark modes. ## Proposed Changes <img width="1354" height="912" alt="image" src="https://github.com/user-attachments/assets/5e9b8506-961e-45b8-bf03-8e1ecad8383c" /> <img width="339" height="190" alt="image" src="https://github.com/user-attachments/assets/9d1cc70f-7d9f-4fb9-87cb-4e0ba91e7da2" /> - Show each local site's total disk usage directly in the About card, with an accessible visual breakdown for Media, Plugins, Themes, Database, and Other files. - Measure storage without following symlinks or issuing unbounded filesystem work, so large local sites do not make the overview unnecessarily disruptive. - Keep the summary useful across both the desktop app and local browser UI; hosted sites gracefully omit local disk data. ## Testing Instructions - Open a local site's Overview and confirm the About card shows a Disk total. - Hover anywhere on the bar, then focus it with the keyboard, and confirm the floating legend shows every category with its color, size, and percentage. - Check the card in both light and dark appearance modes. - Verify sites with little or no data render without a broken or empty breakdown. Automated verification: - `npx eslint --fix <modified files>` - `npm run typecheck` - `npx vitest run packages/common/sites/storage-usage.test.ts --maxWorkers=1` - `npx vitest run apps/ui/src/components/site-overview-view/index.test.tsx --maxWorkers=1` - `npx vitest run apps/cli/tests/local-server.test.ts --maxWorkers=1` - `npm run cli:build:ui` ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
…ew (#4460) ## Related issues <!-- Link a related issue to this PR. If the PR does not immediately resolve the issue, for example, it requires a separate deployment to production, avoid using the "Fixes" keyword and use "Related to" instead. --> Related to STU-2193 ## How AI was used in this PR <!-- Help reviewers understand what to look for and verify that you've reviewed the code yourself. --> It was used to implement the changes. ## Proposed Changes <!-- Explain the intent of this PR: - What problem does it solve, or what need does it address? - How does it affect the user (new capability, fix, performance, accessibility, etc.)? - Note any user-visible behavior changes or trade-offs. Focus on the "why" and the user impact. Avoid listing modified files or describing implementation mechanics — the diff already shows that. --> This PR ensures that when there are unsubmitted but saved changes in annotate mode and you navigate in the preview mode, the changes remain saved until submitted. ## Testing Instructions <!-- Add as many details as possible to help others reproduce the issue and test the fix. "Before / After" screenshots can also be very helpful when the change is visual. --> * Pull the changes from this branch * Start Studio with `npm start` * Ensure that you are in the agentic UI * Start a site and annotate something * Save the changes but don't submit your annotation * Navigate somewhere else in preview * Come back to the page where annotation was * Confirm the unsubmitted annotation is still there * Compare the changes to trunk where this annotation would be lost https://github.com/user-attachments/assets/fac69901-f2bd-4339-a45f-d7455fce1e33 ## Pre-merge Checklist <!-- Complete applicable items on this checklist **before** merging into trunk. Inapplicable items can be left unchecked. Both the PR author and reviewer are responsible for ensuring the checklist is completed. --> - [ ] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>
## Related issues - Fixes [STU-2164](https://linear.app/a8c/issue/STU-2164/use-danger-styling-for-site-delete-actions) ## How AI was used in this PR Claude Code wrote the change and the dialog tests. Reviewed and verified manually. ## Proposed Changes Deleting a site is irreversible, but neither entry point looked it. The sidebar site context menu's "Delete site" now reads red, and its confirmation now uses the design system's destructive-confirm pattern (`AlertDialog` + `intent="irreversible"`), so the confirm button is red and the dialog announces itself as an alert, blocks dismissal mid-delete, and surfaces failures inline. "Delete all preview sites" in Settings → Usage gets the same red treatment. | Delete Site | Delete Preview | |--------|--------| | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/baa03117-11a0-46d4-9272-9b94020372cd" /> | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/6020dc64-f54c-4be0-a010-e64968e6c5a4" /> | ## Testing Instructions 1. Right-click a site in the sidebar → "Delete site" is red; the rest of the menu is not. 2. Click it → confirmation modal's "Delete site" button is red. Cancel. 3. Repeat in the other color scheme (Settings → Appearance). 4. Settings → Usage → Preview sites ⋮ → "Delete all preview sites" is red (needs an account with preview sites). ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
## Related issues - Related to #4441 ## How AI was used in this PR Codex implemented the illustrations and animation choreography through an iterative visual-review process. The output was repeatedly reviewed in the running Electron app, with manual direction on composition, timing, zoom, controls, iconography, and light/dark appearance. ## Proposed Changes - Complete the welcome tour with animated Manage and Preview illustrations instead of placeholder artwork. - Show the current site overview experience, including the About summary and the complete set of site-management shortcuts. - Demonstrate preview switching between the site, WordPress, and database tabs, followed by the annotation workflow and replay state. - Respect reduced-motion preferences and adapt the illustrated UI to light and dark appearances. ## Demo ### Manage  ### Preview  ## Testing Instructions 1. Run `npm start` and open the welcome tour from the app. 2. Verify the signed-out tour shows the Manage illustration on its second page. 3. Verify the Preview illustration switches through the three preview tabs, reveals the Annotate control and tooltip, adds a comment and annotation markers, and ends with Replay. 4. Check the Manage and Preview illustrations in both light and dark appearances. 5. Enable reduced motion and verify each illustration rests on a useful static frame. 6. Run: - `npx eslint --fix apps/ui/src/components/onboarding-guide/illustrations/index.tsx apps/ui/src/components/onboarding-guide/illustrations/overview.tsx apps/ui/src/components/onboarding-guide/illustrations/preview.tsx` - `npm run typecheck` - `npm test -- apps/ui/src/data/onboarding/use-orientation-autostart.test.ts apps/ui/src/data/onboarding/use-whats-new-autostart.test.ts` - `npm run cli:build:ui` ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
## Related issues - Related to [STU-2117](https://linear.app/a8c/issue/STU-2117/tracks-import-and-export-events) ## How AI was used in this PR Implemented with Claude Code (exploration, implementation, and tests), following the patterns from the earlier Tracks PRs (STU-2115/2116/2119). Reviewed by the author. ## Proposed Changes Adds two Tracks events replacing the MC Stats import/export counters (which stay in place for the parallel-run phase): - `studio_site_imported` — `success`, `importer_type` (`jetpack`/`local`/`playground`/`sql`/`wpress`/`xml`/`unknown`), `time_ms`, and a coarse `failure_reason` on failure. - `studio_site_exported` — `success`, `export_type` (`full`/`db`), `time_ms`, and a coarse `failure_reason` on failure. Both are emitted only by the CLI `import`/`export` commands (the sole funnel, same as `studio_site_created` and the preview events), so desktop, agentic UI, and standalone CLI usage are all counted once, attributable via `channel`/`ui_version`. The events deliberately mean **a user imported/exported a backup**. Flows that reuse the same CLI commands as an implementation detail — add-site-flow imports (Classic add-site, agentic onboarding, browser-UI import route), sync-pull imports, and sync-push exports — pass a hidden `--suppress-tracks-event` flag and emit nothing. As a side benefit over the MC Stats counters, this stops sync operations from inflating import/export numbers, and the `importer_type` prop correctly reports `xml` (WXR) imports, which MC Stats counted as "unknown importer". `failure_reason` is a low-cardinality classification — the raw error message is never sent (it can carry file paths). Notes for reviewers: - An import that completes but whose server restart fails reports `success: true` — `success` reflects the import itself; the command still exits non-zero. - An aborted sync export emits nothing (the CLI process is SIGTERM'd), matching today's MC Stats behavior. - `importer_type` is `unknown` when the failure occurs before a concrete importer starts; `failure_reason` carries the phase signal there. - `failure_reason` is derived from machine-readable codes on `LoggerError` (locale-independent), attached at the throw sites. As a side effect, several deep errors were promoted from plain `Error` to `LoggerError`, and the redundant logger-mode `IMPORT_ERROR`/`EXPORT_ERROR`/`BACKUP_EXTRACT_ERROR` wrap-throws were removed — so standalone CLI output for `import`/`export`/`push`/`pull` now shows the specific error (e.g. `Database export failed`) instead of a generic `Import failed:`/`Push failed:` prefix. Nothing parses those prefixes. - The `previousError` merge in `import`/`pull` no longer overwrites an existing cause when a post-import server restart also fails — the root cause stays in the report. Follow-up (not code): register both events with **all** eventprops (including the wrapper-attached common props `channel`, `ui_version`, `is_a11n`, `platform`, `arch`, `app_version`) via the Tracks Registration tool. ## Testing Instructions 1. Import a backup into an existing site from the desktop Import/Export tab (dev build) 2. Check the `Would have recorded Tracks event studio_site_imported…` log line 3. Verify the add-site import flow and sync push/pull log no import/export events. 4. Confirm exports triggered through CLI report `Would have recorded Tracks event studio_site_imported…` lines ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## Related issues - Fixes STU-1946 ## How AI was used in this PR Claude Code assisted with mapping the legacy selective-sync implementation via a few iterations. All changes were reviewed and visually verified by hand in both color schemes. ## Proposed Changes As agreed in STU-1946, the Agentic UI adopts the classic UI's Selective Sync as-is for the beta, so both UIs offer the same sync capabilities. To keep review easy, the legacy modules were intentionally copied verbatim into `apps/ui/src/components/selective-sync/`. Note, there is an existing issue in `trunk` - UI says that the Push is finished, hovewer it isn't. This issue is not covered in this PR - DOTPROD-170. ## Testing Instructions 1. Open Agentic UI, connect a site to a local site 2. Click on Pull and Push and assert that the dialog looks completely the same as in Classic UI and selection works well in the tree <table> <tr> <td><img width="1410" height="1025" alt="Screenshot 2026-07-28 at 16 40 58" src="https://github.com/user-attachments/assets/99e9515b-ce18-4836-8c3a-59529f9bf578" /> <td><img width="1417" height="1028" alt="Screenshot 2026-07-28 at 16 42 10" src="https://github.com/user-attachments/assets/e46e24e7-ffd6-4ce4-b452-37881ed1dc47" /> </tr> <tr> <td><img width="1416" height="1032" alt="Screenshot 2026-07-28 at 16 41 16" src="https://github.com/user-attachments/assets/ae6c5c1d-aa0c-4217-9fd2-1078eb12d0d8" /> <td><img width="1413" height="1031" alt="Screenshot 2026-07-28 at 16 40 32" src="https://github.com/user-attachments/assets/c08f54ce-7b2b-4493-9dd1-fc19a7c835c4" /> </tr> </table> 3. Try to pull all data or select for example only `themes` folder and assert that it works well. 4. You can test the push action too; it works, but there is an existing bug which is not covered in this PR (DOTPROD-170). --------- Co-authored-by: bcotrim <bernardo.cotrim@a8c.com>
## Related issues - Fixes STU-2124 ## How AI was used in this PR AI assisted with reproducing the failure, tracing it to the schema mismatch between Playground's JS schema and the one bundled in blueprints.phar, and drafting the fix and tests. I reviewed the change and verified it locally against the Stylish Press Blueprint. ## Proposed Changes Creating a site from the Stylish Press Blueprint failed under the native PHP runtime. The cause is a schema mismatch, not a parsing failure. Studio pre-validates a Blueprint with Playground's JS schema, then hands it to `blueprints.phar`, which validates it again against its own v1 schema. That schema accepts only `features.networking`, so a Blueprint setting `features.intl` is rejected outright rather than having the flag ignored: ``` Invalid Blueprint v1 provided. See the validation errors below: Blueprint root["features"]["intl"]: Property "intl" isn't allowed here. Allowed properties are: networking. ``` `intl` and `preferredVersions` are both environment choices the runner does not make here. Studio picks the PHP binary and installs WordPress before the Blueprint runs. `normalizeBlueprintForRunner` now strips both, extending the `preferredVersions` handling that was already inline. Studio's PHP builds ship the Intl extension, so dropping the flag loses nothing. ## Testing Instructions 1. Check out this branch and run `npm run cli:build`. 2. Save the Stylish Press Blueprint to a file: ```sh curl -s "https://public-api.wordpress.com/wpcom/v2/studio-app/blueprints" \ | python3 -c "import json,sys; print(json.dumps([b for b in json.load(sys.stdin)['blueprints'] if b['slug']=='stylish-press-2'][0]['blueprint']))" \ > /tmp/stylish-press.json ``` 3. Before this change, the next step fails with `Failed to apply Blueprint`. Create a site from the Blueprint under the native runtime: ```sh node apps/cli/dist/cli/main.mjs site create --name repro --path /tmp/repro-site \ --wp latest --runtime native --blueprint /tmp/stylish-press.json --no-start --skip-browser ``` 4. The command exits `0` and prints `Site created successfully`. 5. Confirm the Blueprint actually applied, rather than being skipped: ```sh ls /tmp/repro-site/wp-content/plugins # includes woocommerce ls /tmp/repro-site/wp-content/themes # includes stylish-press-theme ``` 6. In the app: enable the native PHP runtime, create a site from the **Stylish Press** blueprint, and confirm it creates and opens. 7. Regression: `features.networking` still reaches the runner, and a Blueprint with no `features` key is unchanged. Both are covered by the unit tests below. **Tests:** `npm test -- apps/cli/lib/native-php/tests/blueprints.test.ts` → all 5 pass. **Reset (to re-test):** ```sh node apps/cli/dist/cli/main.mjs site delete repro --delete-files rm -rf /tmp/repro-site /tmp/stylish-press.json ``` ## Pre-merge Checklist - [ ] Have you checked for TypeScript, React or other console errors?
## Related issues - Fixes STU-2157 ## How AI was used in this PR Tested manually first to confirm the issue. Fix was implemented with Claude. Manually reviewed and confirmed the fix ## Proposed Changes When the agent asks a question, the bottom of the question card could end up hidden underneath the composer, so the last option wasn't visible or clickable — leaving the run blocked on a choice the user couldn't see. <img width="3248" height="2120" alt="image" src="https://github.com/user-attachments/assets/325ef4a4-ecac-48f5-b333-05a1ed087c48" /> ## Testing Instructions 1. Open a chat and get the agent to ask a question — e.g. *"Use the AskUserQuestion tool to ask me 2 questions about how I'd like this site styled, with 3 options each."* 2. Before it answers, grow the composer past ~96px: type several lines of text, or drag the composer's resize handle up. 3. When the question appears, all of its options should be visible above the composer. On trunk the last option is cut off; the taller the composer, the more is hidden. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
## Related issues - Depends on WordPress/reprint#436 and WordPress/reprint#540 - Fixes STU-2180 - Supersedes #4401 ## How AI was used in this PR Codex wrote the whole thing based on a detailed upfront plan that I drafted with Claude. The process was highly iterative. ## Proposed Changes The `pull-reprint` command in Studio currently both reads and writes private Reprint state. This was implemented as a temporary measure to make selective sync work, and I'm now working on making the necessary upstream changes and then adapting Studio accordingly. Here are the specific changes in this PR: - Studio was reading Reprint state and index files when preparing a pull. This has been replaced with Reprint's updated `import-metadata` command (see WordPress/reprint#436). - Eventually, Studio should use Reprint to get a file tree from the remote server. However, for now, we will rely on the same Jetpack-powered approach we already use in the `pull` command to get the file tree. - Because Reprint cannot yet sync only individual file paths (see WordPress/reprint#539), the file selector has been made to only display directories. This should be reverted once we have an upstream fix in place. - Pass `--target-engine` and `--target-sqlite-path` to the `apply-runtime` Reprint command. If a user pulls a remote site for the first time and deselects the database, this ensures Reprint still knows to configure the site to use a SQLite database. This part depends on WordPress/reprint#540. This PR depends on WordPress/reprint#436 and WordPress/reprint#540 being included in the bundled PHAR. To make things easier for testers, I've simply committed the patched PHAR. ## Testing Instructions 1. `npm run cli:build` 2. Create a new site for testing and `cd` into it 3. `STUDIO_ENABLE_PULL_REPRINT=1 studiodev pull-reprint` 4. Ensure that the file picker displays successfully 5. Deselect the database and ensure that the sync finishes successfully (and that the site works) 7. Ensure that a second partial file sync also finishes successfully ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
Studio's agentic UI always routes chat through the WordPress.com AI service. This PR lets users bring their own Anthropic API key instead: - The **AI settings** page gains a **"Use your Anthropic API key"** section, in both the browser UI (`studio ui`) and the desktop app's agentic UI. A toggle picks the provider and a field below it holds the key. The key is write-only: the renderer only ever receives a truncated preview (`sk-ant-api03-6Ic...lgAA`), never the key itself. - **Settings live in `~/.studio/shared.json`** (the Desktop↔CLI shared config, next to the WordPress.com auth token), so the CLI, browser UI, and desktop stay in sync. Reads fall back to the legacy `cli.json` location, and a new CLI migration (`apps/cli/migrations/08-move-ai-settings-to-shared.ts`) moves `aiProvider`/`anthropicApiKey` over and strips them from `cli.json` on first run. - **The key is validated and saved as you type** (debounced): it is checked against Anthropic and a rejected key is not stored — the section shows why, and the field gets a matching error border. The toggle stays disabled until a key has been saved, and switching it on re-checks the key so one revoked since it was saved is caught too. Fail-open throughout: if Anthropic is unreachable (offline, outage), the key is accepted. - Clearing the field removes the key and falls back to the WordPress.com provider. - With the Anthropic provider active, the **model picker only offers Anthropic models** (Sonnet 5, Opus 5) — the provider can't serve other families. - Resumed conversations keep the provider they started with; only new conversations pick up the switch. - A new Tracks event, **`studio_setting_ai_provider_change`**, is emitted from the desktop settings handlers when the provider or key presence actually changes (`provider`, `has_anthropic_api_key`, `surface` — the key itself is never sent). Documented in `docs/design-docs/analytics-tracks.md`. - The shared store (`packages/common/ai/settings-store.ts`) tolerates unknown `aiProvider` values by falling back to WordPress.com instead of failing, and preserves unrelated config fields untouched.
## Related issues - Fixes [STU-2114](https://linear.app/a8c/issue/STU-2114/tracks-onboarding-and-authentication-events) ## How AI was used in this PR I used Claude Code to explore the onboarding and auth flows, drafted the plan, and iteratively wrote the implementation and tests. I reviewed the emission points, and the privacy boundaries. ## Proposed Changes Onboarding and WordPress.com login had no Tracks coverage at all, which made the onboarding funnel our biggest blind spot: we could not say how many new users finish onboarding, how many leave with an account connected, where people log in from, or how often auth fails. This adds two events: | Event | Answers | | -- | -- | | `studio_onboarding_complete` | Completion volume, and whether the user finished with an account (`authenticated`) | | `studio_wpcom_auth` | Login outcomes by entry point (`source`), new vs existing account, and why auth failed | I decided to merge `studio_onboarding_wpcom_auth` and `studio_wpcom_auth` events as they would be almost duplicates. Two smaller changes to scope from Linear issue: `success` + `failure_reason` instead of `result`, to match every other outcome event in the catalog (`studio_site_start`, `studio_site_imported`, …); and `source` gained four values for entry points the issue's list missed (`overview_tab`, `site_header`, `add_site`, `cli`) plus `unknown`. ### Implementation notes for reviewers - `source`/`account_type` are known only when auth *starts*, but the outcome arrives later in a deep link carrying only a token. A Main-process pending context (`apps/studio/src/lib/auth-tracks-context.ts`) bridges the two — consumed once, 15-minute TTL, last-write-wins on concurrent attempts. When the link can't be made (restart mid-flow, cold-start deep link, expiry) the event still fires with `source: unknown` rather than guessing. - Both emitters record **after** the token is written, because the wrappers derive `is_a11n` from it. Recording earlier would tag every Automattician's login as `false`. There are tests pinning this ordering. - `source` is a **required** parameter on `useAuth().authenticate` / `useLogin` / `AuthActions`, so a missed call site is a compile error rather than silent `unknown` data. This is what confirmed all 13 sites were covered. - No emails, user ids, tokens, or raw error text are ever sent. ## Testing Instructions Events are logged to console instead of sending in dev mode. **CLI**: 1. Build the CLI: `npm run cli:build` 2. Then, against a throwaway HOME so your real token is untouched: ```bash TMPHOME=$(mktemp -d) HOME="$TMPHOME" STUDIO_FORCE_CLI_TELEMETRY=1 NODE_ENV=development node apps/cli/dist/cli/main.mjs auth login ``` 3. Test the flow providing the bad token. 4. Then try again with correct token. 5. Confirm `Would have recorded Tracks event: studio_wpcom_auth` was logged to console. 6. When done, remove the temp directory: ``` rm -rf "$TMPHOME" ``` **Desktop** 1. Start the app against throwaway home: (`TMPHOME=$(mktemp -d); DEV_CONFIG_DIR="$TMPHOME" npm start`, watch the **Main-process terminal**): 2. With no sites and onboarding not yet completed, press **Skip** → `studio_onboarding_complete` with `authenticated: false`. To test the other case, stop the app, remove home, and create a new one 4. Log in from the Classic UI's top bar → `studio_wpcom_auth` with `success: true`, `source: top_bar`, `account_type: existing`. 7. Deny authorization on WordPress.com → `success: false`, `failure_reason: access_denied`, with the same `source`/`account_type`. 8. Spot-check other entry points report their own `source`: Sync tab (`sync_tab`), Previews (`previews_tab`), Settings → Account (`settings`), the agentic Overview sign-in box (`overview_tab`), and the agentic UI's top-bar site dropdown (`site_header`). 9. **Add site → Connect a site**, signed out → `add_site`. 10. "Create a free account" anywhere → `account_type: new`. 11. When done, remove the temp directory: ``` rm -rf "$TMPHOME" ``` ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors? --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…ws and Linux (#4499) ## Related issues - Fixes [STU-2211](https://linear.app/a8c/issue/STU-2211/window-controls-overflow-the-agentic-ui-frame-on-windows-and-linux) ## How AI was used in this PR Claude mapped the frame/overlay code paths, implemented the change, and measured the resulting geometry and surface colors in the running UI. I reviewed the diff and the reasoning. ## Proposed Changes - On Windows and Linux the minimize/maximize/close controls sat outside the agentic UI's rounded frame, in a mismatched strip jutting past its top and right edges. The controls are painted by Electron at the window's own bounds, but the frame is inset by 12px, so they could never line up. The frame now goes full-bleed when the window-controls overlay is present — the same shape the classic UI has always had — and the controls land inside the frame's own header. - Trade-off: Windows and Linux lose the frame's inset/rounded look. Shrinking the controls isn't an option (Electron exposes only colour and height, no width) and wouldn't help anyway, since the overhang comes from the anchoring, not the size. Flushing only the top and right edges would leave a lone 12px bottom inset that reads as a mistake. - macOS is unaffected — it reserves space separately via `trafficLightPosition`. | macOS | Windows | Settings | Add Site | |--------|--------|--------|--------| | <img width="3248" height="2122" alt="image" src="https://github.com/user-attachments/assets/fa61f81a-d2ef-446d-a4b4-16102a3f2d2a" /> | <img width="3022" height="1728" alt="image" src="https://github.com/user-attachments/assets/2706be9e-07bd-4068-9f8c-7acd392b9a05" /> | <img width="3024" height="1732" alt="image" src="https://github.com/user-attachments/assets/1af53177-49ae-4e00-b7a2-a0512fd18eb3" /> | <img width="3024" height="1728" alt="image" src="https://github.com/user-attachments/assets/f9c91242-80dd-49ab-8920-231cd1dec377" /> | ## Testing Instructions 1. Run Studio on Windows or Linux with the agentic UI. 2. Top-right corner: the controls sit inside the frame's header, on a matching background — not in a strip above and right of it. 3. Check with the preview open and closed, in light and dark, and after maximize/restore. macOS regression check: the frame keeps its 12px inset and rounded corners, and the traffic lights are unchanged. One thing worth a close look: with the preview **closed** in dark mode, the surface behind the controls is `rgb(30,30,30)` while the overlay paints `rgb(36,36,36)`. Expected to be imperceptible; if it reads as a seam, the fix is per-route `setTitleBarOverlay()` colours. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
…te (#4522) ## Related issues - Fixes STU-2243 - Stacked on #4510 — review that one first; this PR targets its branch and will retarget to `trunk` once it lands. ## How AI was used in this PR Written with Claude Code, after tracing how the classic renderer handles the same flow. ## Proposed Changes A push now stays in progress until the live site has actually been updated. Previously it announced "Push complete" as soon as the archive finished uploading, while WordPress.com was still taking its safety backup and importing — so the app looked done, the live site wasn't, and a second push failed with "another import is already in progress". The push also stops reading as idle. Instead of showing "Preparing the live site…" for its whole duration, it names the phase it's in and how far along it is: creating the backup, uploading, backing up the remote site, applying changes, almost there — the same wording the classic UI uses. Failures now say what went wrong, distinguishing a failed database import from a timeout on a too-large site. Cancelling is unaffected: a push is still stoppable until the remote import starts, and refused after. ## Testing Instructions 1. Connect a site to WordPress.com and push it from the site dropdown. Use a site large enough that the remote backup takes a moment. 2. The dropdown should step through the phases with percentages, and **not** toast "Push complete" when the upload finishes. 3. Confirm the live site reflects the change by the time the toast appears. 4. Start a second push immediately after the first completes — it should not fail with "another import is already in progress". 5. Cancel a push during "Creating backup…"/upload — still works; once it reaches "Backing up remote site…" the X is dimmed. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
…-into-release-1.18.0 # Conflicts: # RELEASE-NOTES.txt
AliSoftware
left a comment
There was a problem hiding this comment.
@bcotrim trunk into the currently flying release/1.18.0 release branch…
I'm not 100% how much of your team's release process might differ from how we do it in other apps, but usually we cut release/1.18.0 branch from trunk when we start the code-freeze (to freeze the code, that we plan to ship as a version 1.18, for the duration of beta-testing / smoke-testing the changes before sending it to end users), and then merge release/1.18 into trunk (not the other way around)
By having this PR merging trunk into release/1.18, i.e. the other way around, this means you suddenly will include many new PRs and features/fixes, that have landed in trunk way after you cut release/1.18.0 branch to freeze the code for version 1.18 on Aug 6. This means that the release/1.18 which presumably already started its beta-testing will suddenly get a buttload of new features and PRs that landed in trunk and were not there at the time you code-froze release 1.18 initially.
Maybe that is intentional for some reason (due to a different way you do your release process in studio that I'm not aware of, or a rationale for an exception this time around that I'm missing), but just wanted to flag it to be extra sure that adding so many commits and trunk PRs into the release/1.18.0 branch 1 week after its code-freeze was intentional vs a misclick in the direction you created this PR?
Marking as "Request changes" until I get more info to ensure it's not merged accidentally by habit, happy to revise the review if this is truly justified and not an error
|
Maybe I should have read the PR description more carefully before jumping to look at the diff and replying hastily though 😅
Still would love a double-confirmation to be extra sure, given how uncommon this is and how easily it could have been an AI misinterpreting a prompt the wrong way. Happy to approve once you confirm 🙂 |
📊 Performance Test ResultsComparing 6f7fc94 vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
|
My intention is to bring everything from trunk now into a new code freeze for the next release. My plan is to merge this trunk (once approved and green CI) and proceed with the release normally by creating a new beta and running smoke tests. Does this look good? Thank for the review @AliSoftware 🙇 |
Ok sounds good 👍 Then if that's the goal, then this makes sense to me, and reassures me that this was intentional and not a misclick or mistake 👍 Approving now. |
|
Exactly!
I didn't consider closing/deleting the release branch and starting a new code freeze, would that have made things cleaner? Next time we could do it differently |
|
PS: May I suggest to use "Add Notes" in ReleasesV2 to leave breadcrumbs about this decision in the release 1.18.0? I think something like below will be enough, but given ReleasesV2 is meant to be the source of truth for anyone in the company who wants to follow-along the status of the release, or for your future selves to understand what happened (and why the dates changed) when you might look at stats or release retrospectives in many months, leaving a breadcrumb in ReleasesV2 would allow to connect the dots 🙂
|
There was a problem hiding this comment.
Nice catch remembering to update the release notes 👍
I think both are ultimately OK and mostly equivalent… though now that I think of it, we may be missing some details (especially translatable strings, see below) with the way you did it here. Personally I think I'd probably have gone with "delete the branch and redo the code-freeze again" mostly because:
So maybe re-doing the code-freeze to ensure the string bundles are regenerated to include potential new strings introduced in The only risk that I identify of redoing the code-freeze is that the new code-freeze will redo a version bump (54334b6) to |
|
@bcotrim I looked at the Fastfile and what were the details of what we are doing in TL;DR: It's ok to merge this instead of deleting the release/ branch and creating it anew, as long as we verify the As part of the
|
|
Nice catch @AliSoftware, thanks for checking that! 🙇 |
Re-running `bundle exec fastlane generate_pot_file` after #4536 merged `trunk` into the `release/1.18.0` branch, in order to make sure the `.pot` file that will be sent to translation picks up any latest strings that might have been added to `trunk` since the original code freeze that did it in 0d4d002
Done: #4541 |
…from trunk (#4541) - **Resynchronizing `bundle-strings.pot` after \#4536** ## Related issues N/A ## How AI was used in this PR No AI was ~~harmed~~ used in the making of this PR ## Proposed Changes ### Why? / Context The team recently decided to delay the Studio release `1.18.0` to Friday, Aug 14, and as a result merged all the recent commits from `trunk` into `release/1.18.0` (via #4536) to incoroprate all the latest features/fixes from `trunk` in that `1.18.0` release. As discussed in #4536 (comment), because this was done by merging `trunk` into the existing `release/1.18.0` (that had been cut during the code-freeze one week ago on Aug 6)—as opposed to the `release/1.18.0` branch being deleted and the code-freeze being re-done from scratch—this means that the `generate_pot_file` action that is usually called during `code_freeze`, to generate the `bundle-strings.pot` file with strings to be sent for translation, was not called again, and that `bundle-strings.pot` file was thus not updated with any new string that might have been added in `trunk` since Aug 6. ### How? / The fix To fix that, I've run `npm install && bundle exec fastlane generate_pot_file` from the `release/1.18.0` manually (after #4536 got merged) to update the `bundle-strings.pot`, resulting the diff in this PR. Note that I've encountered the `The await using declaration should be first transformed by \`@babel/plugin-transform-explicit-resource-management\`` errors in the logs when running this lane on my machine, but this is an unrelated known issue, for which there's already a Draft PR #4467 ## Testing Instructions N/A Just check the diff makes sense ## Pre-merge Checklist - [ ] Have you checked for TypeScript, React or other console errors?
Related issues
How AI was used in this PR
Claude verified the merge is content-identical to
trunkand regenerated theRELEASE-NOTES.txtdraft using the same GitHub generate-notes call thecode_freezelane makes.Proposed Changes
1.18.0 slipped to Friday, so the Aug 6 freeze is 58 commits behind
trunk. This bringsrelease/1.18.0back up totrunkand refreshes the draft release notes so they cover everything actually shipping in 1.18.0.Nothing on the release branch is lost:
git merge-tree --write-tree origin/release/1.18.0 origin/trunkproduces the same tree asorigin/trunk^{tree}, i.e. the merge is a no-op againsttrunk.The notes are still the auto-generated draft — the Pre-Release step curates them the way 1.17.0's section was.
Testing Instructions
RELEASE-NOTES.txtlists 149 PRs, ending at Agentic UI: Wait for the remote import before reporting a push complete #4522.git diff origin/trunk origin/release/1.18.0is empty (barring anything new landing ontrunkmeanwhile).Pre-merge Checklist