mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-02 18:18:35 +09:00
0.296.0
6658
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
631ea07068 | Merge branch 'main' into release-31-08-2026.staging 0.296.0 | ||
|
|
c9618de88b |
fix: Scaffold projects with attribute aliases (#6300)
## Summary - recover from every standard HTML/SVG and React attribute alias collision during generated JSX export - keep the last persisted value for non-class collisions, matching existing duplicate-prop recovery - merge distinct class aliases with generated atomic classes - keep shared collision validation strict in authoring, import, MDX, and instance-conversion paths ## Implementation The React SDK generator now normalizes safe instance props before generating JSX. One map keyed by the final JSX name provides deterministic last-value recovery for exact duplicates and non-class aliases. A second map keyed by the original class spelling preserves one value per class alias so those composable values can be merged into the single emitted `className` attribute. Projected resource props use the same normalized-name set, avoiding a second route to duplicate generated JSX properties. ## Checklist - [x] Reproduce the reported `class`/`className` failure on unchanged `main` - [x] Reproduce non-class failures including `tabindex`/`tabIndex`, `for`/`htmlFor`, and `readonly`/`readOnly` - [x] Cover every current standard-to-React alias pair in both persistence orders - [x] Preserve exact duplicate-prop last-value behavior - [x] Merge distinct class aliases with atomic classes - [x] Keep strict shared validation outside generated JSX recovery - [x] Review documentation impact; no user-facing documentation changes are required - [x] Review fixture impact; no fixture inputs or generated fixture outputs are affected - [x] Run targeted tests, typecheck, lint, build, and direct generator reproducers - [ ] Run `pnpm evaluations` if explicitly approved ## Verification - `pnpm --filter @webstudio-is/react-sdk exec vitest run src/component-generator.test.tsx --pool=forks` — 156 passed - `pnpm --filter @webstudio-is/content-engine exec vitest run src/jsx-attributes.test.ts --pool=forks` — 3 passed - `pnpm --filter @webstudio-is/react-sdk typecheck` - `pnpm --filter @webstudio-is/react-sdk build` - `pnpm exec oxlint --deny-warnings packages/react-sdk/src/component-generator.ts packages/react-sdk/src/component-generator.test.tsx` - direct generator reproducers now emit one normalized property for `tabIndex`, `htmlFor`, and `readOnly` The exhaustive regression test is derived from the shared attribute mapping, currently covering 105 non-class pairs in both orders; the separate class test covers exact duplicate recovery, distinct alias merging, and atomic classes. Agent evaluations were not run because they require explicit approval. Closes #6299 |
||
|
|
1de752f2ae |
fix: Keep Slot colors consistent (#6296)
## Summary - Define the purple treatment as a semantic secondary-accent CSS color family. - Use its foreground in the Layers panel and its background/on-background pair on the canvas. - Add visual regression coverage that shows the actual Navigator and canvas Slot treatments together. - Keep the same purple in light mode and use a more chromatic, readable foreground in dark mode. ## Implementation The dark-theme migration replaced the former reusable-instance color with two unrelated choices: the blue accent foreground in the navigator and an accent-derived purple canvas fill. This change adds three generated, theme-aware semantic colors using Craft's existing naming and explicit foreground pairing conventions: - `--background-accent-secondary` for Slot canvas labels and outlines. - `--foreground-accent-secondary` for reusable instances in the navigator. - `--foreground-on-accent-secondary` for content on the strong secondary-accent background. The secondary accent derives from the theme accent. Its foreground keeps the existing strong purple in light mode and raises dark-mode lightness without washing out its chroma, so reusable instances remain visibly distinct from ordinary Navigator text. Portable light and dark visual stories render the real `NavigatorTree` beside the real canvas `Outline` and `Label` Slot variant. This covers the user-reported cross-surface consistency and the dark-mode foreground directly. ## Todo - [x] Trace the regression to the color-system migration. - [x] Add the secondary-accent semantic CSS family and generated types. - [x] Add foreground/background contrast contracts across supported themes. - [x] Update navigator and canvas consumers. - [x] Add light and dark visual regression coverage for the actual Navigator and canvas treatments. - [x] Confirm the visual comparison fails before approval and inspect the rendered screenshot. - [x] Run Design System and focused Builder tests. - [x] Run Design System and Builder typechecks, scoped lint, and formatting checks. - [x] Review fixture impact; no fixture inputs or generated fixture outputs are affected. - [x] Review documentation impact; update the internal color-system reference. Authoritative user documentation is unaffected. ## Verification - `pnpm --filter @webstudio-is/design-system test` — 223 tests passed. - `pnpm --filter @webstudio-is/builder exec vitest run --project core-browser-builder-features app/builder/features/navigator/navigator-tree.test.ts` — 20 tests passed. - The dark secondary-accent regression test was confirmed to fail with the washed-out foreground, then pass with the stronger chromatic foreground. - `pnpm --filter @webstudio-is/design-system typecheck` — passed, including generated color-type freshness. - `pnpm --filter @webstudio-is/builder typecheck` — passed. - Scoped `oxlint --deny-warnings` — passed. - Scoped `oxfmt --check` — passed. - `pnpm visual-regression -- --base origin/main --grep "Builder/Navigator/Navigator tree"` — expected failure with two added visual stories; both light and dark screenshots were inspected. The source-contract test was confirmed to fail before the semantic variables were added, then pass with the implementation. Browser contrast tests cover both new pairings across light/dark modes and the complete supported theme parameter range. Closes #6295 |
||
|
|
4a10645cb8 |
docs: Explain Builder themes and CSS warnings (#6298)
## Summary - Document the shared System, Light, and Dark interface-theme preference in the Dashboard and Builder guides. - Distinguish the Webstudio interface theme from the authored site's color scheme. - Explain experimental, nonstandard, and obsolete CSS property warnings in the Advanced Style panel. - Add focused, matching light- and dark-theme screenshots of the released Dashboard controls. ## Implementation The Dashboard guide owns the screenshot and complete theme explanation. The Builder anatomy guide documents the Builder menu path and links to that canonical section. The screenshot pair was captured from the released interface, cropped to the smallest useful region, and excludes account identity. ## Checklist - [x] Document the Dashboard theme path and available preferences. - [x] Document the Builder theme path and canvas-theme boundary. - [x] Explain CSS property status warnings and MDN compatibility details. - [x] Capture and visually review matching light/dark screenshots. - [x] Review documentation impact and update all affected authoritative `docs/` pages. - [x] Verify internal anchors, asset references, image formats, and the final diff. ## Verification - `git diff --check` — passed. - Screenshot assets — verified as 366×100 PNG files with equivalent UI state and no account identity. - Referenced files and `#interface-theme` / `#example-dark-mode` anchors — verified. - Repository formatter — not applicable; `oxfmt` excludes these documentation targets. - Tests — not run; documentation and screenshot assets only. - Fixture inputs and generated outputs — unaffected. ## Known limitations None. Closes #6297 |
||
|
|
f4eeff0ddf | build: Release 31-08-2026 0.295.0 | ||
|
|
81d3ddf076 |
fix: tolerate duplicate props during JSX export (#6294)
## Summary - tolerate duplicate persisted props during JSX generation - preserve the last value for a duplicate prop name - add regression coverage for duplicate Image width props ## Verification - `pnpm --filter @webstudio-is/react-sdk exec vitest run src/component-generator.test.tsx --pool=forks` - `pnpm --filter @webstudio-is/content-engine exec vitest run src/jsx-attributes.test.ts --pool=forks` - `pnpm --filter @webstudio-is/react-sdk typecheck` |
||
|
|
7bec7c0488 |
fix: Share split button active state (#6290)
Ref #3818 ## Summary - Apply the primary toggle’s pressed surface to both split-button segments. - Keep both buttons independently actionable and preserve their shared hover behavior. ## Implementation The split-button directly styles the adjacent menu segment when the primary segment has `aria-pressed`. The menu segment keeps its separate action and expanded hit target, so Builder state and color logic are not duplicated. ## Todo - [x] Share the active surface across both segments. - [x] Preserve independent actions, disabled behavior, and shared hover behavior. - [x] Verify light and dark Storybook rendering. - [x] Run typecheck and lint. - [x] Review documentation impact — no documentation changes are required for this restored component behavior. ## Verification - `pnpm --filter @webstudio-is/design-system typecheck` - `pnpm lint` No fixture inputs or generated fixture outputs are affected. |
||
|
|
a8c1726418 |
fix: stabilize CLI bundle contract after publish (#6293)
## Summary - bundle Zod into the published CLI because `bundleVersion` derives from Zod schema internals - bundle `@emotion/hash`, which produces the contract identifier - prevent compatible dependency updates at install time from changing an already-published CLI's contract - add regression coverage for the CLI bundling boundary ## Root cause `webstudio@0.294.0` externalized `zod` and declared `^4.4.3`. The Builder was built with the lockfile version, while a fresh `npx webstudio@latest` installation resolved Zod 4.5.4. Because the project bundle contract is calculated at runtime from Zod definitions, the Builder expected `bundle-1mym82p` while the freshly installed CLI sent `bundle-8e39e9` despite both being the same Webstudio release. ## Packaged CLI reproduction Tested the CLI built from the parent commit and this branch in the same isolated `webstudio@0.294.0` installation with Zod 4.5.4. Both builds executed the real local `webstudio sync` command against the same capture server. - Before: `{"label":"before","zod":"4.5.4","bundleVersion":"bundle-8e39e9"}` - After: `{"label":"after","zod":"4.5.4","bundleVersion":"bundle-1mym82p"}` - Live Builder: `{"bundleVersion":"bundle-1mym82p"}` The fixed local CLI now sends the exact contract required by the live Builder even though the install environment still contains Zod 4.5.4. ## Verification - isolated before/after packaged CLI test through the real `sync` request path - `pnpm --filter webstudio exec vitest run src/cli-bundle-externals.test.ts` - `pnpm --filter webstudio typecheck` - `pnpm --filter webstudio build` - verified emitted CLI files contain no external imports from `zod` or `@emotion/hash` - `pnpm exec oxfmt --check packages/cli/vite.config.ts packages/cli/src/cli-bundle-externals.test.ts` - `git diff --check` |
||
|
|
c49c0786be |
fix: unify dashboard background surface (#6287)
## Description 1. What is this PR about (link the issue and add a short description) ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file |
||
|
|
f953d1be37 |
fix: Restore the login background gradient (#6286)
## Summary Restores the original Webstudio login gradient after the color-system migration added a dark scrim over it. Fixed Webstudio identity artwork now belongs to the Design System, while generic surfaces, content, translucency, and overlays use the semantic color system instead of a Builder-local brand color bag. ## Architecture - The Design System exports only the fixed Webstudio background gradient, progress gradient, and progress shadow as brand artwork. - Generic black, white, translucent panel, and scrim entries were removed rather than moved. - Login and error surfaces use semantic light/dark pairings. - Project-card tags derive their local 30% scrim from the semantic overlay color. ## Todo - [x] Restore the original login gradient without a scheme-dependent scrim. - [x] Move fixed identity artwork into the Design System package. - [x] Remove the Builder-local brand color registry. - [x] Replace generic fixed colors with semantic colors or local derivations. - [x] Add explicit dark-mode Storybook coverage for the login screen. - [x] Run Design System and Builder typechecks. - [x] Run Design System tests, scoped lint, formatting, and package-boundary validation. - [x] Review documentation impact and document ownership in the Design System color README. ## Verification - Design System tests: 222 passed. - Design System and Builder typechecks: passed. - Scoped Oxlint and formatting: passed. - Package-boundary validation: passed. - Focused visual regression: 23 affected stories compared; the newly added dark login story is the only difference. - Fixture impact: no fixture inputs or generated outputs are affected. Ref #3818 |
||
|
|
4273b7001f |
refactor: Organize Builder development and test tooling (#6285)
## Outcome Builder development, backend, E2E, and CI tooling now share one ownership model: Builder defines named commands and backend modes, while CI only schedules those commands. ## Technical choices - Group shared Compose files, PostgreSQL initialization, and backend helpers under `apps/builder/backend`. - Resolve `compose.<mode>.yaml` by convention instead of maintaining Compose filename lists in scripts and workflows. - Keep persistent development and disposable test Compose projects separate by default, while allowing the standard `COMPOSE_PROJECT_NAME` override. - Make schema snapshots invalidate from discovered migration sources and backend files. - Move E2E behavior recipes into named Builder commands; retain concise root proxies for developer entry points. - Let Vitest allocate available browser ports instead of maintaining a cross-package port registry. - Keep test-suite scheduling explicit in `main.yml`, but move executable test commands to root package scripts. - Move fixture-size enforcement from inline GitHub JavaScript into a locally runnable repository script. ## Todo - [x] Consolidate Builder backend and Compose ownership. - [x] Add named development, E2E, schema-cache, Supabase, and CI-shard commands. - [x] Remove Compose topology and behavior flags from CI. - [x] Remove the static Vitest browser-port registry. - [x] Extract fixture-size checking from the workflow. - [x] Verify migration bootstrap, snapshot-backed E2E, tests, builds, types, formatting, lint, generated contracts, and workflow syntax. - [x] Review documentation impact: updated the E2E developer guide; no user-facing `docs/` content is affected. ## Verification - Full package, CLI, Builder core, and Builder app test suites - Full workspace typecheck - Builder production build - Schema-cache generation through the complete migration history - Supabase migration compatibility - Snapshot-backed Playwright animation workflow - Backend regression tests, including demonstrated fail/pass coverage - All four Compose mode configurations - `oxfmt`, `oxlint`, package boundaries, generated API, and generated docs checks - `actionlint` and Bash syntax checks The fixture-size checker preserves the existing Linux `du` thresholds. Its three inputs build locally; macOS allocation sizes are not directly comparable to the Linux CI thresholds, so CI remains the authoritative size result. |
||
|
|
bc8630f413 |
fix: Gate Builder releases on the published CLI contract (#6282)
Closes #6280 ## Summary - Expose the deployed Builder's CLI-facing bundle contract through a non-cached, read-only endpoint. - Resolve and execute the exact `webstudio@latest` registry artifact, observe the bundle version sent by its real `sync` request, and require an exact match before assigning the release staging alias. - Include expected and received bundle versions in runtime and release-gate errors. ## Technical choices - The existing generated `bundleVersion` remains the single compatibility boundary. Builder-only changes outside that project-bundle contract do not require a CLI release. - The CLI sync probe runs against a local fixture API and temporary directory. It reads the deployed runtime contract but never reads or modifies a Cloud project. - Verification runs after Vercel creates the exact production-built deployment and before the release staging alias is assigned. A mismatch therefore leaves production domains untouched. - Registry resolution requires version and integrity metadata, then executes the resolved immutable version rather than source from the checkout. - The gate requires the deployed Builder origin and cannot fall back to the checkout's contract. ## Todo 1. [x] Add the deployed Builder contract endpoint. 2. [x] Probe the exact published CLI through its real sync request. 3. [x] Gate the release staging alias on an exact contract match. 4. [x] Report expected and received versions for compatibility failures. 5. [x] Add regression tests and verify the production Builder build. 6. [x] Review documentation and fixture impact. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run app/services/build-router.server.test.ts app/services/cli-compatibility-route.node.test.ts` — 12 passed. - `pnpm --filter webstudio exec vitest run scripts/builder-contract-gate.test.ts scripts/release-smoke-registry.test.ts` — 7 passed. - Rebased onto `main` at `9ec4c820e1`. - Builder and CLI typechecks passed. - `pnpm lint` and changed-file formatting passed. - `pnpm --filter @webstudio-is/builder build` passed and emitted `/rest/cli-compatibility`. - The changed GitHub Action parses as valid YAML. - Real registry probe passed for `webstudio@0.293.0` against `bundle-kzb45v`. - Real registry probe correctly blocked current Builder contract `bundle-1mym82p` and reported expected `bundle-1mym82p`, received `bundle-kzb45v`. - Missing staged Builder origin fails closed before registry execution. - GitHub CI passed all four workflows, including all six Builder E2E shards. - The formerly failing empty-MDX insertion workflow passed 8 repeated runs with 4 workers locally, then passed in Builder E2E shard 4 in CI. - Full browser-based release smoke was not run, per the request not to use Chrome. Agent evaluations were not run because no evaluation approval was requested or received. - Documentation: no user-facing documentation changes are required. - Fixtures/generated outputs: no fixture inputs or generated outputs are affected. ## Operational boundary The check needs the exact deployed runtime, so Vercel creates an unaliased `--skip-domain` deployment before verification. A failed check cannot affect production domains or the normal release alias. Repository automation cannot prevent a Vercel administrator from manually promoting an arbitrary deployment outside this release path. |
||
|
|
9ec4c820e1 |
fix: Use writable npm cache for previews (#6272)
## Summary - Use a writable `.webstudio/preview/.npm-cache` for npm preview installs when `npm_config_cache` is not explicitly configured. - Preserve explicit npm cache settings and pnpm behavior. - Document a safe recovery path that requires no cache deletion. This removes preview startup failures caused by an unwritable default npm cache. Initial dependency installation and its network/download cost still remain when preview dependencies are not already installed. ## Technical choices - Keep the cache beside the isolated generated preview because that directory is already writable and reused across regenerations. - Let an explicit `npm_config_cache` continue to take precedence. - Do not retry arbitrary install failures or classify package-manager prose. ## Todo - [x] Reproduce npm dependency installation against an unwritable cache before changing code. - [x] Reproduce #6274 at the same dependency-install stage used by session-backed screenshots. - [x] Demonstrate the regression assertion failing before the fix and passing afterward. - [x] Use the preview-local cache only for npm without an explicit cache. - [x] Preserve explicit npm cache configuration and pnpm behavior. - [x] Verify the real dependency installer against an unwritable project npm cache. - [x] Verify session-backed screenshot flow proceeds from successful preview preparation to browser capture. - [x] Review documentation impact and update the CLI manual plus generated MCP documentation. - [x] Review fixture impact; no project fixture inputs or outputs are affected. - [x] Review the final diff for correctness, duplication, and unnecessary complexity. ## Verification - Actual npm install reproduced #6269 and #6274 with `EPERM` against an unwritable cache. - Real preview dependency installation passed after the fix while project npm configuration still pointed at that cache. - Fail-before/pass-after regression demonstrated. - `pnpm --filter webstudio test` — 65 files, 1,044 tests passed. - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm check:generated-docs` - Formatting and diff checks passed. - GitHub CI after rebasing onto current `main` — 30 checks passed, 7 skipped, no failures. - Agent evaluations were not run because they require separate explicit approval. Closes #6269 Closes #6274 |
||
|
|
1b48716ff4 |
docs: Document MDX-backed Content Blocks (#6273)
## Summary - Document how people create, connect, edit, validate, and publish MDX-backed Content Blocks. - Document the complete MCP workflow, including scoped expression sources, frontmatter updates, diagnostics, conflicts, and disconnect behavior. - Add two focused screenshots for the human workflow. - Fix issues found by a low-reasoning MCP agent while executing every documented workflow. Ref #6182 ## Implementation notes - Connection confirmation uses the public `confirmReplacement` field because `confirm` is reserved as a hidden transport field. - MCP edits frontmatter with `update-content-block-frontmatter`; materialized MDX elements are not persistent targets for generic instance mutation tools. - Reload now intentionally discards a conflicted local source and accepts the Asset's latest storage revision before an edit is reapplied. - Generated MCP documentation and runtime contracts are updated from their source files. ## Checklist - [x] Document the human MDX Content Block workflow. - [x] Document MCP discovery, connection, editing, diagnostics, frontmatter, dynamic sources, conflicts, and disconnection. - [x] Add only screenshots that clarify otherwise hard-to-describe UI steps. - [x] Test every documented MDX capability through the local MCP CLI with a low-reasoning agent. - [x] Reproduce and fix the replacement-confirmation schema mismatch. - [x] Reproduce and fix persistent-session conflict reload and reapply. - [x] Add regression tests that failed before each product fix and pass afterward. - [x] Regenerate runtime contracts and generated MCP documentation. - [x] Review authoritative `docs/` content and update affected pages. - [x] Run affected tests, typechecks, formatting, and diff checks. ## Verification - Project Build: 208 affected tests passed. - Content Engine Asset session: 8 tests passed. - CLI documentation tests: 14 tests passed. - MCP docs generator: 3 tests passed. - Content Engine, Project Build, CLI, and MCP docs typechecks passed. - `pnpm oxfmt --check` passed. - `git diff --check` passed. - Low-reasoning MCP evaluation passed all documented workflows, including a real two-client revision conflict, reload, reapply, and final saved inspection. |
||
|
|
8718feb465 |
test: simplify browser testing infrastructure (#6271)
## Summary Unifies frontend testing around three intentional boundaries: - Vitest Node projects for pure and server tests - Vitest Browser Mode with Playwright/Chromium for DOM and component tests - Playwright Test for Builder end-to-end workflows The Builder no longer uses jsdom. Ordinary E2E workflows use an automatically managed isolated `page` fixture; explicit contexts remain only for simultaneous identities and suite-scoped setup. ## Technical choices - Split Builder tests into one Node project and independent browser projects so each Chromium/Vite process has a bounded workload. - Added shared Browser Mode configuration for the affected SDK React packages. - Preserve the Builder's production top-window bridge ownership; Browser Mode uses explicit test-only installation seams. - Centralized Playwright context options and kept action/navigation timeouts bounded. - Validate Playwright filters before Docker, migrations, browser installation, or Builder builds start. - Preserve the first failed E2E attempt's report, traces, screenshots, and videos when CI retries a shard. - Split static checks, typechecks, CLI tests, core package tests, browser package tests, and Builder projects into parallel CI jobs with five-minute hard ceilings. - Distribute Builder E2E tests across ten isolated shards with two workers; parallel suites create unique per-worker setup data. - Reuse color contrast DOM/canvas samples so the exhaustive theme sweep takes about four seconds instead of timing out at 30 seconds. - The removed cost is jsdom behavior drift, oversized serial check jobs, and unnecessary E2E startup for empty selections. Real browser startup and E2E environment setup remain. ## Todo - [x] Split Builder pure/server tests from browser/component tests. - [x] Migrate Builder DOM tests from jsdom to Vitest Browser Mode. - [x] Migrate affected SDK React DOM tests to the shared Browser Mode setup. - [x] Remove jsdom annotations, dependencies, and compatibility setup. - [x] Replace ordinary manual E2E contexts with the isolated `page` fixture. - [x] Keep explicit contexts only for concurrent identities and `beforeAll` setup. - [x] Preserve setup authentication isolation from workflow pages. - [x] Add bounded Playwright action and navigation timeouts. - [x] Preserve first-attempt E2E failure evidence across CI retry. - [x] Reject empty E2E selections before expensive environment setup. - [x] Parallelize repository checks into bounded CI shards. - [x] Isolate parallel E2E setup data across workers. - [x] Remove the color contrast sweep bottleneck. - [x] Update E2E contributor documentation. - [x] Review product documentation impact; no user-facing product docs are affected. - [x] Run the full repository tests and typechecks. - [x] Run formatting, lint, package-boundary, generated-file, and fixture checks. - [x] Complete final correctness and simplification review. ## Verification - `pnpm --filter @webstudio-is/builder test` - `pnpm -r typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` - `pnpm fixtures` - Design-system: 222 tests pass locally. - Builder: all seven Vitest projects pass locally. - The formerly slow E2E shard passes locally in 1m55s. - Full database-backed Builder E2E execution passes in CI. - All CI jobs pass; the slowest completed in 4m58s. - No fixture inputs/outputs or generated files changed. Ref #6270 |
||
|
|
f6c524572d |
feat: add Builder dark theme and rebuild colors
## Summary
Rebuilds Webstudio’s color system, migrates the entire Builder to it,
and introduces a complete dark theme.
A small set of theme colors and contrast controls now drives the
interface through relative CSS colors:
```text
Theme colors and contrast
↓
Light/dark derivation bounds
↓
Derived color families
↓
Reusable semantic colors
↓
Component composition
↓
Builder interface
```
CSS is the runtime source of truth. Light and dark modes share the same
theme inputs, so changing a theme color automatically updates its
surfaces, content, borders, states, and component presentation. The
refactor turns dark mode into a first-class Builder theme rather than a
separately maintained palette.
This is an atomic migration. Legacy color names and compatibility
aliases will not remain after all consumers have moved.
## Scope
- The color source, derivation model, semantic vocabulary, validation,
typing, and Storybook overview.
- Every design-system component.
- Builder, dashboard, authentication, shared UI, Query Builder, stories,
and tests that consume the legacy color scale.
- Removal of the legacy Stitches color scale after its final consumer is
migrated.
- A complete dark theme across application UI while keeping authored
canvas content independent.
- Complete light and dark visual verification.
- Unified browser-test infrastructure: Vitest Browser Mode for Design
System browser contracts and standard Playwright Test for all Builder
E2E workflows.
Literal colors remain only where color is the actual content or belongs
to a deliberately separate system, such as user-authored values,
external previews, brand artwork, data visualization, functional canvas
overlays, and source assets. Every remaining exception must have an
explicit owner.
## Architecture decisions
- Theme authors control six color families and three bounded contrast
controls.
- Relative CSS colors derive the rest of the system.
- Dark mode changes derivation bounds instead of maintaining a second
independent palette.
- Components consume a small reusable semantic vocabulary.
- Component states and exceptional presentation are composed inside
components.
- Builder-specific categorical meaning uses focused composite recipes,
not intent semantics or a larger global vocabulary.
- TypeScript validates public semantic CSS-variable names but does not
generate runtime colors.
- No token-manager dependency, compatibility aliases, or
component-specific public color tokens.
- A new semantic or theme variable is added only when existing semantics
and local composition cannot represent a reusable cross-feature
decision.
## Todo
### Color-system foundation
- [x] Establish direct CSS as the runtime source of truth.
- [x] Define bounded theme colors and contrast controls.
- [x] Derive light and dark modes from the same theme inputs.
- [x] Reduce the semantic inventory to reusable decisions and explicit
accessibility pairs.
- [x] Generate only TypeScript names for public semantic CSS variables.
- [x] Validate layers, references, cycles, consumption, naming,
generated types, and browser-computed contrast.
- [x] Add the Storybook color-system overview and theme controls.
- [x] Document the architecture and its relationship to the public Craft
specification.
### Design-system migration
- [x] Replace every active legacy color consumer in design-system
components and Storybook chrome.
- [x] Compose component states locally without component-specific public
tokens.
- [x] Preserve intentional preview and sample-content colors.
- [x] Add complete positive, negative, warning, informative, and accent
accessibility pairings.
- [x] Validate light and dark scheme-bound references independently.
- [x] Verify the design-system package with typecheck, lint, formatting,
Storybook, and 222 tests.
### Inventory and contract
- [x] Inventory all 319 legacy references across 107 Builder, Query
Builder, story, test, and design-system files.
- [x] Classify every reference as a direct semantic replacement, local
composite recipe, documented literal exception, or removable code.
- [x] Record the intentional authored-content, external-preview,
functional-preview, data-visualization, brand, and source-asset
exceptions.
- [x] Treat the public semantic vocabulary as closed by default and
justify any proposed addition by cross-feature reuse and accessibility
need.
- [x] Keep Builder code limited to typed public variables accepted by
`cssVar()`.
### Theme infrastructure
- [x] Add `system` (default), `light`, and `dark` application
preferences.
- [x] Persist the preference in existing client settings and resolve
`system` through `matchMedia`.
- [x] Apply the resolved scheme before paint and respond to
operating-system changes.
- [x] Expose the persisted theme control under **View → Color scheme**.
- [x] Keep authored canvas documents independent from the application
theme.
- [x] Ensure portals, overlays, embedded surfaces, and third-party
controls receive the correct interface scheme.
### Generic interface migration
- [x] Migrate shared dialogs, project settings, notifications, controls,
and Query Builder.
- [x] Migrate dashboard, authentication, publishing, and shared
application UI.
- [x] Migrate the Builder loading state, topbar, sidebars, navigator,
workspace, footer, settings, pages, alerts, and menus.
- [x] Replace fixed interface literals alongside their owning surfaces.
- [x] Remove the old scrollbar variable and hardcoded loading color.
### Style panel and style-source recipes
- [x] Migrate ordinary style-panel inputs, labels, layouts, spacing,
alignment, menus, property states, and value editors.
- [x] Model style-source provenance, kind, interaction, and error as
separate axes.
- [x] Compose categorical style-source colors from neutral and
accent-relative colors.
- [x] Use negative semantics only for actual errors, not overwritten
provenance.
- [x] Reuse one feature-owned recipe across style-source controls,
badges, menus, and values without adding global tokens.
### Canvas and editors
- [x] Migrate canvas selection, reusable outlines, grid guides, resize
handles, labels, badges, and overlays.
- [x] Keep collaborator colors as data visualization while guaranteeing
readable labels.
- [x] Prevent Builder theme values from leaking into authored content.
- [x] Migrate editor surfaces, selections, autocomplete, lint states,
and tooltips.
- [x] Derive syntax visualization from neutral and accent-relative
colors; reserve intent colors for diagnostics.
### Explicit color domains
- [x] Isolate external search and social previews from the application
scheme.
- [x] Preserve user-authored CSS values, functional color previews, and
checkerboards.
- [x] Review brand surfaces independently in both schemes.
- [x] Document every retained literal in the exception ledger.
### Stories, tests, and legacy removal
- [x] Migrate all affected Builder stories and tests.
- [x] Replace the design-system test that intentionally references the
legacy scale.
- [x] Add theme-preference and scheme-resolution behavior tests.
- [x] Remove the legacy `design-tokens.color` registry.
- [x] Remove the Stitches `colors` scale and `rawTheme.colors`.
- [x] Remove color-name conversion code that exists only for the legacy
scale.
- [x] Add a focused repository check that rejects legacy references.
- [x] Confirm no compatibility mappings or deprecated aliases remain.
### Browser-test infrastructure
- [x] Run pure Design System tests in Node and browser-dependent tests
in Vitest Browser Mode with Playwright Chromium.
- [x] Migrate all 79 Builder E2E workflows from the custom harness to
standard Playwright Test.
- [x] Replace filename-based shard discovery with standard Playwright
sharding.
- [x] Preserve clean-backend shard retries and upload Playwright failure
artifacts in CI.
- [x] Remove the custom runner, registry, and timeout infrastructure.
### Verification and documentation
- [x] Compare light-mode visual regressions directly with `main`; review
every difference rather than accepting snapshots wholesale.
- [x] Add representative dark coverage for dashboard, Builder shell,
style panel, dialogs, editors, canvas tools, and status states.
- [x] Test default and extreme custom-theme presets.
- [x] Verify semantic and categorical-recipe contrast.
- [x] Test first paint, persistence, system changes, portals, and canvas
isolation.
- [x] Run affected tests, typechecks, lint, formatting, and Storybook
checks.
- [x] Review fixture impact; no fixture inputs or generated outputs are
affected.
- [x] Review authoritative `docs/` content and update it where needed.
- [x] Review the final diff and make this checklist reflect delivered
scope.
## Current verification
- Design-system typecheck and generated-type freshness: passed.
- Design-system tests: 222 passed, including the full theme-parameter
contrast sweep and browser component coverage.
- Builder typecheck and production build: passed.
- Theme preference and scheme-resolution tests: 10 passed.
- Scoped Oxlint, formatting, and diff checks: passed.
- Design-system Storybook build and representative light/dark visual
review: passed.
- Builder E2E: 80/80 Playwright entries passed (setup plus 79
workflows).
Ref #3818
Closes #6267
|
||
|
|
e25b7871c3 |
fix: close navigation overlays for anchor links (#6244)
## Summary - Close Popover, Navigation Menu, Dialog, and Sheet content when an ordinary same-context link is activated. - Resolve nested text and icon clicks through the containing anchor. - Keep modified clicks, downloads, empty fragments, new browsing contexts, and Builder canvas interactions unchanged. - Preserve Dialog focus handling, controlled Navigation Menu behavior, and existing Navigation Menu Link dismissal. ## Technical choices - Classify link activation once in the Radix package and share it across overlay components. - Handle activation on each content component so portalled content closes its owning root without a global window listener. - Close overlays based on link activation rather than route lifecycle, making hash-only, current-page hash, and cross-page links consistent. - Preserve Navigation Menu's controlled `value` contract while using `defaultValue` only to initialize uncontrolled state. - Resolve `_parent`, `_top`, and named targets against the anchor document's current browsing context. - Do not prevent the link's default behavior; native hash scrolling and framework routing remain responsible for navigation. ## Compatibility - No schema, migration, data, or public prop changes. - Existing controlled and uncontrolled Navigation Menu behavior remains intact. - Existing Navigation Menu Link behavior remains intact. - Generated fixture inputs and outputs are unaffected. ## Checklist - [x] Add shared same-context link activation rules. - [x] Apply dismissal to Popover, Navigation Menu, Dialog, and Sheet runtime components. - [x] Preserve Dialog focus restoration behavior. - [x] Preserve controlled and uncontrolled Navigation Menu semantics. - [x] Cover top-level and child browsing-context targets. - [x] Assert native fragment navigation remains active. - [x] Add component regression coverage and demonstrate fail/pass behavior. - [x] Run targeted lint, tests, type checking, declaration generation, and package build. - [x] Review documentation impact; no product documentation changes are required because this restores expected navigation behavior without changing the authoring interface. ## Verification - `pnpm --filter @webstudio-is/sdk-components-react-radix test` — 15 tests passed. - Regression demonstrations: - canceling default activation failed the hash assertion; - restoring Dialog trigger focus failed the focus assertion; - treating all non-`_self` targets as external failed the top-level `_parent` and `_top` assertions; - replacing the controlled value with local state failed the controlled Navigation Menu assertion. - `pnpm --filter @webstudio-is/sdk-components-react-radix typecheck` — passed. - `pnpm --filter @webstudio-is/sdk-components-react-radix dts` — passed. - `pnpm --filter @webstudio-is/sdk-components-react-radix build` — passed. - Targeted `oxlint --deny-warnings` — passed. - `git diff --check` — passed. ## Known limitations - Browser layout scrolling is not covered by a published-site E2E. Component tests verify the native fragment update, overlay state, and Dialog focus outcome directly. Closes #6242 |
||
|
|
f9681dc30f |
feat: MDX-backed Content Blocks (#6234)
## Summary Supersede #6182 with a clean implementation of MDX-backed Content Blocks on top of the unchanged `main` Content Block editing model. A connected `.mdx` Asset changes where authored children are loaded and saved; it must not change how Content mode inserts, edits, selects, moves, copies, or deletes instances. The previous implementation remains available in `agent/mdx-content-block-6124` and `agent/mdx-content-block-6124-review`. Reuse its independently tested parsers, converters, schemas, Asset repository, template resolution, publication, MCP, and UI work where those pieces fit the corrected architecture. Do not port its per-operation storage routing, projected editing stores, MDX undo/history, or atomic multi-root machinery. Ref #6124 Ref #6182 Closes #6261 ## Locked behavior - `.md` keeps its existing Markdown behavior; `.mdx` enables MDX. - Standard Markdown structures are stored as Markdown. JSX is used only for structures Markdown cannot represent losslessly. - Generic elements use `<ws.element ws:tag="…">`; template instances use `<ws.element ws:name="…">`. - Invalid, unsafe, or unsupported MDX never prevents editing the file or publishing the project. Builder and publication use the same recovery result: recoverable nodes are skipped with source-located warnings, while an unrecoverable document renders no authored file content in either environment. - Connecting a source never serializes existing Content Block children into the file. **Connect** removes ordinary persisted children, preserves Templates, sets `src`, and uses file content. - Disconnecting resets `src`, discards derived instances, leaves the Content Block empty, and never changes the Asset. - While connected, normal Content Block mutations update in-memory instances synchronously. Asset persistence happens afterward and never blocks rendering. - Genuine external revision conflicts use the standard reload-required flow. Rapid local edits are ordered/coalesced and must never conflict with each other. - Repeated scopes use Content Block ID plus Collection item identity. - Multiple Content Blocks may intentionally share one MDX Asset. They share one revisioned document session and edits propagate to every connected occurrence. - Missing templates show warnings/placeholders only in Builder and are skipped on published sites. ## Reuse strategy - [x] Audit all 62 original implementation commits and 5 later review/fix commits - [x] Reuse the shared Content Engine Markdown/MDX AST, parser, serializer, diagnostics, reference discovery, and tests - [x] Reuse SDK source schemas, instance-name utilities, unique template naming, and source-integrity validation - [x] Reuse template resolution/materialization and authored-tree conversion after removing storage-operation coupling - [x] Reuse revisioned Asset content repository, authorization, limits, and browser/server transport - [x] Reuse publication, document-graph, CLI, MCP, source-control UI, frontmatter UI, and E2E work where contracts remain valid - [x] Reuse tests as behavioral specifications; rewrite tests that assert the rejected projection/routing architecture - [x] Do not port per-operation MDX routing, alternate projected mutation stores, semantic reconciliation after each command, MDX Builder history/undo, atomic multi-file rollback, or canvas loading/saving UI ## Old-branch porting map — do not rewrite Before implementing any checklist batch, inspect the named implementation and tests on `agent/mdx-content-block-6124-review`. Move the implementation and its tests first; change only the boundary that conflicts with the rebuilt architecture. Do not create a second implementation under a new name. When a test encodes the rejected projected-store architecture, retain its behavioral assertion and replace only its setup. ### Already ported - `parseMarkdownAst`, `createMdxDocumentFromMarkdown`, `parseMdxDocument`, `serializeMdxDocument`, `preferMarkdownSyntax`, `discoverMdxBodyAssetReferences`, `discoverMdxAssetReferences`, and `previewMarkdownToMdxConversion` - Asset-reference, byte-stream, document-graph, Markdown, and MDX helpers included in commit `76bc388ba9` - Tests: the corresponding `packages/content-engine/src/**/*.test.ts` files already on this branch ### Port with their existing tests | Area | Functions to move or adapt | Tests to move with them | | --- | --- | --- | | Source contract and integrity | `parseContentBlockSourceProp`, `getContentBlockSource`, `isEqualContentBlockSource`, `formatContentBlockSourceIntegrityIssue`, `getContentBlockSourceIntegrityIssues`, `allocateUniqueContentBlockTemplateName` | `packages/sdk/src/content-block.test.ts`, `packages/sdk/src/schema/content-block.test.ts` | | Existing instance/name utilities | `findChildReferenceIndex`, `findParentInstanceReference`, `getInstanceName` | `packages/sdk/src/instances-utils.test.tsx` | | Template naming in mutations | `assignUniqueBlockTemplateNamesMutable`, `findBlockTemplateNameCollision`, `getSourceBackedBlockTemplateContext`, `getBlockTemplateNameConfirmation`, `getBlockTemplateInsertionIndex` | `packages/project-build/src/runtime/block.test.ts` | | Content-mode property permissions | `getContentModePropEligibility`; preserve its distinction between editable, design-only, incompatible, and unknown props | `packages/project-build/src/runtime/content-mode-permissions.test.ts` | | Template resolution | `resolveMdxTemplates` | `packages/project-build/src/runtime/mdx-template-resolution.test.ts` | | Template materialization | `createMdxScopeIdGenerator`, `materializeMdxTemplates` | `packages/project-build/src/runtime/mdx-materialization.test.ts` | | MDX → instances and instances → MDX | `isMaterializedMdxAuthoredContentRoot`, `preserveMdxAuthoredContentIds`, `materializeMdxAuthoredContent`, `reconcileMdxAuthoredContent`, `omitTransientEmptyParagraphs`, `serializeMdxTemplateInsertion` | `packages/project-build/src/runtime/mdx-authored-content.test.ts`; retain the pure serialization cases from `mdx-storage-adapter.test.ts` | | Revisioned Asset I/O | `createAssetContentRevision`, `readAssetContentBytes`, the package-owned `createHttpAssetContentRepository`, the thin Builder `createBuilderHttpAssetContentRepository`, `createAssetContentBridge`, `initAssetContentBridge`, `getAssetContentBridge`; keep one repository implementation rather than copying the old Builder duplicate | `packages/asset-uploader/src/content-repository.test.ts`, `apps/builder/app/builder/shared/assets/mdx-content-repository.test.ts`, `apps/builder/app/shared/asset-content-bridge.client.test.ts` | | Source lifecycle planning | `createContentBlockBodyRemoval`, `prepareContentBlockConnect`, `prepareContentBlockDisconnect`, `prepareContentBlockSwitch`, `ContentBlockSourceRevisionConflictError` | `packages/project-build/src/runtime/content-block-source-lifecycle.test.ts` | | Per-Asset revision/session behavior | `getContentBlockSessionSource`, `isContentBlockSessionSourceCommitted`; reuse the loading, authorization, revision, queue, conflict, retry, cancellation, and source-replacement internals of `createMdxAssetEditingSession`, but key the rebuilt session by Asset rather than Content Block/render root | Port the applicable cases from `packages/project-build/src/runtime/mdx-asset-session.test.ts`; replace root-projection setup with in-memory snapshot setup | | Template migrations | `validateMdxTemplateMigrationConfirmation`, `planMdxTemplateMigration` | `packages/project-build/src/runtime/mdx-template-migration.test.ts` | | Publication | `createPublishedMdxMaterializationCache`, `materializePublishedMdx`, `getPublishedMdxContentDatabaseMaxBytes`, `getDynamicPublishedMdxSourceBlockIds`, `hasDynamicPublishedMdxSources`, `createPublishedBuildContentCompilationPlan`, `resolvePublishedMdxDependencyClosure`, `resolvePublishedMdxAssetCandidates` | `packages/project-build/src/runtime/published-mdx.test.ts`, `packages/project-build/src/content-database.test.ts` | | Build/import integrity | `assertContentBlockSourceIntegrity` and the Content Block cases in `getBuildIntegrityIssues`/`formatBuildIntegrityIssue` | `packages/project-build/src/build-integrity.test.ts` | | MDX paste/MCP insertion | `insertMdxText` and its input/result schemas; retain parsing, confirmation, template-resolution, and insertion-index logic, then invoke the normal mutation path | `packages/project-build/src/runtime/mdx-paste.test.ts` | | Builder source control | `createContentBlockSourceController`, `createBuilderContentBlockSourceController` and the existing source-control components | `content-block-source-controller.test.ts`, `content-block-source.test.tsx` | | Diagnostics | `formatContentBlockDiagnostic`, `deduplicateContentBlockDiagnostics`, `takeNewContentBlockDiagnostics` | Port only their focused cases from `apps/builder/app/shared/content-block-content.test.ts` | ### Explicitly do not port - `projectContentStorageChanges`, `createContentStorageProjection`, `createContentStorageSelectorProjection`, `executeContentStorageMutation`, `executeContentStorageTextReplacement`, `executeContentStoragePropMutation`, and `executeContentStorageStructuralMutation` - `applyMdxContentStorageChanges` and `prepareMdxContentStorageWrites`; replace them with one post-mutation snapshot serializer built from the reusable pure `reconcileMdxAuthoredContent` converter - `createContentBlockApplicationOperations` and the persistence-plan wrappers that route individual editing commands - Builder `$runtime*` projected stores, materialized mutation functions, alternate selector/tree helpers, pending projected-change state, and MDX-specific mutation sequences from `content-block-content.ts` - Canvas loading/saving/open-file presentation state, MDX history/undo, and atomic rollback machinery ## Implementation checklist ### 1. Preserve the `main` editing architecture - [x] Keep normal synchronous insert, text, Enter, slash menu, property, delete, move, wrap, copy/paste, selection, and focus mutations unchanged - [x] Materialize connected content through the same runtime instance interfaces used by ordinary Content Blocks - [x] Keep connected authored children in memory and exclude them from persisted build data - [x] Route persistence only after a synchronous mutation has updated the canvas - [x] Never wait for Asset loading, conversion, or saving before rendering an interaction - [x] Add no MDX-specific implementation to individual editing commands ### 2. Shared Markdown and MDX conversion - [x] Parse Markdown and the Markdown portion of MDX through one shared AST and plugin configuration - [x] Implement one shared MDX-to-instances converter and one shared instances-to-MDX converter - [x] Serialize headings, paragraphs, links, images, lists, tables, task lists, blockquotes, thematic breaks, code, emphasis, strong, strikethrough, and other supported GFM structures as Markdown - [x] Serialize only non-lossless/custom structures as Webstudio JSX - [x] Preserve nested Markdown in MDX elements, frontmatter, comments, tight/loose list semantics, code whitespace, reference links, and Asset references - [x] Omit transient empty draft paragraphs instead of emitting `<ws.element ws:tag="p" />` - [x] Preserve unsupported source text and authored metadata whenever it cannot be converted safely - [x] Add deterministic round-trip and canonical-output coverage for every supported Markdown structure ### 3. Invalid and unsafe MDX - [x] Preserve file source exactly; never silently repair or rewrite invalid source - [x] Ignore imports, exports, expressions, executable JavaScript, invalid properties, and other unsupported nodes when they can be isolated - [x] Continue rendering valid siblings and report every skipped subtree once with filename, line, and column - [x] Use the same recovery pipeline in Builder and publication so both render the same authored result for the current file revision - [x] When structural syntax prevents recovery, render no authored file content in Builder or publication instead of retaining a stale materialization - [x] Skip an unrecoverable Content Block on published sites and continue the build with a warning - [x] Keep invalid and unsafe files editable and reconnectable - [x] Enforce UTF-8, byte-size, depth, node-count, property-count, and generated-output limits with source-located diagnostics where possible ### 4. File formats and Asset creation - [x] Keep `.md` parsing and raw-HTML behavior unchanged - [x] Support creating, opening, editing, deleting, and recreating `.mdx` files through the normal text-file UI - [x] Open `.mdx` in the same editor experience as `.md` - [x] Always create an independent empty MDX Asset even when identical empty files exist - [x] Allow renaming `.md` to `.mdx` without converting or rewriting its contents; after rename, handle invalid contents through the normal MDX diagnostics and recovery pipeline - [x] Update an already-open MDX editor immediately after canvas persistence - [x] Bound read/write buffering and verify the returned Asset identity and revision ### 5. Source contracts and lifecycle - [x] Support direct Asset bindings and dynamic expression bindings - [x] Keep source mutation controls available only in Design mode; show the connected filename and **Open** action read-only in Content mode - [x] Reject duplicate source props, unsupported prop types, missing Assets, non-MDX Assets, and unauthorized Assets - [x] Analyze selected file diagnostics before confirmation without modifying the block or file; MDX syntax diagnostics do not block connection - [x] For a non-empty block, show **Abort** and **Connect** and explain that ordinary children will be replaced - [x] On connect, remove every non-template child, preserve Templates, set `src`, and materialize file content - [x] Replace disconnect handoff with normal `src` reset; discard derived content and leave the block empty - [x] Remove disconnect confirmation and conversion; resetting a repeated binding leaves every occurrence empty - [x] Switching sources validates/loads the target before replacing the usable binding and leaves both files unchanged - [x] Revalidate Asset revision and project version when confirmation is submitted - [x] Make repeated connect/disconnect operations idempotent - [x] Prevent disposed, stale, or out-of-order loads from replacing the newest source - [x] Keep loading, saving, conflict, empty-file, and open-file actions off canvas ### 6. Asynchronous persistence and conflicts - [x] Snapshot the current in-memory authored root after normal mutations - [x] Serialize/coalesce rapid edits per resolved Asset and always prepare against the latest local snapshot - [x] Allow independent Assets to save concurrently without scope leakage - [x] Use one revisioned document session and one ordered save queue per Asset, even when multiple Content Blocks or render scopes reference it - [x] After a shared Asset changes, rematerialize every connected occurrence without persisting their generated instances to project data - [x] Pin the resolved Asset and exact loaded revision for each write - [x] Recheck authorization immediately before storage - [x] Ensure local queued edits never produce stale-revision conflicts with each other - [x] On a genuine external revision conflict, preserve local content, stop writes, and enter the standard reload-required state - [x] Keep failed non-conflicting writes retryable without discarding local content - [x] Finish already accepted persistence writes after a Content Block unmounts or switches source - [x] Cancel obsolete loads, materializations, and UI updates after unmount, reload, or source switch - [x] Dispose project-scoped roots, queues, parse caches, failure state, generations, and session subscriptions when the Asset session is replaced - [x] Invalidate Asset resources and synchronize open file editors after successful writes - [x] Keep multi-root persistence ordered, serial, and non-atomic; report partial completion without rollback - [x] Do not add Asset-history undo/redo; native text-editor undo remains local to the open editor ### 7. Content mode parity - [x] Empty connected blocks remain selectable and expose the normal Content-mode `+` affordance - [x] First insertion renders immediately - [x] Enter creates and focuses the next paragraph immediately - [x] Slash commands work in newly created empty paragraphs - [x] Deleting one selected instance deletes exactly that instance - [x] Mouse and keyboard moves use the same operation and permissions - [x] Preserve sibling reorder, nested reparenting, and moves between editable Content Blocks where `main` permits them - [x] Preserve content-editable props such as Link `href` - [x] Preserve copy, paste, cut, multi-cut, wrapping, unwrapping, grid insertion, selection, Navigator order, and canvas order - [x] Cover mutation routing centrally, retain the full unconnected Builder suite, and exercise representative connected interactions in real Builder E2E ### 8. Template names and permissions - [x] Resolve only exact user-facing names from the direct flat Templates list - [x] Enforce unique names within each Templates list - [x] Reject duplicate names during rename with inline validation - [x] Allocate unique names during insert, paste, duplicate, move, wrap, and unwrap - [x] Apply valid template properties using the same permissions as Content mode - [x] Preserve and warn about ignored design-only, invalid, or stale properties - [x] Preserve template shell provenance without serializing expanded template internals - [x] Generate deterministic materialized IDs from source identity, render scope, and authored usage path so focus/selection survives saves - [x] Warn before renaming or deleting referenced templates; files remain unchanged - [x] Provide shared AST-based rename/remove migration operations for MCP-assisted multi-file cleanup ### 9. Scope, frontmatter, and diagnostics - [x] Scope materialized content by Content Block ID plus exact Collection-item/render context - [x] Prevent repeated instances and dynamic candidates from leaking generated IDs, template resolution, or diagnostics across scopes while sharing the underlying Asset source and revision where applicable - [x] Remove frontmatter editing from Settings; edit the exact YAML through the MDX Asset file editor - [x] Preserve the exact frontmatter source byte-for-byte during canvas body saves - [x] Route canvas body changes and complete-file editor saves through one revisioned per-Asset coordinator - [x] Show a source warning indicator in Settings and precise source-located diagnostics in the Asset editor - [x] Deduplicate repeated diagnostics without losing distinct locations - [x] Keep unresolved-template placeholders selectable and accessible only in Builder ### 10. Asset references, transfer, and integrity - [x] Discover and rewrite Asset references in frontmatter, Markdown links/images, and MDX properties - [x] Preserve Asset references while editing unrelated content - [x] Include referenced Asset and template revisions in dependency/cache identity - [x] Route referenced Assets through published URL rewriting - [x] Validate Content Block source integrity during project import, fragment/page transfer, copy/paste, build integrity, and pre-publish audit - [x] Allow multiple Content Blocks and dynamic render scopes to reference the same MDX Asset without treating the connection as an integrity error - [x] Preserve Templates when copying a connected Content Block - [x] Preserve direct and dynamic Content Block source bindings when copying or pasting within the same project - [x] When copying only one rendered Collection item, resolve that item’s current MDX Asset and replace the copied Content Block’s dynamic source with a direct binding to that same Asset - [x] When copying an entire Collection, preserve the Collection, its instances, and its dynamic source bindings - [x] Preserve the complete MDX source and frontmatter by reference; copying a connected block must not rewrite the shared file - [x] During cross-project transfer, copy every discoverable distinct bound MDX Asset and rewrite transferred bindings to the destination Assets - [x] If some cross-project dynamic candidates cannot be discovered or copied, continue with successful copies, preserve what can be represented safely, and warn about skipped candidates - [x] Revalidate source revisions and the destination project before applying a cross-project transfer - [x] If cross-project Asset creation or project insertion fails, leave the source project unchanged and clean up any newly reserved destination Asset - [x] Use the same transfer operation through Builder and MCP ### 11. Dynamic sources and publication - [x] Resolve dynamic bindings once per render/save scope - [x] Require finite, discoverable candidate sets for publication and load no unrelated MDX - [x] Warn and skip unbounded, missing, unreadable, malformed, or unsafe sources without failing the complete build - [x] Materialize only rendered Content Blocks; ignore Templates definitions and `src` on non-Content-Block instances - [x] Skip unresolved template subtrees while keeping valid siblings - [x] Include selected template styles, fonts, resources, unresolved names, and referenced Asset revisions in generated dependency output - [x] Keep draft-only MDX Assets out of publication retention ### 12. Builder, MCP, CLI, and shared operations - [x] Use the same converters, source lifecycle, revision checks, persistence service, diagnostics, and template migrations in Builder and MCP - [x] Keep frontmatter editing file-based; retain whole-frontmatter runtime operations only where compatibility requires them - [x] Avoid Builder-only or MCP-only mutation/conversion implementations - [x] Regenerate runtime/API contracts from their source definitions - [x] Update CLI Content Engine reference and generated MCP documentation ### 13. Verification and delivery - [x] Add regression tests that reproduce failures from the previous implementation, including double deletion and blocked rendering - [x] Cover two Content Blocks sharing one Asset: edits from either block serialize once, update both canvases, preserve scope-specific Templates, and cannot overwrite a newer local snapshot - [x] Verify new tests fail against the broken implementation and pass with the corrected behavior - [x] Run SDK, Content Engine, Asset Uploader, Project Build, Builder, React SDK, CLI, Protocol, and HTTP Client affected suites and typechecks - [x] Run real Builder E2E for source lifecycle, live file refresh, empty insertion, Enter/slash focus, Link props, delete, keyboard reorder, switching, disconnect, conflicts, unresolved templates, dynamic sources, and repeated scopes - [x] Regenerate shared project fixture bundles and verify a second generation leaves the tree clean - [x] Run lint, package boundaries, `pnpm oxfmt --check`, and `git diff --check` - [x] Review and update authoritative `docs/` content and navigation - [ ] Run the complete agent evaluation suite — not run because it requires separate explicit approval ### 14. Content-mode parity and disconnect handoff - [x] Allow keyboard reordering in Content mode through the normal move command while keeping the editable Content Block boundary - [x] Let already accepted Asset writes drain independently before resetting the source; disconnect does not load, flush, or convert the file - [x] Remove MDX-to-instance copying from disconnect - [x] Reset `src`, remove the derived tree, and leave the ordinary Content Block empty - [x] Preserve automatic text-editor focus after inserting editable content from the template menu - [x] Remove Builder frontmatter-save UI and report complete-file save failures through the Asset editor - [x] Add regression coverage for keyboard movement, disconnect teardown, source switching, insertion focus, and paragraph deletion focus restoration - [x] Run the complete six-scenario MDX Content Block Builder E2E suite ### 15. Final architecture review fixes - [x] Keep one canonical ordered pending document per Asset so shared Content Block occurrences cannot conflict with one another - [x] Merge ordered local edits from different occurrences while preserving text changes, insertions, deletions, and sibling reordering; keep external revisions on the strict reload-required path - [x] Centralize typed render-scope parsing, repeated-occurrence detection, scoped variable lookup, and dynamic Asset resolution across Canvas, Settings, source lifecycle, and copy/paste - [x] Capture the owning Asset session when a save is accepted so normal unmount/source-switch teardown cannot redirect or lose it - [x] Dispose project-owned roots, queues, caches, generations, failure state, and subscriptions when replacing the project Asset session - [x] Add regression coverage for same-Asset edits from two occurrences, same-node last-write ordering, structural reorder, insertion preservation, scoped source resolution, and project cleanup - [x] Re-run affected full unit suites, typechecks, production build, static checks, and all six MDX Content Block Builder E2E scenarios ### 16. Final persistence and transfer hardening - [x] Drain every accepted per-Asset edit before project-session teardown while retaining the owning authorization context - [x] Drain canvas serialization queues and revisioned Asset writes before pre-publish audit and publication - [x] Block publication on a queued serialization failure or Asset revision conflict - [x] Copy actual Asset bytes during cross-project paste, preserve MDX reference names, rewrite direct and Collection-backed Asset IDs, and clean up newly created Assets when insertion fails - [x] Include every resolved dynamic MDX source when copying an entire Collection and warn while preserving successful copies when individual Assets cannot be transferred - [x] Keep MDX editor save failures visible with retry and route conflicts through the standard reload-required flow - [x] Give keyboard nested reparenting the same editable Content Block boundary used by pointer movement - [x] Add regression coverage and rerun the complete Content Engine and Builder unit suites plus type, lint, formatting, package-boundary, and diff checks ## Current rebuild status - The connected Content Block now owns one complete MDX document: frontmatter feeds designed-shell bindings and the explicit Body outlet owns the authored MDX body. - Builder and published output resolve the same frontmatter document graph, including nested document references and Asset references. - Direct frontmatter text/property edits use the existing ordered per-Asset session; referenced-document values remain file-owned. - Repeated Collection occurrences keep isolated runtime shell/Body identities and occurrence-specific document values. - The local blog article layout has been upgraded to the document/Body model and its bindings validate cleanly. - Full affected package suites and typechecks pass; every new regression was demonstrated fail/pass. - `pnpm lint`, package boundaries, `pnpm oxfmt --check`, generated API/docs checks, fixture builds, and `git diff --check` pass. - Full fixture synchronization is blocked by the development API rejecting this local CLI version before fixture generation; existing fixture bundles build successfully. - Complete agent evaluations remain pending explicit approval. ### 17. Treat Content Block source as a property - [x] Declare Content Block `src` in component metadata as a Design-mode initial property labeled **Source** - [x] Add the short property description: “Create an .mdx file in Assets, then select or bind it here.” - [x] Accept only a direct Asset or an expression resolving to an Asset ID; reject URL/string sources, missing Assets, and non-MDX Assets - [x] Extract and reuse the Image-style Asset picker and binding presentation without duplicating source-control UI - [x] Render Source through the normal properties section and remove the separate source-section placement and special `src` filtering - [x] Route Source changes through Content Block connect, switch, and disconnect lifecycle operations instead of generic prop updates - [x] Keep connect confirmation, Open, diagnostics, and persistence state attached to Source; remove frontmatter and disconnect UI - [x] Add regression coverage for direct Assets, dynamic Asset bindings, invalid resolved values, lifecycle operations, and Design/Content mode visibility - [x] Re-review authoritative `docs/` content for the Source-property UI change and update it if required ### 18. Source property UX - [x] Show one full-width bindable Connect .mdx file button while disconnected - [x] Show equal-width filename and Open buttons while connected - [x] Switch files from the filename button through the source lifecycle - [x] Override PropertyLabel reset and Alt-click with the disconnect lifecycle - [x] Preserve confirmation, pending, failure, repeated-scope, and dynamic-source behavior - [x] Add regression coverage for connect, switch, binding, reset, and disconnect - [x] Update Content Block documentation - [x] Run affected tests, typecheck, lint, formatting, package boundaries, and diff checks ### 19. Reduced file-owned frontmatter follow-up This checklist supersedes the earlier structured-frontmatter and disconnect-copy behavior. Frontmatter remains file-owned and is edited only in the MDX Asset editor. #### A. Remove structured frontmatter UI - [x] Remove the JSON frontmatter editor and unused Builder controller/state - [x] Keep source mutation Design-mode-only; show connected Source read-only in Content mode and allow authorized editors to open the complete file - [x] Retain runtime frontmatter APIs only where compatibility requires them #### B. Preserve source and separate validation - [x] Preserve the exact frontmatter envelope during every canvas body save without parsing/stringifying YAML - [x] Preserve comments, ordering, quoting, whitespace, BOM, newline style, delimiters, and invalid but closed YAML - [x] Keep the existing unsupported-node/property MDX recovery; do not add an ad hoc partial parser - [x] Parse body and frontmatter independently so either valid half remains usable - [x] Keep bounded Asset-query frontmatter extraction unchanged - [x] Treat structurally malformed MDX as having no safe body tree #### C. Share Asset state with the raw editor - [x] Route canvas and complete-file changes through one ordered, non-blocking per-Asset coordinator - [x] Update canvas and clean raw editors immediately from shared in-memory source - [x] Reject stale dirty-editor saves, preserve unsaved text, and require reload; never force-overwrite - [x] Drain accepted writes after source replacement/disconnect and report background failures globally - [x] Dispose sessions only after they have no consumers and no queued work #### D. Connect, replace, and disconnect - [x] Load and diagnose before connect; block only unreadable/unauthorized/non-MDX Assets - [x] Show **Abort / Connect** for non-empty blocks, including diagnostics and the recoverable-content warning - [x] Set `src` and delete persisted children through one runtime mutation - [x] Switch to a loaded source without waiting for the previous Asset's network save - [x] Remove disconnect confirmation and conversion - [x] Reset `src` immediately, discard the derived tree, leave the block empty, and preserve the Asset - [x] Resetting a bound source leaves every repeated occurrence empty #### E. Dynamic and shared sources - [x] Keep one source/revision state per Asset and a separate derived instances tree per occurrence - [x] Resolve Templates independently per Content Block and preserve Builder-only missing-template placeholders - [x] Resolve bound `src` from the selected Collection occurrence - [x] Make **Open** use the occurrence's resolved Asset; update the filename and disable Open when unresolved - [x] Add direct/bound tests including Collection item A opening `a.mdx` and item B opening `b.mdx` #### F. Diagnostics, MCP, and publication - [x] Show an accessible warning icon beside Source with the first diagnostic, line/column, and remaining count - [x] Show precise YAML/MDX diagnostics in the Asset editor without repetitive canvas/toast UI - [x] Reuse parser/diagnostic/revision contracts in Builder, build, publication, and MCP - [x] Keep MCP frontmatter editing file-based and return structured diagnostics for complete-source writes - [x] Emit build warnings; published sites skip invalid/unsupported content without diagnostic UI #### G. Verification and documentation - [x] Add fail/pass regressions for source preservation, independent validation, stale raw saves, lifecycle, dynamic Open, shared Assets, and cleanup - [x] Run affected tests, typechecks, lint, formatting, package boundaries, fixtures, and diff checks - [x] Open Markdown and MDX editors at twice the default dialog size with the right-side preview visible initially - [x] Document canvas body editing, file-owned frontmatter, Content-mode Asset access, and cloning an MDX Asset for a new post - [x] Perform a final correctness, data-loss, DRY, simplification, accessibility, and performance review - [x] Keep this checklist synchronized with implementation status ### 20. Content-mode component properties - [x] Show a connected Content Block Source read-only in Content mode with an active **Open** action - [x] Keep source switching, binding, reset, and disconnect available only in Design mode - [x] Expose HTML Embed code and preserve Code Text's code-editor metadata on authored Text Content - [x] Audit every registered component and expose authored payload while keeping design, structure, and behavior controls in Design mode - [x] Keep media dimensions and Code Text theme Design-only while preserving adapter-owned intrinsic Image metadata during MDX round trips - [x] Add exact component-permission and regression coverage - [x] Update authoritative component documentation - [x] Run affected full suites, typechecks, formatting, lint, package boundaries, and generated contract/documentation checks ### 21. Designed document shell and Body outlet - [x] Add one structural **Content Block Body** outlet and keep legacy Content Blocks without it compatible - [x] Materialize and persist only `document.body` children through the Body outlet while preserving the surrounding designed shell and Templates - [x] Expose the connected document frontmatter through a Content Block `document` parameter for shell text and property bindings - [x] Write direct frontmatter-bound text and properties back through the same ordered per-Asset session without blocking canvas mutations - [x] Resolve document `$ref` dependencies and Asset references consistently in Builder and published output - [x] Keep referenced-document values read-only on canvas and direct editors to the referenced file - [x] Isolate repeated Collection occurrences while retaining occurrence-specific source, frontmatter, shell, and Body content - [x] Render the same designed shell, frontmatter values, and Body substitution in generated/published output - [x] Upgrade the local blog article layout to bind title, excerpt, dates, author data, and images from frontmatter and render MDX through Body - [x] Add fail/pass regressions for nested Body discovery, lifecycle, permissions, repeated values, document references, and generated shell rendering - [x] Update authoritative Content Block documentation - [x] Run affected tests and typechecks, formatting, lint, package boundaries, generated API/docs checks, and fixture builds ### 22. Final nested references and frontmatter editing - [x] Keep direct frontmatter-bound text and property controls editable in Content mode without exposing or replacing their bindings - [x] Keep referenced-document values read-only and preserve legacy instance-property name normalization - [x] Render direct frontmatter text bindings through the plain-text editing path - [x] Resolve nested legacy and structured Asset references from referenced Markdown/MDX frontmatter - [x] Preserve missing Asset references, emit structured `ASSET_NOT_FOUND` diagnostics, and keep them out of the document graph - [x] Add fail/pass regressions for the real Settings control and root/nested missing Asset-reference cases - [x] Fix exact Content Block selection after the Body node appears in Navigator - [x] Run full affected suites/typechecks, all six MDX Content Block E2E scenarios, deterministic fixture builds, generated checks, lint, formatting, package boundaries, and diff checks ### Before merge - [x] Resolve #6261: Nested Asset references in referenced Markdown frontmatter work consistently in Assets queries, previews, publication, and static export ### 23. Explicit writable expression bindings - [x] Add an explicit `readwrite` mode to expression bindings; existing expressions remain read-only by default - [x] Accept `readwrite` only for direct static member paths and centralize their parsing and validation - [x] Require the expression root to provide a writable data source; initially support the connected Content Block document frontmatter - [x] Update Content Block permissions, canvas text editing, and property controls to require a valid writable binding - [x] Persist direct frontmatter edits through the existing ordered per-Asset session - [x] Create new direct frontmatter bindings with `readwrite` mode and migrate existing compatible bindings - [x] Preserve writable mode through schemas, serialization, loading, copy/paste, transfer, and export - [x] Add fail/pass regressions for valid paths, derived expressions, unsupported sources, permissions, persistence, and compatibility - [x] Review authoritative `docs/` content and update it if the persisted binding contract affects user-facing documentation - [x] Reject unsafe frontmatter paths and reject `readwrite` bindings outside a connected Content Block document - [x] Preserve expression binding mode through the public HTTP client and document the MCP authoring contract - [x] Limit frontmatter value write-back to Content mode so Design mode retains normal binding replacement/reset behavior - [x] Keep bindings inside Templates and across nested Content Block ownership boundaries read-only - [x] Upgrade compatible legacy bindings even when the Content Block is disconnected during migration - [x] Run affected tests, typechecks, formatting, lint, package boundaries, fixture checks, and `git diff --check` Verification: full SDK (567), Project Build (2,277), and Builder (2,695) suites pass, along with affected Expression, Migration, Template, HTTP Client, and MCP suites; typechecks, lint, formatting, package boundaries, and diff checks pass. Generated contracts are refreshed. Fixture synchronization remains blocked before generation because the development API rejects this local CLI version as incompatible. The checked-in bundles pass the current Protocol suite and every fixture build with the current bundle version. |
||
|
|
7e7c14868a |
fix: Preserve read-only guides and publish targets (#6266)
## Summary - Route explicit read-only `meta.guide` requests to focused discovery tools and exclude mutations, side-effecting session tools, broad design context, and visual verification. - Require explicit task scope, specialized workflow, authored-fragment routing, and design-system reuse instead of inferring behavior from brief prose. - Persist the requested staging or production target in new SaaS deployment records. - Return the same target from publish list and job status, with backward-compatible inference for historical records. ## Todo - [x] Reproduce the read-only custom-code audit misrouting from #6262. - [x] Add failing regressions and implement strict read-only routing. - [x] Remove behavior-affecting prose inference from CLI/MCP guide routing. - [x] Reproduce the single-domain production target mismatch from #6263. - [x] Add create-to-list/status regressions and persist the explicit target. - [x] Cover historical deployment records that predate the stored target. - [x] Verify production create → list → get-job through the staging deployment. - [x] Regenerate and verify project fixtures against the changed bundle contract. - [x] Review documentation impact and update the generated MCP manual. - [x] Review the complete diff for correctness, compatibility, duplication, and unnecessary complexity. ## Verification - Real staging publish for #6263 — passed; create, list, and get-job consistently reported `production` for a one-domain publish. The supplied project has no custom domains, so the custom-domain variant was not available. The job remained `pending` during this check. - Real local CLI/MCP verification for #6262 — passed; no mutation or side-effecting tools leaked. - `pnpm --filter @webstudio-is/protocol test -- src/fixtures.test.ts` — 17 passed - `pnpm -r fixtures:build` — passed for all eight fixtures - `pnpm --filter @webstudio-is/project-build test` — 2,134 passed - `pnpm --filter webstudio test` — 1,037 passed; the one payload-size regression was fixed and its targeted test passed - `pnpm --filter @webstudio-is/domain test` — 24 passed - `pnpm --filter @webstudio-is/sdk test` — 519 passed - Builder API router test — 30 passed - Relevant package typechecks — passed - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` - Regression tests were demonstrated failing against the previous behavior and passing with the fixes. - Agent evaluations were not run because they require separate explicit approval. Closes #6262 Closes #6263 |
||
|
|
88ecbc5f7b |
chore: renew wstd.dev certificate (#6256)
## Summary Renew the local Builder HTTPS certificate for `wstd.dev` and its wildcard subdomains. ## Todo - [x] Replace the tracked certificate, private key, and HAProxy bundle - [x] Verify certificate dates, SANs, and matching public/private keys - [x] Verify repository formatting and diff integrity - [x] Review documentation impact — no product documentation changes are required ## Verification - `openssl verify -partial_chain -CAfile https/fullchain.pem https/fullchain.pem` - Certificate and private-key public keys match - HAProxy certificate and bundled private-key public keys match - `pnpm oxfmt --check` (using the existing Builder dependency installation) - `git diff --check` No fixture inputs or generated outputs are affected. |
||
|
|
cbe4950cd0 |
fix: Use available package manager for previews (#6251)
## Summary - Use the npm or pnpm launcher that started Webstudio for preview dependency installation, builds, and server startup. - Use pnpm-compatible isolated-install flags and report the selected package-manager path on failure. - Preserve the existing installed-dependency reuse path before package-manager resolution. ## Technical choices - Read the standard `npm_execpath` metadata already supplied by npm and pnpm; users do not need to configure another environment variable. - Run JavaScript launchers such as `pnpm.cjs` with the selected Node runtime, supporting bundled Node distributions without adjacent npm. - Keep the existing npx-to-npm mapping and fallback behavior unchanged. - Distinguish numeric package-manager exit codes from process-launch errors such as `ENOENT`. ## Todo - [x] Reproduce the bundled Node + pnpm + missing adjacent npm failure. - [x] Add fail-before/pass-after coverage for dependency installation, production build, and preview startup. - [x] Reuse the detected pnpm launcher. - [x] Preserve installed-dependency reuse. - [x] Include the selected launcher path in installation failures. - [x] Report package-manager exits and process-launch errors accurately. - [x] Review documentation impact and update the CLI manual plus generated MCP documentation. - [x] Review fixture impact; no fixture inputs or outputs are affected. ## Verification - Focused install diagnostic regression suite — 28 tests passed. - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm --filter webstudio test` — 1,029 of 1,030 tests passed; an existing process-supervisor cleanup test hit a transient `ENOENT`, then passed 4/4 when rerun in isolation. - Generated documentation checks passed. - Real pnpm JavaScript launcher invocation with isolated preview install flags. - Agent evaluations were not run because they require separate approval. Closes #6250 |
||
|
|
fc6b5f2fde |
fix: Retry bulk style deletions after conflicts (#6255)
Closes #6254 ## Summary - Mark `styles.deleteDeclarations` as safe to retry after a confirmed version conflict. - Recompute the deletion against refreshed style namespaces before the retry. - Add a regression covering 185 CSS custom-property declarations and the complete conflict/refresh/retry path. - Regenerate the public runtime operation contract. ## Root cause and behavior `delete-styles` already accepts and plans a 185-declaration payload. The failure occurs when the remote build changes between the session snapshot and the commit: the session refreshes, but the operation contract currently has `retryOnConflict: false`, so the atomic deletion returns uncommitted and the project version does not advance. Style declaration deletion is retry-safe because the operation is recomputed from the refreshed snapshot and removes only exact declaration keys that still exist. The released CLI already writes structured success and failure JSON to stdout; stderr contains lifecycle diagnostics. No stderr parsing change is needed in Webstudio. The issue's stderr acceptance criterion was LLM-authored without captured failure diagnostics in CLI 0.293.0. ## Tradeoffs and compatibility - Retries only confirmed version conflicts. - Ambiguous commit results are still not replayed. - No schema, migration, or user-facing API shape changes. ## Checklist - [x] Reproduce the 185-declaration CSS-variable deletion through the CLI/MCP dry-run path. - [x] Reproduce the unchanged-version failure with a conflicting commit. - [x] Verify the regression fails before the contract change and passes afterward. - [x] Enable conflict retry for `styles.deleteDeclarations`. - [x] Regenerate runtime operation contracts. - [x] Review documentation impact; no documentation update is required for this reliability fix. - [x] Verify fixture impact; no fixture inputs or outputs are affected. ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,132 tests passed. - `pnpm --filter @webstudio-is/project-build typecheck` — passed. - Targeted oxlint on changed source/tests — passed. - `pnpm check:generated-api` — passed; generated files are clean. - Agent evaluations were not run because they require separate explicit approval. |
||
|
|
981f45fd0d |
docs: Optimize documentation image sizes (#6253)
## Summary Replace ten oversized PNG screenshots in the product documentation with high-quality WebP assets and update their references. The affected assets shrink from 27,813,051 bytes to 2,822,010 bytes (90% smaller) while retaining their original pixel dimensions. ## Technical choices - Encoded screenshots as WebP at quality 88 with sharp YUV conversion. - Kept original dimensions to preserve UI text legibility and zoom detail. - Left animated GIFs unchanged: GIF-native optimization, palette reduction, and resizing tests increased their file sizes, so changing them would add cost or reduce clarity. - Kept documentation content, navigation, and public page paths unchanged. ## Checklist 1. [x] Audit raster assets in `docs/.gitbook/assets`. 2. [x] Optimize referenced PNG assets above 1 MB where conversion materially reduces size. 3. [x] Update every affected documentation reference. 4. [x] Verify replacement dimensions and image decoding. 5. [x] Verify visual quality (SSIM 0.961–0.997 plus manual spot checks). 6. [x] Verify new references resolve and removed filenames are no longer referenced. 7. [x] Review documentation impact; this PR changes documentation assets and their direct references only. 8. [x] Verify no fixture inputs or generated fixture outputs are affected. ## Verification - `git diff --check` - Reference checks for all ten added and removed filenames - Pixel-dimension comparison for all ten replacements - FFmpeg SSIM comparison for all ten replacements - Manual visual review of representative full-resolution screenshots The repository formatter excludes these documentation files, so it reported no matching targets. Agent evaluations were not run because this is a documentation-asset-only change. Closes #6252 |
||
|
|
471f504087 |
feat: Select unused assets before deleting (#6245)
Closes #6243 ## Summary - Add checked-by-default controls for every asset in the **Delete unused assets** dialog. - Add a footer **Select all** control that reflects the complete selection and toggles all assets. - Delete only selected assets that remain unused and disable deletion when the selection is empty. - Keep the Assets documentation aligned with the selective deletion workflow. ## Implementation The dialog owns a set of selected asset IDs initialized from the unused-assets result. Individual checkboxes update that set, while **Select all** replaces it with either every currently unused ID or an empty set. Asset usage inputs remain subscribed while the dialog is open. The deletion payload is intersected with the current unused-assets list, and this cleanup path does not force deletion. If an asset becomes referenced before the mutation executes, the runtime rejects its deletion instead of removing a now-used asset. ## Todo - [x] Add per-asset selection controls. - [x] Add and position the **Select all** footer control. - [x] Limit deletion to selected asset IDs that remain unused. - [x] Protect against assets becoming referenced while the dialog is open. - [x] Add regression tests for individual selection, select-all behavior, empty-selection protection, selective deletion, and live usage changes. - [x] Review documentation impact and update the Assets guides. - [x] Verify formatting, lint, types, and Asset Manager/assets tests. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run app/builder/shared/asset-manager app/builder/shared/assets` — 26 files, 221 tests passed. - `pnpm --filter @webstudio-is/builder typecheck` — passed. - `pnpm exec oxlint --deny-warnings apps/builder/app/builder/shared/assets/delete-assets.ts apps/builder/app/builder/shared/asset-manager/delete-unused-assets.tsx apps/builder/app/builder/shared/asset-manager/delete-unused-assets.test.tsx` — passed. - `pnpm exec oxfmt --check apps/builder/app/builder/shared/assets/delete-assets.ts apps/builder/app/builder/shared/asset-manager/delete-unused-assets.tsx apps/builder/app/builder/shared/asset-manager/delete-unused-assets.test.tsx` — passed. - Both regression tests were confirmed failing before their respective implementations and passing afterward. ## Compatibility and follow-ups No data migrations, public API changes, fixture changes, or known follow-ups. |
||
|
|
9a4ee57929 |
fix: Create page templates without explicit titles (#6240)
## Summary Allow `create-page-template` to omit `title` by deriving a fixed title expression from the required template name. Explicit titles remain unchanged. Closes #6239 ## Todo - [x] Reproduce the name-only mutation failure against the persisted page-template schema - [x] Derive the omitted title from the template name - [x] Add and verify a fail-before/pass-after regression test - [x] Review fixture impact; no fixture inputs or generated outputs are affected - [x] Review documentation impact; the existing command schema and example already document the optional title, so no documentation update is needed ## Verification - `pnpm --filter @webstudio-is/project-build test -- src/runtime/page-copy.test.tsx` - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm exec oxfmt --check packages/project-build/src/runtime/page-copy.ts packages/project-build/src/runtime/page-copy.test.tsx` - `pnpm exec oxlint --deny-warnings packages/project-build/src/runtime/page-copy.ts packages/project-build/src/runtime/page-copy.test.tsx` - Full package test run: 2,127 passed; three unrelated existing descendant-selector failures remain in `src/runtime/styles.test.ts` - Agent evaluations were not run because they require separate approval |
||
|
|
db2175f333 |
fix: transfer pasted assets across deployments (#6228)
Closes #6227 ## What changed Cross-deployment copy/paste now transfers referenced assets into the destination project before inserting instances, pages, templates, or folders. - Add optional source deployment metadata to the existing v0.1 clipboard formats. - Keep old v0.1 payloads readable and keep new payloads readable by older builders, which ignore the additive field. - Reuse the existing asset upload-by-URL flow for images, fonts, videos, and files. - Preserve source video dimensions through the existing upload route. - Replace source asset IDs and font-family references with destination values before runtime insertion. - Include and remap page social images and marketplace thumbnails. - Reject current clipboard payloads whose page metadata references omitted assets. - Leave the public `pageTransfer.insert` runtime input unchanged. - Abort insertion with a paste error when an asset cannot be imported. No clipboard version increase, custom network fetcher, address blocklist, rollback framework, or global paste wrapper is introduced. If a multi-asset import partially uploads before a later upload fails, the completed uploads may remain unused. ## Checklist - [x] Rebased onto `main` - [x] Preserve the existing v0.1 clipboard format - [x] Transfer and remap instance assets - [x] Transfer and remap page, template, and folder assets - [x] Preserve video metadata - [x] Keep runtime page-transfer API compatible - [x] Add regression coverage - [x] Review documentation impact and update page-copy documentation - [x] Run Builder tests and typecheck - [x] Run project-build tests and typecheck - [x] Run lint, package-boundary, and generated-API checks ## Verification - Builder full suite: 219 files, 2,552 tests passed - Project-build full suite: 78 files, 2,129 tests passed - Final affected suite: 84 tests passed - New regressions were confirmed failing before the fixes and passing afterward - Builder and project-build typechecks passed - `pnpm lint` passed - `pnpm check:package-boundaries` passed - `pnpm check:generated-api` passed - Fixture inputs and generated fixture bundles are unaffected |
||
|
|
61df069016 |
fix: Report recovered project settings commits (#6236)
## Summary A stale project-settings mutation could retry and commit successfully while retaining the original `CONFLICT` error diagnostic. CLI and MCP then reported failure even though the requested settings were stored and the project version advanced. Successful conflict retries now retain only recovery information. Failed retries still preserve their errors. ## Implementation checklist - [x] Reproduce the stale project-settings conflict before changing the implementation. - [x] Remove the obsolete error diagnostic only after a retry succeeds. - [x] Cover `update-project-settings` commit status, resulting version, and remote read-back. - [x] Confirm the regression fails before the fix and passes after it. - [x] Review documentation impact; no user documentation changes are required. - [x] Review generated contracts and fixtures; neither is affected. - [ ] Confirm CI passes. ## Verification - ProjectSession suite: 49 tests passed. - Complete Project Build suite: 2,126 tests passed. - Project Build typecheck passed. - CLI ProjectSession adapter suite: 8 tests passed. - Changed-file lint and formatting passed. - Agent evaluations were not run because they require separate approval. Closes #6235 |
||
|
|
130d371759 |
perf: Skip resources in statically hidden subtrees (#6233)
## Summary - Skip read-time resources scoped to an instance with literal `show=false` or any descendant of that instance. - Use the same static reachability rule in the Builder client preloader and CLI-generated published resource map. - Keep dynamic `show` expressions on the existing loading path because their result may depend on resource data. ## Data path and performance In the Builder, the client-side resource request set now excludes statically hidden subtrees before requests enter the preloader. For generated sites, the CLI still scans project instances and props during build, but removes statically hidden subtrees from the page build data. Their read resources therefore never enter the generated server-side resource map and no corresponding resource network request runs during page rendering. This removes request and server/network cost for literal-`false` subtrees. It does not remove build-time project scanning, and resources under dynamic conditions still load. ## Compatibility - No project schema or persisted data changes. - No migrations. - Action-bound resources retain their existing explicit-trigger behavior. - Dynamic `show` expressions retain current behavior. ## Checklist - [x] Add shared static-subtree reachability logic. - [x] Apply it to Builder preview resource preloading. - [x] Apply it to generated/published resource collection. - [x] Add Builder and generated-output regressions for direct, descendant, visible, and dynamic cases. - [x] Demonstrate the new regressions fail against the previous behavior and pass with the implementation. - [x] Review authoritative `docs/` content; no documentation update is required because the UI and authoring workflow are unchanged. - [x] Review fixture inputs and outputs; no fixture contains this resource/show combination, so fixture regeneration is not required. ## Verification - `pnpm --filter @webstudio-is/sdk test` - `pnpm --filter @webstudio-is/react-sdk test` - `pnpm --filter @webstudio-is/builder exec vitest run app/shared/nano-states/props.test.tsx` - `pnpm --filter webstudio build:content-runtime` - `pnpm --filter webstudio exec vitest run src/prebuild.test.ts` - Typechecks for SDK, React SDK, Builder, and CLI - Targeted `oxlint --deny-warnings` - `git diff --check` Agent evaluations were not run because they require separate explicit approval. Closes #6232 |
||
|
|
8e3f8e3234 |
fix: Avoid Builder E2E registry throttling (#6231)
## Summary - pull the pinned Supabase Postgres image from its official GHCR package instead of anonymous Public ECR - pin the multi-platform index digest shared by both registries ## Technical choice The existing Public ECR and GHCR tags resolve to the same multi-platform index digest, so changing registries preserves the amd64 and arm64 image contents. GHCR public pulls require no long-lived CI credentials. ## Checklist - [x] Verify Public ECR and GHCR resolve to the same image digest - [x] Switch the Compose database image to the pinned GHCR digest - [x] Validate shell syntax and rendered Compose configuration - [x] Review documentation impact; no user-facing documentation is affected - [x] Review fixture impact; no fixture inputs or outputs are affected ## Verification - `bash -n apps/builder/dev/backend.sh apps/builder/e2e/run-local.sh` - `docker compose ... config --images` - `docker buildx imagetools inspect` digest comparison for both registries - `git diff --check` The full Builder E2E suite was not run locally because the change only selects an identical image from a different registry. Closes #6230 |
||
|
|
9e504037fb |
fix: improve MCP reliability across project workflows (#6222)
## Summary Fixes the reproducible MCP, preview, redirect, audit, mutation, and asset-upload failures from the latest issue batch. Historical and non-reproducible reports were investigated without speculative fixes. Visual verification is now opt-in unless the user explicitly requests it. ## Issue checklist - [x] #6207 — report tested recovery when an explicitly selected browser fails to start. - [x] #6208 — accept generic and registered buttons as valid label targets without requiring a separate form label. - [x] #6209 — reject unknown style coordinates such as `breakpointId` and document the supported `breakpoint` field. - [x] #6210 — traced Node 18 access to CLI 0.293.0 predating the launcher guard; closed as already fixed by #6201. - [x] #6211 — verified the supported launcher blocks the reported Node 18 crypto path; closed as already fixed by #6201. - [x] #6212 — give sequential responsive captures the sum of their per-capture timeout budgets. - [x] #6213 — keep preview install, build, and server subprocesses on the parent CLI Node runtime. - [x] #6214 — add safe confirmation and diagnostics for ambiguous mutation responses; this does not claim to remove upstream latency. - [x] #6215 — confirmed as the same historical Node 18 release path as #6210; closed as already fixed by #6201. - [x] #6216 — verified malformed input returns structured errors on current main; closed as not reproducible and improved future failure diagnostics. - [x] #6217 — add transaction-id confirmation for large fragment mutations after ambiguous 5xx responses; this does not make the operation asynchronous. - [x] #6218 — verified the existing DevTools reconnect fix from #6205; closed as already fixed. - [x] #6219 — preserve the incoming pathname and query when a redirect target supplies only a hash. - [x] #6220 — return ordered `uploaded`, `failed`, and `ambiguous` results so partial asset successes are not lost or retried unsafely. - [x] #6221 — verified parser recovery without a Node crash; closed as not reproducible and improved future JSX failure diagnostics. - [x] #6223 — verified browser-session reuse, reconnect, and cleanup; closed as already fixed by #6205 after the reported CLI version. - [x] #6224 — expose both text-asset sources and encode the exactly-one requirement in the standard MCP schema. - [x] #6225 — could not reproduce the project-specific upstream timeout; closed with safe confirmation coverage and improved structured diagnostics, without claiming a latency fix. - [x] #6226 — could not reproduce the project-specific upstream timeout; closed with safe confirmation coverage for insert-fragment, without adding a speculative fragment-specific fix. - [x] #6229 — reproduced the reported two-process sequence with the current local CLI and a real browser; both captures passed, so the 0.293.0 report was closed without a speculative fix. - [x] Require explicit user consent before preview, screenshots, diffs, OCR, or rendered visual audits unless visual verification was requested. ## Technical notes - Ambiguous mutation responses are confirmed only with the same idempotent transaction id. If confirmation is also ambiguous, the session reports `AMBIGUOUS_COMMIT`, refreshes state, and never replays a fresh mutation. - CLI error mapping retains the original remote error as a non-enumerable cause, so JSON gateway status reaches the ambiguity classifier without exposing raw remote context in serialized diagnostics. - Forced asset uploads are not automatically retried after an unknown/network/5xx outcome. Batch results retain the original input index, including duplicate filenames. - Stable issue codes and constraints are retained for diagnostics. Arbitrary validation paths, messages, argument values, project content, and raw contextual data are excluded. - The MCP handshake remains the source of tool input schemas; goal-specific guides avoid duplicating those contracts and reduce model-context cost. - `update-asset-content` now exposes `path` and `content` with a machine-readable `oneOf` constraint, matching the runtime rule that exactly one source is required. - Redirect targets with their own pathname or query still replace those request components. - Generated runtime contracts, CLI documentation, product documentation, and deployment fixtures were regenerated from their sources. ## Verification - [x] Three independent review/test agents exercised visual consent and preview behavior; mutation, asset, and privacy behavior; and accessibility, styles, and redirects. - [x] `pnpm checks` passed after the final transport follow-up: all workspace tests and typechecks, lint with warnings denied, package boundaries, generated API contracts, generated docs and documentation checks, and the complete fixture link/sync/build pipeline. - [x] Changed-package suites passed, including Project Build (2,125 tests), HTTP client (42 tests), CLI, Protocol, and Builder. - [x] Complete `pnpm evaluations` run on the preceding implementation commit: all five real-world fixtures and every behavioral check passed. Four baseline comparisons passed; one font-assets sample exceeded only its model-output token allowance, and its isolated rerun passed. Evaluations were not rerun after the final transport and schema follow-ups because fresh approval is required. - [x] Design evaluation MCP response bytes improved from the 39.8 KB baseline to 37.6 KB after removing duplicated guide contracts. - [x] Documentation impact reviewed; generated MCP docs and multi-file upload guidance are updated. ## Related issues Closes #6207 Closes #6208 Closes #6209 Ref #6210 Ref #6211 Closes #6212 Closes #6213 Ref #6214 Ref #6215 Ref #6216 Ref #6217 Ref #6218 Closes #6219 Closes #6220 Ref #6221 Ref #6223 Closes #6224 Ref #6225 Ref #6226 Ref #6229 |
||
|
|
626b5e741b |
fix: Reduce discovery for authored fragments (#6203)
Ref #6177 Ref #6154 ## Outcome Bounded authored-fragment requests no longer receive broad design/authentication context bundles, registry discovery, or design-token operations through generic keyword matching. The initial ProjectSession synchronization is unchanged. Focused target reads, missing nested schemas, and expression guidance can still add calls when the requested fragment requires them. ## Root cause `meta.guide` treated the generic word `design` as visual intent and allowed workflow-specific context bundle tools to enter ordinary keyword-ranked recommendations. An authored component insertion could therefore be classified as visual work and receive `inspect-design-context` even without a supplied visual reference or a request to reuse the project design system. ## Implementation - Give specialized goal guides stable IDs and return structured routing metadata with the matched workflow and broad context tools. - Keep `inspect-auth-context` and `inspect-design-context` exclusive to their specialized workflows. - Treat Figma, screenshots, supplied designs, and explicit design-system references as visual intent without treating every use of `design` as visual work. - Suppress component/template registry discovery for explicit `insert-fragment` or authored-fragment requests. - Suppress design-token operations for those requests unless the brief explicitly asks for design-system or token reuse. - Preserve the existing design-input workflow for Figma, screenshots, and supplied designs. ## Todo - [x] Add a regression test for the reported authored timer/component workflow. - [x] Demonstrate that the regression test fails before the routing fix and passes afterward. - [x] Preserve explicit design-input discovery and verification behavior. - [x] Add machine-readable workflow routing metadata. - [x] Review documentation impact and update the authoritative MCP manual plus generated GitBook output. - [x] Review fixture impact; no fixture inputs or generated fixture bundles are affected. - [ ] Run the complete local agent evaluation suite. It was not run because repository policy requires separate explicit approval and approval was not provided. ## Verification - Project-session MCP tests: 117 passed. - Project-build and CLI typechecks passed. - Targeted oxlint passed. - Documentation generator tests and documentation typecheck passed. - MCP documentation and CLI generated docs were regenerated twice with stable hashes. - `git diff --check` passed. ## Tradeoffs and limitations - Brief classification remains deterministic intent matching; clients still decide which recommended tools they actually call. - The change prevents broad context tools from being recommended generically but does not enforce a universal discovery-call limit. - A fragment that genuinely needs existing tokens, unfamiliar expressions, or unknown target structure can still require focused discovery. - No schema migration, project-data migration, or fixture regeneration is required. |
||
|
|
df3601c26a |
fix: Capture preview failure diagnostics (#6206)
## Summary - Give invalid project bundles a stable `PROJECT_BUNDLE_INVALID` error code and structured validation issues. - Remember the latest failed MCP tool call and attach sanitized diagnostics to automatic issue reports. - Render the tool, error code, bundle contract, and invalid schema paths in a dedicated issue section. ## Scope and issue assessment This PR improves diagnostics; it does not change which asset shapes `preview.start` accepts. Issue #6198 came from CLI 0.290.0 and did not include the rejected field, value, or bundle contract, so its exact root cause cannot be established. Node 22 is not implicated by the available evidence. Canonical video assets were added separately in #6189, which may explain an old-CLI schema mismatch, but that relationship is an inference rather than a confirmed reproduction. Per project triage policy, this PR closes #6198 despite being diagnostics-only. If the failure still exists on a current CLI, the enriched report will provide enough evidence to reopen or file a new actionable issue. ## Implementation Bundle validation exposes structured paths such as `assets.0.type`. The MCP host records the latest failure and injects it into CLI-owned runtime metadata when `report-issue` is called. The MCP registry supplies either a canonical known tool name or `unknown`. Stable error codes are validated once by the CLI error-code boundary. Detailed paths are included only for `PROJECT_BUNDLE_INVALID`, capped at 30 issues, and omit received values, error messages, examples, filenames, IDs, details, and stack traces. The bundle-contract field remains optional so reports from older CLI versions still validate. CLI-owned runtime metadata is not advertised as model-authored MCP input, keeping the handshake compact and making ownership explicit. ## Checklist - [x] Add structured bundle validation diagnostics. - [x] Capture the latest MCP failure in issue-report runtime metadata. - [x] Render deterministic diagnostics in GitHub issue bodies. - [x] Add fail/pass regression coverage and privacy constraints. - [x] Keep CLI-owned runtime fields out of the model-facing MCP schema. - [x] Regenerate the server-only API contract. - [x] Review documentation impact — no product documentation changes are required; this only enriches internal anonymous issue reports. - [ ] Run agent evaluations — not run because repository policy requires explicit approval. ## Verification - Real Node 22.22.1 stdio MCP run with an isolated malformed local bundle returned `PROJECT_BUNDLE_INVALID`, path `assets.0.type`, code `invalid_value`, and constraint `one_of:["image"]`. - The following real `report-issue` call was accepted by the server and deduplicated to existing issue #6198; it created no duplicate issue and changed no linked project. - Project-build: 2,115 tests passed. - CLI: all 1,005 unaffected tests passed; one unrelated process-supervisor timing test failed once and its exact two owner-disconnect cases passed on immediate rerun. - Project-build and CLI typechecks passed. - Formatter and diff checks passed. - All latest GitHub workflows passed, including both test/typecheck matrices, visual regression, size and generated checks, packaged SSG, and all six Builder E2E shards. Closes #6198 |
||
|
|
f2cece41ee |
fix: Reconnect responsive screenshots after preview restart (#6205)
## Summary Reconnect the reusable browser capture session and retry once when a managed screenshot reports that its Browser DevTools connection closed. The active generated-site preview remains running, so the retry recreates only the failed browser session and replays the requested single or multi-viewport capture. ## Root cause Vision already performs a bounded recovery inside its browser runtime. If that recovery still surfaced a DevTools session closure, the MCP preview handler reset the failed session during error cleanup but returned the failure to the caller. The next manual screenshot call could succeed, but the first screenshot after a preview restart still failed. ## Technical choices - Give browser-session closure errors a stable typed code at the Vision boundary. - Detect that typed failure in the MCP preview handler. - Close and recreate only the reusable browser capture session. - Retry the complete capture once against the existing active preview. - Apply the same recovery to one-viewport and responsive batch captures. - Report the reconnect as a screenshot lifecycle progress checkpoint. ## Impact A one-viewport responsive screenshot after preview restart now recovers automatically from a closed DevTools connection. Other screenshot errors retain their existing behavior, and repeated connection failure remains bounded. ## Checklist - [x] Add a fail-first regression for preview restart followed by a one-viewport responsive capture - [x] Recreate the failed browser session without restarting the active preview - [x] Retry the complete screenshot request once - [x] Preserve existing behavior for non-session errors - [x] Verify the recovery through a real preview server, Chrome, CDP, rendering, and PNG output - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected - [x] Review documentation impact: no update is required because this restores documented automatic screenshot behavior - [ ] Run agent evaluations (requires separate explicit approval) ## Verification - Regression failed before the implementation with `Browser DevTools connection closed.` and passed after it - Real-browser harness with Google Chrome: - restarted a real local HTTP preview and captured a full-page `1440×900` PNG successfully on the first call - forcibly closed the real CDP socket during `Page.captureScreenshot` twice and confirmed the lower browser retry surfaced the typed session-closed failure - confirmed the MCP handler created a new browser session, replayed the full capture successfully, and emitted `tool screenshot reconnecting browser session` - confirmed browser recovery did not restart the active preview - closed all Chrome processes, preview resources, temporary profiles, and screenshot artifacts - `pnpm --filter webstudio exec vitest run src/commands/mcp-preview.test.ts` — 44 tests passed - `pnpm --filter @webstudio-is/vision test` — 13 files, 81 tests passed - `pnpm --filter webstudio typecheck` - `pnpm --filter @webstudio-is/vision typecheck` - `pnpm exec oxlint --deny-warnings packages/vision/src/screenshot-browser-cdp.ts packages/cli/src/commands/mcp-preview.ts packages/cli/src/commands/mcp-preview.test.ts` - `pnpm exec oxfmt packages/vision/src/screenshot-browser-cdp.ts packages/cli/src/commands/mcp-preview.ts packages/cli/src/commands/mcp-preview.test.ts` - `git diff --check` The DevTools failures were injected deterministically at the screenshot command. The ordinary post-restart capture used the same real preview and Chrome path without fault injection. Agent evaluations were not run because repository policy requires separate explicit approval. Closes #6200 |
||
|
|
b2d62b2e49 |
fix: Restore scoped descendant selectors (#6195)
## Summary Restore custom state selectors that target descendants of the selected instance, including `:hover .button` and `:hover > .icon`. The CSS engine already generated these selectors correctly. #5886 unintentionally rejected them while hardening MCP style inputs against selectors that can escape instance scope. ## Technical choices - Parse exactly one selector with `css-tree`. - Require the selector to begin with a pseudo-class, pseudo-element, or attribute state anchored to the selected instance. - Allow only descendant and direct-child combinators after that anchor. - Continue rejecting selector lists, unanchored type/class/ID selectors, sibling combinators, unknown pseudo-selectors, and pseudo-elements used as ancestors. - Document CSS variables as the preferred parent-child interaction pattern; use descendant selectors when selector-based targeting is specifically required. ## Todo - [x] Restore scoped descendant and direct-child selectors. - [x] Preserve instance-scope protections. - [x] Cover real authoring inputs and generated CSS. - [x] Demonstrate new tests fail without the restored behavior and scope guards. - [x] Verify the reported workflow through the local CLI/MCP and generated preview. - [x] Review documentation impact and update the authoritative Builder docs. - [x] Verify generated API contracts remain current. ## Verification - `pnpm --filter @webstudio-is/css-data test` — 4,623 passed, 1 skipped - `pnpm --filter @webstudio-is/css-data typecheck` - `pnpm --filter @webstudio-is/project-build exec vitest run src/runtime/styles.test.ts src/runtime/audit.test.ts` — 198 passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm lint` - `pnpm check:generated-api` - Documentation targets and anchors verified - Local MCP disposable-fixture workflow: - Discovered `insert-fragment` and `update-styles` through MCP metadata. - Inserted a card with a descendant `<button class="button">`. - Dry-run and committed `state: ":hover .button"`; `get-styles` returned the persisted state. - MCP preview generated `.chjrfuf:hover .button` while the card used the `chjrfuf` instance class, proving the selector remained instance-anchored. - Preview screenshot completed and returned HTTP 200. - Agent evaluations were not run because the suite has no custom-selector coverage ## Known limitation Sibling combinators remain unsupported because they can select elements outside the selected instance. Selector lists remain unsupported because later list entries can escape the generated instance prefix. Closes #6175 |
||
|
|
b1d23f69c0 |
fix: Report unsupported Node versions at CLI startup (#6201)
## Summary - Reject unsupported Node.js versions before loading the CLI bundle. - Report the declared engine range and detected version with an install-and-retry instruction. - Keep the runtime check aligned with `package.json#engines.node`. ## Root cause The CLI declares Node.js 22.12+ but did not enforce that requirement at startup. Package managers can warn and continue, allowing unsupported runtimes to reach preview code. Execa 10 then initializes `Set.prototype.union()`, which is unavailable in Node 20 and causes the delayed `screenshot.responsive` failure. ## Technical choices - Validate the runtime directly at the published executable boundary. - Parse the declared engine range with `semver`. - Dynamically import the CLI only after the runtime passes validation. - Report the exact engine range rather than assuming every valid range means “or newer.” - Test the published `bin.js` in a subprocess with an injected unsupported runtime version. - Write the actionable startup failure to stderr and exit nonzero. - No migrations or public API changes. ## Checklist - [x] Add the startup runtime guard. - [x] Add executable-level regression coverage for unsupported Node.js. - [x] Verify the supported runtime still loads the CLI. - [x] Review fixture impact; no fixture inputs or outputs are affected. - [x] Review authoritative documentation; `docs/university/cli.md` already requires Node.js 22.12+, so no update is needed. - [ ] Run agent evaluations — not run because the requester declined them. ## Verification - Published and local launcher tests: 4 passed. - CLI typecheck: passed. - Targeted lint and formatting: passed. - CLI production build: passed. - Node.js 18.16.1 and 20.12.2 executable checks: exited 1 before loading the CLI, reported the `>=22.12.0` requirement, and wrote no stdout. - Node.js 22 executable check: CLI loaded successfully. - Package dry run: includes the guarded `bin.js` and no separate runtime helper. - `git diff --check`: passed. - The executable-level regression test was confirmed to fail against the previous message/implementation and pass after the direct guard was applied. ## Known limitation An MCP client may wrap a subprocess startup failure in its own UI, but the CLI now provides the actionable requirement and installation instruction on stderr before any tool runs. Closes #6190 |
||
|
|
a2e01a8ebe |
fix: Export configured Webhook Form methods (#6192)
## Summary
- Add an optional metadata contract for copying allowlisted resource
fields into generated component props.
- Pass action resources into page component generation.
- Configure Webhook Form's resource-bound `action` prop to generate the
form's `method` prop.
- Preserve explicitly authored props over generated resource props.
- Add generic generator, schema safety, rendered static-export
regression coverage, and updated generated fixture output.
## Root cause
Builder stores a Webhook Form's selected method on its action resource,
not as an ordinary instance prop. Component generation serialized the
resource-bound action identifier but had no generic contract for copying
safe resource fields into component props. The generated component
therefore received `action={"action"}` without the configured method,
and plain HTML rendering omitted the `method` attribute.
## Implementation
Resource prop metadata can now declare same-named fields using
`generatedProps`:
```ts
generatedProps: ["method"]
```
The component generator resolves those declarations generically; it
contains no Webhook Form component checks. The schema currently
allowlists only `method`, so resource URLs, headers, bodies, and other
potentially sensitive configuration cannot be generated as component
props. An explicit instance prop with the same name takes precedence.
Dynamic routed Webhook Forms retain their existing browser-to-server
POST behavior. This change preserves configured resource metadata in
generated component output and does not add static Webhook submission
support.
## Todo
- [x] Reproduce the missing method from an existing resource-bound
Webhook Form.
- [x] Demonstrate the generator regression test fails against the
previous output.
- [x] Define a typed, allowlisted generated-props contract for
resources.
- [x] Apply generated props generically without component-name checks.
- [x] Preserve explicit instance props.
- [x] Verify a real SSG prerender contains `method="post"`.
- [x] Verify unsafe resource fields such as `url` cannot be generated.
- [x] Give the build/prerender regression test the established 30-second
timeout.
- [x] Regenerate and verify the affected Webstudio Features fixture.
- [x] Run affected lint, typechecks, unit suites, builds, and CLI
prebuild tests.
- [x] Review documentation impact; no update is needed because
configuration and static-site support constraints are unchanged.
## Verification
- Regression test before implementation: failed because resource-bound
forms contained `action` but no generated `method`.
- `@webstudio-is/sdk`: 517 tests passed; focused schema test passed
after the rename.
- `@webstudio-is/sdk-components-react`: 126 passed, 1 skipped.
- `@webstudio-is/react-sdk`: 140 tests passed; focused generator test
passed after the rename.
- CLI prebuild: 59 tests passed; focused rendered static HTML test
passed in 2.7 seconds with a 30-second test timeout.
- Webstudio Features fixture: regeneration is idempotent; typecheck and
production build passed.
- Typechecks: SDK, SDK components, React SDK, and CLI.
- Targeted formatting and `oxlint --deny-warnings`.
- React SDK and CLI builds.
- `git diff --check origin/main...HEAD`.
- Agent evaluations were not run because approval was not requested.
Closes #6191
|
||
|
|
2df130171f |
feat: Resolve asset references as structured metadata (#6184)
## Summary - add exact `$ref` asset values that resolve to Asset Manager metadata - keep plain local asset paths returning URL strings for backward compatibility - derive reference metadata from the canonical asset object so newly added asset fields flow through automatically - let Assets query output fields select only the metadata returned, including nested arrays - carry the same resolved shape through preview, generated preview, published runtime, and static export - document the syntax and accessible image binding in Content Engine and MCP docs ## Design The source document declares only the relationship: ```yaml featureImage: $ref: ./assets/hero.png ``` The Assets query controls projection with fields such as `properties.featureImage.src` and `properties.featureImage.description`. Selecting `properties.featureImage` returns the canonical Asset Manager asset metadata together with the resolved `src`. The Content Engine runtime contract accepts the canonical asset object instead of maintaining a second metadata field list; `url` becomes `src`, and internal `contentRef` is not exposed. Plain strings retain their existing URL-string result. Existing document `$ref` behavior is preserved by resolving structured asset metadata only when the target is a known non-document asset. ## Verification - [x] Content Engine full test suite: 298 tests - [x] SDK full test suite: 517 tests - [x] Asset repository tests: 39 tests - [x] CLI prebuild tests: 58 tests - [x] Content Engine, SDK, Asset Uploader, CLI, and Project Build typechecks - [x] Repository lint - [x] Content Engine and MCP documentation generation and tests - [x] Generated API check - [x] Local fixture build and generated fixture update - [x] New behavior tests demonstrated fail before/pass after the implementation - [ ] Complete fixture sync (development API currently rejects this branch's newer CLI protocol; local fixture build passes) - [ ] Agent evaluations (not run; require explicit approval) ## Checklist - [x] Local structured references return field-selected metadata - [x] Newly added canonical asset fields flow through without a Content Engine whitelist change - [x] Plain-path queries remain backward compatible - [x] Nested object and array projection - [x] External URL strings remain usable - [x] Missing or null descriptions allow `??` fallback to the title - [x] Expanded metadata counts toward query result-size limits - [x] Documentation impact reviewed and Content Engine and MCP docs updated - [ ] Missing asset targets return a non-failing unresolved value and dedicated diagnostic - [ ] Apply the resource and Image binding changes to the separate Webstudio blog project ## Known limitation A `$ref` whose asset target no longer exists is not yet converted into an unresolved asset value with a dedicated diagnostic. This PR intentionally does not claim that acceptance criterion yet. Ref #6179 |
||
|
|
d4a876bc35 |
fix: Report terminated MCP single-op calls (#6187)
## Summary - return structured `MCP_CALL_TERMINATED` output when a one-shot MCP call receives SIGHUP, SIGINT, or SIGTERM, or reaches `beforeExit` without a result - reuse the existing bounded host-cleanup and signal-preservation path from `mcp run` - cover the reported anchor → inline SVG → `pointer-events: none` fragment through the real MCP normalization path ## Evidence and scope The reported fragment itself does not hang: it normalizes in about 20–30 ms on both CLI 0.290.0 and current main, including Node 26.0.0. The reproducible gap is in the surrounding process lifecycle: `mcp run` reports interrupted calls, while `mcp single-op-call` had no termination handlers. An external caller timeout could therefore end a one-shot call without a structured result. The original long-running project-session condition could not be reproduced with the available credentials. This PR fixes the missing termination diagnostic; it does not claim that nested SVG parsing caused the stall. ## Technical choices - Install termination handling before input parsing and project-session startup so every active phase is covered. - Re-check termination after every asynchronous preflight phase so refreshes and mutations cannot start during cleanup. - Stop reporting the call as active once success or failure output is ready, preventing duplicate JSON during cleanup. - Preserve the original terminating signal after bounded cleanup instead of converting it to an ordinary exit. - Do not add an arbitrary operation timeout: a timed-out committed mutation can still finish remotely and would make retry safety ambiguous. ## Todo - [x] Reproduce the reported fragment on CLI 0.290.0, current main, and Node 26.0.0 - [x] Add structured termination reporting to `mcp single-op-call` - [x] Cover the nested SVG style input and termination payload - [x] Exercise the installed one-shot `beforeExit` lifecycle, not only the payload formatter - [x] Stop execution after asynchronous checkpoint preflight resumes from termination - [x] Review documentation impact — existing CLI docs already promise structured JSON for failed one-shot calls; no content update is required ## Verification - Nested-SVG reporter regression demonstrated fail-before (`reportMcpSingleOpCallTermination is not a function`) and pass-after - Installed-lifecycle regression demonstrated fail-before when the active-call hook was disabled and pass-after when restored - `pnpm --filter webstudio exec vitest run src/commands/mcp.test.ts` — 43 passed - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint --deny-warnings packages/cli/src/commands/mcp.ts packages/cli/src/commands/mcp.test.ts` - `pnpm --filter webstudio exec vitest run src/bin.test.ts` — 3 passed - `pnpm --filter webstudio test` — 998 passed; two unrelated concurrent-suite timeouts (`src/bin.test.ts` and `evaluations/high-impact/fixture-api.test.ts`). The launcher test passed in isolation. The evaluation fixture was not rerun because evaluations require separate approval. ## Known limitations - SIGKILL cannot be intercepted, so no process can emit a final diagnostic in that case. - This change does not impose an internal operation deadline or cancel in-flight mutations. - A real authenticated reproduction is still needed to identify why the original project-session call remained active. Ref #6132 |
||
|
|
0760d6cfec |
fix: upload videos from Builder and MCP (#6189)
## Summary Video uploads failed because file detection returned `video` while the canonical Asset schema accepted only `font | image | file`. The mismatch was introduced when video detection was added in #5539; the recent JSON work only exposed the adjacent contract gap and did not cause it. This makes `video` a first-class `Asset["type"]` across Builder, SDK, storage formatting, project bundles, HTTP uploads, and MCP. There is no separate upload-only type and no conversion from `video` to `file`. ## Implementation - Add the canonical `video` Asset variant with width/height metadata. - Make Builder UI reservations and optimistic assets preserve `video`. - Make MCP and HTTP upload schemas derive their enum from the canonical SDK `assetType`. - Preserve video metadata through S3 and filesystem upload paths. - Include canonical video assets in project/canvas bundles. - Keep legacy video records without dimension metadata readable as generic `file` assets. - Fall back to a labeled file preview when the browser cannot decode a video format such as AVI; browser-supported formats continue to render video thumbnails. - Regenerate runtime operation contracts and sync fixtures from the PR deployment. ## Contract protection - Assert every detected upload category parses as a canonical Asset type. - Exercise Builder reservations for every value in `assetType.options`. - Assert MCP's upload enum exactly equals `assetType.options`. - Exercise direct HTTP video upload metadata and URL construction. - Cover canonical video formatting, legacy fallback, preview assets, and canvas serialization. - Verify a video decode error replaces the blank media element with a visible format-labeled fallback. - Store canonical WebM and MP4 records with dimensions in the `webstudio-features` fixture and verify generated runtime metadata. ## Checklist - [x] Make video a canonical Asset type - [x] Verify Builder UI upload flow - [x] Verify MCP and direct HTTP upload contracts - [x] Add fail/pass regression coverage for the broken paths - [x] Add an Assets panel fallback for browser-unsupported video formats - [x] Regenerate runtime contracts - [x] Sync and build fixtures against the PR deployment - [x] Run affected package tests, typechecks, lint, package-boundary, generated API, and generated docs checks - [x] Review documentation impact — existing Assets documentation already lists supported video formats and upload behavior; no user-facing documentation change is required ## Verification - Builder: 2,543 tests passed - Builder asset thumbnail regression: 14 tests passed - Project build/MCP runtime: 2,111 tests passed - CLI: 999 tests passed - SDK: 516 tests passed - Asset uploader: 199 tests passed - Protocol: 92 tests passed - HTTP client: 38 tests passed - Typechecks passed for Builder, SDK, asset uploader, project build, protocol, HTTP client, and CLI - Lint and package-boundary checks passed - Generated API and documentation checks passed - Fixture sync completed against `fix-video-up-be4d8a0.development.webstudio.is` - All fixture builds passed after synchronization Closes #6186 |
||
|
|
5a57234c75 |
revert: Store Content Block content in MDX assets
Revert the accidental merge of #6125 so the implementation can continue in draft PR #6181. |
||
|
|
5d10a7de60 |
fix: Recover responsive screenshots after DevTools disconnects (#6170)
## Summary Recover responsive screenshot batches when the Browser DevTools WebSocket closes transiently. The capture session now treats a DevTools socket closure as the same recoverable session failure as an unexpected browser exit. It restarts Chromium once and reruns the complete viewport batch, so callers receive a consistent set of screenshots instead of partial artifacts. ## Root cause The DevTools socket close handler rejected pending commands with a generic `Error`. The reusable browser retry boundary only recovered typed browser-session closures or a browser process that had exited, so a closed socket with a still-running Chromium process escaped as `MCP_TOOL_FAILED`. ## Technical choices - Classify a DevTools WebSocket closure as `BrowserSessionClosedError` at the CDP boundary. - Reuse the existing bounded browser-session restart path instead of adding a separate MCP-layer retry. - Retry the complete responsive batch once so results remain all-or-nothing. - Preserve the original `Browser DevTools connection closed.` diagnostic when the replacement connection also closes. ## Impact A transient DevTools disconnect during a responsive capture automatically restarts the reusable browser and captures every requested viewport. Repeated connection loss still fails after one retry without looping indefinitely. ## Checklist - [x] Add a fail-first regression for a two-viewport responsive capture - [x] Verify mobile and desktop widths are both recaptured after reconnect - [x] Verify a second consecutive disconnect returns the original error - [x] Independently verify recovery with real Chrome, CDP, rendering, and PNG output - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected - [x] Review documentation impact: no user-facing documentation changes are required because this restores documented behavior - [ ] Run agent evaluations (requires separate approval) ## Verification - New responsive reconnect regression failed before the implementation with `Browser DevTools connection closed.` and passes after it - Independent real-browser harness with Google Chrome `151.0.7922.138`: - served a real local responsive page and captured `375×812` and `1440×900` - forcibly closed the first real CDP WebSocket during `Page.captureScreenshot` - observed Chrome #1 terminate, its profile get removed, Chrome #2 launch, and the complete viewport batch replay - produced valid PNGs at both requested dimensions and left no browser processes or temporary profiles behind - `pnpm --filter @webstudio-is/vision test` — 13 files, 81 tests passed - `pnpm --filter @webstudio-is/vision typecheck` - `pnpm --filter webstudio exec vitest run src/commands/mcp-preview.test.ts` — 43 tests passed - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint --deny-warnings packages/vision/src/screenshot-browser-cdp.ts packages/vision/src/screenshot-browser-cdp.test.ts` - `pnpm exec oxfmt packages/vision/src/screenshot-browser-cdp.ts packages/vision/src/screenshot-browser-cdp.test.ts` - `git diff --check` The real-browser fault was injected deterministically at the first screenshot command rather than produced by an organic OS or network failure. It exercised the reported DevTools closure boundary and complete responsive-batch recovery. Agent evaluations were not run because they require separate explicit approval. Closes #6169 |
||
|
|
5ec3547d36 |
fix: Support JSON content files in Builder (#6168)
## Summary - make the complete asset filename editable in Asset settings - convert existing editable text assets when their extension changes while preserving the asset ID - accept every JSON root type and normalize JSON-compatible syntax into formatted strict JSON - expose the same optional extension change through MCP/API `update-asset-content` - initialize new JSON files and empty text-to-JSON conversions with a valid empty object - distinguish browser URL imports from JSON file uploads so JSON objects with a root `url` field remain file content - update the Assets and Content Engine documentation ## Root cause Asset settings rendered the extension as a fixed suffix outside the name input. The metadata rename mutation could only change the display basename, while content revisions always inherited the current storage extension. As a result, changing `.md` to `.json` was impossible in the UI and unavailable through the shared MCP/API revision command. Asset settings now edits the complete filename. Ordinary renames keep using the metadata mutation. A text-extension change loads the current content, validates it for the target format, and writes a new immutable revision through the existing conflict-safe content endpoint. The existing Acorn-backed `parseJsonExpression` utility accepts JSON-compatible syntax without evaluating code and serializes it as strict JSON. Objects, arrays, strings, numbers, booleans, and `null` are all accepted. ## Checklist - [x] Create JSON files by entering a `.json` filename - [x] Edit the complete filename in Asset settings - [x] Convert editable text-file extensions while preserving the asset ID - [x] Expose extension conversion through `update-asset-content` - [x] Create JSON files and convert empty text files with a valid empty object - [x] Normalize safe JSON-compatible syntax to strict JSON - [x] Accept objects, arrays, and scalar JSON roots - [x] Reject executable or incomplete content - [x] Preserve browser-uploaded JSON object shapes - [x] Review and update authoritative Builder documentation - [x] Add focused UI, revision, HTTP-client, CLI/MCP, protocol, and upload regression tests - [x] Run affected typechecks, lint, documentation checks, and the Builder production build - [ ] Manually verify create, edit, rename `.md` to `.json`, reload persistence, and Content Engine query in a browser - [ ] Run the complete local agent evaluation suite if approved ## Verification - 217 focused tests passed across Builder, asset revisions, HTTP client, CLI/MCP, and protocol - Builder, asset-uploader, HTTP-client, protocol, CLI, and project-build typechecks passed - Builder production build passed - MCP and Content Engine documentation checks passed - `oxlint` on changed TypeScript files passed - `git diff --check` passed - Regression tests were demonstrated failing before the implementation and passing afterward A disposable E2E database and PostgREST stack bootstrapped successfully in the earlier real-path test, but UI automation remained blocked because no controllable browser was available. Fixture inputs and generated fixture outputs are not affected. Agent evaluations were not run because approval is required and was not requested. Closes #6167 |
||
|
|
81d5148046 |
fix: canonicalize trailing-slash page URLs (#6173)
## Outcome Canonical page URLs now omit a trailing slash in Webstudio Cloud sites and exported JavaScript applications. A request such as `/about/?campaign=launch` receives a permanent `301` redirect to `/about?campaign=launch`, preventing both URL variants from serving identical page content. The behavior is implemented once in the generated root redirect handler, so it covers fixed and dynamic application routes without generating an extra route per page. Exact project redirects remain authoritative. Protocol-relative-looking paths such as `//example.com/` are left untouched so canonicalization cannot become an external redirect. Static exports cannot redirect requests themselves. Their URL behavior remains host-specific and is documented for Cloudflare Pages, Netlify, Vercel, and other static hosts. ## Implementation - Add one shared pathname normalizer in the SDK. - Apply canonicalization after exact authored redirect matching in both generated application runtimes. - Ignore repeated leading slashes before constructing a redirect location. - Extend redirect-loop detection to model the implicit canonical redirect. - Regenerate the affected fixture applications from their templates. - Document application canonicalization and host-specific static export behavior. ## Todo 1. [x] Add central trailing-slash canonicalization. 2. [x] Preserve query strings, encoded path segments, and the root path. 3. [x] Cover concrete dynamic URLs without per-route generation. 4. [x] Preserve explicit project redirect precedence. 5. [x] Detect redirect loops that pass through canonicalization. 6. [x] Prevent protocol-relative external redirects. 7. [x] Regenerate and review fixture output. 8. [x] Review documentation impact; document application and SSG behavior. 9. [x] Run targeted and repository-level verification. ## Verification - SDK tests: 548 passed - SDK typecheck: passed - Project Build tests: 2,379 passed - Project Build typecheck: passed - CLI tests: 997 passed; two tests timed out only while three package suites ran concurrently, then both affected files passed in isolation (6/6) - Redirect regression suite after security follow-up: 302 passed - CLI typecheck: passed - `pnpm lint`: passed - `pnpm check:package-boundaries`: passed - `pnpm fixtures`: passed - Documentation internal anchors and Markdown whitespace: checked - New regression tests were confirmed failing before their implementations and passing afterward - Agent evaluations were not run because they require separate explicit approval Closes #6172 Closes https://github.com/webstudio-is/webstudio/issues/4327 |
||
|
|
86b6310fff | feat: Store Content Block content in MDX assets | ||
|
|
ab5717c9cf |
feat: Support CSS properties of every status (#6166)
## Summary - Make every CSS property in the current MDN dataset available in the Advanced style workflow, regardless of standards status. - Mark experimental, nonstandard, and obsolete properties with a yellow warning icon, status-specific tooltip, and MDN link. - Add complete CSS anchor-positioning property and value support. - Update `mdn-data` from 2.28.0 to 2.33.0 and `css-tree` from 3.1.0 to 3.2.1. ## Root cause Webstudio generated its supported property list from MDN data but filtered by status and then manually allowed a few experimental and nonstandard entries. A property could therefore exist in the installed MDN package without being exposed by the Builder. Runtime validation had a separate grammar gap. CSS-tree 3.2.1 now includes the anchor functions and alignment values, but its bundled data predates the current `position-anchor: normal | match-parent` additions. ## Implementation - Remove status-based property filtering and the nonstandard-property allowlist. - Generate one property-to-status map for 486 standard, 40 experimental, 119 nonstandard, and 15 obsolete properties. - Show status-specific browser-compatibility guidance for every non-standard status. Active declarations keep the warning after the value with 3px left spacing. - Infer MDN links from existing property metadata and fall back to MDN search for entries without a direct URL. - Preserve known vendor prefixes from the generated property inventory instead of maintaining a prefix allowlist. - Generate WebKit text fill/stroke longhands directly from MDN instead of preserving them through parser exceptions. - Preserve unsupported initial-value shapes as unparsed CSS rather than excluding their properties. - Use CSS-tree 3.2.1's native anchor-function and alignment grammars. Keep one narrow extension for the current `position-anchor` keywords missing from its bundled MDN data. - Generate recursively flattened shorthand longhands and initial values from MDN. - Expand syntax-defined shorthands generically from CSS-tree's matched property captures, including function-valued components. - Decline generic expansion when CSS-tree and MDN disagree about the longhand set or a longhand repeats. - Update the font grammar reference and CSS math validation for CSS-tree 3.2.1 compatibility. - Regenerate CSS metadata and property-variable fixtures. ## Checklist - [x] Include MDN properties regardless of status. - [x] Generate status metadata for standard, experimental, nonstandard, and obsolete properties. - [x] Show warning icons in Add styles results and active declarations. - [x] Add status-specific consequences and MDN links. - [x] Preserve generated vendor-prefixed properties during CSS import. - [x] Generate WebKit text fill/stroke longhands without parser exceptions. - [x] Support `anchor()`, `anchor-size()`, and `anchor-center`. - [x] Support current `position-anchor` keywords. - [x] Expand syntax-compatible shorthands through generic MDN metadata and CSS-tree captures. - [x] Cover ordered optional, unordered, slash-separated, function-valued, omitted, CSS-wide, variable, invalid, and incompatible-data cases. - [x] Verify new status, warning, prefix, and shorthand tests fail without their implementations and pass when restored. - [x] Update to CSS-tree 3.2.1. - [x] Regenerate CSS metadata and property-variable fixtures. - [x] Review documentation impact; no authoritative Builder documentation lists individual supported CSS properties, so no update is needed. - [x] Review fixture impact; 668 fixtures and 2,030 valid cases were regenerated with zero unsupported. ## Verification - `pnpm --filter @webstudio-is/css-data test` — 4,618 passed, 1 skipped. - Builder CSS editor and property-status tests — 25 passed. - CSS data, CSS engine, Project Build, and Builder typechecks passed. - Lint, formatting, repeated regeneration, and diff checks passed. ## Known limitation This change covers CSS declarations and values. It does not add a dedicated Builder editor for the `@position-try` at-rule. Closes #6162 |
||
|
|
af11ec211f |
feat: Search all local project data from MCP (#6165)
Ref #6154 ## What - Add standalone search across all 13 synchronized Builder namespaces. - Search in the CLI ProjectSession and send only paged matches to the model; initial synchronization is unchanged. - Return stable match ids, exact paths, entities, references, and affected routes. - Preserve deprecated `scopes` output, redact recognized credential fields, and document the command. ## Objectives - [x] O1 — Universal Builder namespace search - [x] O2 — Stable identity and actionable location - [x] O3 — Filters, pagination, route impact, and references - [x] O4 — Honest synchronization → local search → model-input boundary - [x] O5 — Standalone command and workflow documentation - [x] O6 — Safety, compatibility, typed contracts, and regression tests Verified by Atlas (implementation), Scribe (docs/workflow), and Sentinel (adversarial review). ## Remaining #6154 work - [ ] Atomic semantic multi-record updates - [ ] Targeted route rendering and assertions - [ ] General slow-operation consent and time budgets - [ ] Full agent evaluation suite after approval ## Verification - Project search + MCP: 129 tests passed - Protocol docs: 8 tests passed - CLI schema/docs: 23 tests passed - Compact MCP handshake budget test passed - Project-build, protocol, and CLI typechecks passed - Generated docs and API checks passed - Agent evaluations not run; approval is required ## Limitation Asset metadata is searchable. Asset binaries and document contents are not Builder namespace data and are not searched. |
||
|
|
4ca695cf46 |
fix: Improve MCP screenshot and session compatibility (#6163)
## Summary Allow responsive MCP screenshots to use local project data and remove the CLI session storage dependency on the Web Crypto global. ## Root causes - Responsive capture rejected every `source: "local"` request before preview preparation, even though the generated preview and reusable browser session support local data. - Local screenshot inputs skipped collision-free port resolution. - Project session revisions and restore-point IDs called `crypto.randomUUID()` through the ambient global. Environments without the Web Crypto global failed after otherwise successful mutations. - The production/session route-generation failure from #6161 is no longer reproducible on current `main`; the exact reported flow succeeds, so this PR does not add a speculative change for it. ## Technical choices - Resolve an available preview port for local generated screenshots using the existing screenshot port path. - Permit local and session sources through the same responsive generated-preview capture path. - Keep mixed preview targets and mixed browser configurations rejected. - Import `randomUUID` from `node:crypto` for session revisions and restore points. - Preserve explicit URL and `baseUrl` capture behavior. ## Impact A single `screenshot.responsive` call can prepare a local project once, reuse the configured browser, and capture desktop, tablet, and mobile viewports. Native MCP mutations can persist their session state without requiring the Web Crypto global. ## Checklist - [x] Add fail-first coverage for local responsive preview preparation and port allocation - [x] Add fail-first coverage for session persistence without the Web Crypto global - [x] Verify a real local CLI capture at 1440×900, 768×1024, and 390×844 - [x] Verify the production/session scenario from #6161 on current `main` - [x] Run the complete CLI test suite - [x] Run CLI typecheck and lint - [x] Review documentation impact: no user documentation changes are required because this restores the documented MCP behavior - [ ] Run agent evaluations (requires explicit approval) ## Verification - `pnpm --filter webstudio test` — 62 files, 983 tests passed - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint --deny-warnings packages/cli/src/commands/mcp-preview.ts packages/cli/src/commands/mcp-preview.test.ts packages/cli/src/project-session.ts packages/cli/src/project-session.test.ts` - `git diff --check` - Real local-source production capture returned HTTP 200 at all three viewports using one generated preview and the requested Chrome executable Closes #6156 Closes #6160 Ref #6161 |
||
|
|
baa48232fc |
fix: Keep Assets routes out of the static sitemap (#6158)
## Summary - keep Assets-backed dynamic path discovery and SSG prerendering unchanged - stop merging Assets-derived paths into `$resources.sitemap.xml` - keep eligible static pages in the generated sitemap - update the existing Assets prerender integration test to cover static sitemap behavior ## Why The CLI used one Assets query result for both route generation and sitemap indexing. Renderability and indexability are separate concerns, and automatic insertion could duplicate entries from a custom `/sitemap.xml` page. The Builder already exposes only static sitemap data, so generated production output should match it. ## Compatibility and release note Assets-backed dynamic routes are no longer added automatically to the static sitemap. Existing projects that relied on that behavior need to add those routes explicitly to a custom `/sitemap.xml` page with an Assets resource and Collection. This `fix:` PR is included in the repository's generated release notes under **Fixes**. ## Technical choices - Removed only the Assets-derived sitemap collection and merge. - Left `getAssetResourcePrerenderPaths()`, query evaluation, route generation, prerendering, and draft filtering unchanged. - Continued using `getStaticSiteMapXml()` as the sole source of generated sitemap entries. ## Verification - Regression demonstration before the implementation change: the updated targeted test failed because `/blog/hello-world` was present in `$resources.sitemap.xml.ts`. - After the implementation change, the targeted integration test passed and successfully built/prerendered `/blog/hello-world`. - `pnpm --filter webstudio test -- src/prebuild.test.ts` — 58 tests passed. - `pnpm --filter webstudio typecheck` — passed. - `pnpm exec oxfmt --check packages/cli/src/prebuild.ts packages/cli/src/prebuild.test.ts` — passed. - `pnpm exec oxlint --deny-warnings packages/cli/src/prebuild.ts packages/cli/src/prebuild.test.ts` — passed. - Agent evaluations were not run, per request. - Fixture regeneration was not needed because no fixture inputs or outputs changed. ## Todo - [x] Invert the existing Assets prerender sitemap assertion. - [x] Demonstrate that the regression test fails with the old behavior. - [x] Remove Assets-derived sitemap collection and merging. - [x] Confirm dynamic Assets routes still build and prerender. - [x] Confirm drafts stay excluded and eligible static pages stay included. - [x] Review documentation impact. - [x] Review the authoritative `docs/` content: the Content Engine guide already directs users to build and draft-filter a custom sitemap for dynamic Assets entries, and the XML Node guide documents combining it with the static Sitemap resource; no docs change is required. - [x] Document the compatibility change for generated release notes. Closes #6157 |
||
|
|
dbfb0a9849 |
fix: Preserve variable font styles (#6153)
## Summary Preserve font style metadata for variable fonts so upright and italic files from the same family produce distinct `@font-face` rules. Variable fonts with an `ital` or `slnt` axis are also registered for the matching CSS styles. ## Technical choices - Detect `normal`, `italic`, and `oblique` from the font binary, preferring OS/2 `fsSelection`, then `post.italicAngle`, then the existing subfamily parser. - Add `style` to variable-font metadata while defaulting legacy stored records to `normal`. - Keep update metadata partial and strict, but accept and persist `style` and `variationAxes` together so a `get-asset` result can be written back. - Group generated font faces by family, style, and browser-selectable variable descriptors so separate upright and italic files cannot overwrite each other. - Regenerate the runtime operation contracts from the updated schema. ## Checklist - [x] Add regressions using real upright and italic Inter variable-font binaries. - [x] Cover style detection, metadata compatibility, updates, and generated font-face selection. - [x] Verify the final stylesheet contains distinct upright and italic `@font-face` rules. - [x] Verify the public asset update contract accepts a complete variable-font metadata object. - [x] Review documentation impact and update the custom-font guide. - [x] Regenerate and verify runtime API contracts. ## Verification - `@webstudio-is/fonts`: 14 tests and typecheck passed. - `@webstudio-is/asset-uploader`: 198 tests and typecheck passed. - `@webstudio-is/sdk`: 514 tests and typecheck passed. - `@webstudio-is/project-build`: 2,094 tests and typecheck passed. - CLI: 980 tests and typecheck passed. - Builder typecheck passed. - `pnpm lint`, `pnpm check:package-boundaries`, `pnpm check:generated-api`, and `pnpm check:generated-docs` passed. - Regression tests were demonstrated failing against the previous behavior and passing with the fix. - Fixture builds regenerated successfully with no diff. Full remote fixture sync was attempted, but the deployed API rejected the source CLI contract as incompatible. - Agent evaluations were not run because they require separate explicit approval. Closes #6150 |
||
|
|
95c867697f |
feat: Make MCP verification proportional (#6155)
## Summary Make MCP verification proportional to the requested task and require an explicit preflight before a full production preview starts. This is the first vertical slice of the broader fast-workflow work in #6154. It fixes the current guidance and production-preview escalation behavior without claiming the universal search, cross-record update, or targeted route-evaluation APIs are complete. ## Technical choices - Classify `meta.guide` requests as: - small value or reference correction - focused page change - visual change - structural project change - project-wide migration - Give small corrections the explicit workflow `Focused search → atomic edit → targeted assertions` and omit the visual loop. - Include full-production-preview cost and faster-alternative metadata in goal guidance. - Change mutation follow-up guidance so focused assertions are sufficient for small corrections; reserve audit and screenshot work for structural, visual, or runtime-dependent outcomes. - Add `maxDurationMs`, `confirmSlow`, and `confirmationToken` to `preview.start`. - Return a non-running preflight for production mode with an honest 30–60 second estimate, purpose, faster alternative, and short-lived token. - Bind confirmation tokens to the normalized preview input and time budget so changed requests require a fresh preflight. ## Tradeoffs and compatibility - Iterative preview behavior is unchanged. - Production preview now requires one additional confirmed call. - The successful `preview.start` output still reports running state and mode; `url` is optional because a preflight has not started a server. - This PR does not yet add universal content search, match IDs, cross-kind atomic updates, or a targeted route renderer. Those remain in #6154. ## Todo - [x] Classify MCP task scope in `meta.guide` - [x] Recommend focused search → atomic edit → targeted assertions for small corrections - [x] Stop prescribing preview/screenshots for non-visual small corrections - [x] Add production-preview time-budget preflight - [x] Require an unchanged short-lived confirmation token before production preview - [x] Add fail-before/pass-after regression coverage - [x] Review documentation impact: generated MCP docs are unchanged; no authored `docs/` update is required for this internal contract increment - [ ] Add universal search results with stable match IDs and route/location context - [ ] Add one cross-kind atomic semantic update operation - [ ] Add lightweight route assertions and targeted route rendering - [ ] Apply the generic slow-operation contract to other broad audits, crawls, and multi-capture workflows - [ ] Add historical timing inputs to cost estimates ## Verification - `pnpm --filter @webstudio-is/project-build test -- --run src/mcp.test.ts` — 116 passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm exec oxlint --deny-warnings packages/project-build/src/mcp.ts packages/project-build/src/mcp.test.ts` - `pnpm docs:mcp:sync` — no generated diff - `pnpm docs:mcp:test` — 3 passed - `pnpm docs:mcp:typecheck` - Agent evaluations were not run because they require separate explicit approval. Ref #6154 |