mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-03 18:48:06 +09:00
0.286.0
6570
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b8a34e8268 | build: Release 04-08-2026 0.286.0 | ||
|
|
c44ef705cf |
perf: Speed up Builder resource loading (#6011)
## Problem Assets-backed Builder pages can take 6–7 seconds to become usable even when their Assets resources only request metadata. On the production-derived Blog project, a single Assets query measured 8,703 ms and an immediate repeat measured 8,110 ms. Four sibling Assets resources repeated the same authorization, development-build load/parse, compilation, canonical-asset preparation, runtime metadata load, and document work. ## Architecture The loader now treats remote resources holistically while preserving provider boundaries: - The client scheduler is resource-provider neutral. It versions logical requests, frees capacity when obsolete requests are replaced, ignores stale results, and aborts physical batches only when every member is obsolete. - Ordinary Assets requests in one server resource-loader call use a deferred Assets provider and execute as one repository batch. Independent HTTP, GraphQL, and other resources start immediately instead of waiting for Assets preparation. - Arbitrary remote responses are **not** coalesced or persistently cached. Their auth headers, cookies, upstream freshness, and `Vary` semantics remain isolated. - The Assets provider authorizes and creates its API context once per batch, then loads only `props`, `dataSources`, and `resources` from the development Build. - Queries covered by the saved Build compilation plan reuse that exact plan/artifact, preserving published byte limits, truncation, and pinned-revision behavior. Uncovered unpinned queries use a deterministic literal union and safely fall back to their existing individual path if shared preparation cannot preserve behavior. - Request-scoped document loading uses npm's byte-bounded `lru-cache` so sibling queries do not reread the same referenced author/content files. - Sibling dynamic queries with the same filter, sort, output, and content shape stitch into one document-graph resolution while keeping filter values, pagination windows, results, and failures independent. Aggregate document/byte-limit failures fall back to isolated execution. - Provider-neutral batching lives in the SDK runtime, and project asset-query preview orchestration lives in the shared project package so Builder and MCP paths can reuse the same behavior. - Cancellation flows from the client batch through the SDK/server/build/query path, with checkpoints between expensive phases. - Runtime asset metadata remains conservatively artifact-wide because URL/size filters, structured references, markdown hydration, materialized rows, and saved plans have different reachability rules. To make 1,000-asset artifacts safe, PostgREST `.in(...)` lookups are deduplicated and split into 100-ID chunks with bounded concurrency. ## Implementation checklist - [x] Trace the production Blog resource path and identify repeated work - [x] Copy the production Blog project into an ignored disposable local project - [x] Record production and local baselines - [x] Add provider-neutral client scheduling, stale-result protection, and cancellation - [x] Batch ordinary Assets queries without coupling or caching HTTP/GraphQL responses - [x] Load only Build fields required to create the saved content compilation plan - [x] Preserve saved-plan, truncation, fallback, diagnostics, and revision semantics - [x] Share Assets artifacts, runtime metadata, and revision-keyed document reads per request - [x] Stitch compatible query shapes into one graph resolution with isolated fallback - [x] Extract reusable SDK batching and project preview orchestration for MCP/runtime consumers - [x] Bound large runtime asset metadata lookups for the 1,000-asset project limit - [x] Add regression coverage and demonstrate new tests failing before their fixes - [x] Run focused and broad tests, type checks, lint, format, package-boundary, and diff checks - [x] Review documentation impact; no authoritative `docs/` content changes are required - [x] Regenerate and verify the affected asset-query runtime fixture; no production data is changed - [x] Address all actionable PR review comments - [x] Rerun the final parity-preserving implementation against the copied Blog project ## Measurements Production trace before the change: - Updates Assets query: 8,703 ms - Immediate identical repeat: 8,110 ms - Query artifact: 9,344 bytes / 7 documents - Saved source database: 42,086 bytes / 28 documents Copied-project local baseline: - Builder navigation until resource loading: 5,111 ms - Exact four-resource batches: 1,448 / 797 / 1,377 / 774 / 3,018 ms During implementation, before the final saved-plan parity tightening: - Exact four-resource batch: 174 ms first run, then 51–80 ms - Actual Builder resource-loader requests: 234–246 ms Final parity-preserving copied-project rerun: - Preflight: 10 ms - Exact four-resource batch: 435 ms cold, then 119 / 97 / 90 / 79 ms warm - Every response returned HTTP 200 with the same 16,884-byte payload The final cold batch is 70% faster than the best copied-project cold baseline, and the fastest warm batch is 90% faster than the best warm baseline. The production trace remains the authoritative production baseline; these before/after comparisons use the same disposable local project and captured request payload. ## Verification Passed: - Full package suites: Builder (212 files / 2,496 tests), asset-uploader (22 / 193), content-engine (40 / 274), project (7 / 84), SDK (29 / 508), and project-build (82 / 2,070) - Final focused regressions: Builder preview/API/resource integration (3 files / 42 tests), SDK resource loader (23 tests), and document-graph resolution (6 tests) - Builder, asset-uploader, content-engine, project, SDK, and project-build type checks - Fixture regeneration is deterministic; the generated vendor exactly matches the source runtime bundle - Fixture typecheck and production build - Changed-file Oxfmt, repository Oxlint, and package-boundary checks - `git diff --check` - `git diff --name-only HEAD --exit-code` New behavioral tests were demonstrated to fail before implementation and pass afterward, including Assets batch coordination, saved-plan wiring, truncation and pinned revisions, shared document reads, cancellation checkpoints, stale/replaced client requests, and large PostgREST ID filters. Agent evaluations were not run because they require separate explicit approval. ## Compatibility and remaining work The public resource result/error shape and on-demand diagnostics contract stay compatible. Generic HTTP/GraphQL caching semantics are unchanged. Compilation already in progress is not force-cancelled because safely interrupting shared compilation requires ownership/reference tracking; cancellation prevents later phases from starting. Closes #6003 |
||
|
|
6385e290c6 |
feat: Add syntax highlighting to Code Text (#6007)
Closes #4119 Supersedes #5999 after GitHub closed it during the head-branch rename. ## Approach Code Text uses one optional public highlighting boundary: - `@webstudio-is/sdk-components-react/code-text` → `src/code-text.tsx` The ordinary `components` entry remains Shiki-free. Canvas loading, metadata options, theme variables, and the plain semantic `<code>` component remain private implementation details. **Code** uses the code editor. **Language** and **Theme** use normal bindable selects. Fixed selections generate direct imports for only the per-page language/theme union; plaintext imports no grammar. Bound selections generate Shiki's lazy language/theme registries. SSR and client rendering share the same factory. Missing bound assets suspend the first render while SSR resolves the selected modules. SSG now waits for Suspense before serializing HTML. During hydration the completed server markup stays in place while the browser fetches only the selected language and theme. Later client-side binding changes load only the new selections and keep the same `<code>` node and focus. Highlighted output preserves the semantic root, ref, author classes/styles, whitespace, escaped source, and legacy children/native `lang` behavior. Shiki's implicit tab stop is disabled. A color-only transformer strips theme typography so asynchronous highlighting cannot change text geometry. ## Bundle impact Measured from same-commit production React Router + Cloudflare builds containing one JavaScript / GitHub Light Code Text instance. Sizes are the sum of emitted JavaScript files; gzip is the sum of each file compressed independently. | Worker output | Files | Raw | Sum gzip | | --- | ---: | ---: | ---: | | Fixed selections | 3 | 1,341,851 B | 288,342 B | | Bound selections | 310 | 10,372,112 B | 1,872,273 B | | Increase | +307 | +9,030,261 B (8.61 MiB) | +1,583,931 B (1.51 MiB) | The bound browser build also emits the catalog as lazy chunks: +9,012,594 raw bytes / +1,578,779 sum-gzip bytes across the complete deployed output. Those chunks are not all delivered on page load. The production SSG regression verifies 100+ catalog chunks are emitted while the HTML directly module-preloads only one shared runtime chunk; the browser fetches the runtime-selected language/theme modules on demand. ## Tradeoffs and compatibility - Instances with both highlighting properties unset keep the legacy plain renderer. - Static highlighting still requires both **Language** and **Theme**. - Binding either selection includes that catalog in deploy output because its runtime value is not known at publish time. - The syntax-highlighting property is `language`; legacy native HTML `lang` remains preserved. - Invalid or unavailable runtime selections render as plain code. - Fixed selections retain the smallest publish output; bound selections trade deploy/worker size for runtime flexibility. ## Todo - [x] Restore the specialized Code Text component and semantic plain fallback - [x] Use a code editor for Code and bindable selects for Language and Theme - [x] Persist JavaScript / GitHub Light template defaults - [x] Collapse highlighting to one public `./code-text` entry - [x] Keep canvas loaders and option/theme helpers private - [x] Generate direct imports for fixed selections and omit plaintext grammar - [x] Generate lazy catalogs when Language or Theme is bound - [x] Preserve highlighted SSR markup during hydration without node/focus movement - [x] Support Suspense-aware highlighted SSG output - [x] Preserve escaping, accessibility, legacy children, and native `lang` - [x] Measure fixed versus bound Cloudflare worker output - [x] Deep-review correctness, DRYness, package surface, and obsolete binding infrastructure - [x] Review documentation impact and update Code Text documentation - [x] Run focused tests, typechecks, production builds, formatting, and staged diff review - [ ] Fixture pipeline — blocked during sync because the current API rejects this local CLI version as incompatible; no fixture output changed ## Verification - [x] New/changed regressions were demonstrated failing without their behavior and passing after restoration - [x] SDK Code Text metadata, rendering, hydration, and bundle tests: 17 passed - [x] Component registry tests: 3 passed - [x] CLI asset collection and full prebuild suite: 59 passed - [x] SDK components, component registry, SDK, and CLI typechecks - [x] SDK components declaration and production builds - [x] Component registry production build - [x] Production Vite + Vike prerender emits highlighted bound SSG HTML with one doctype - [x] Dynamic catalog chunks remain outside the SSG page's direct preload set - [x] Documentation reviewed and updated - [x] Formatting and staged diff checks |
||
|
|
6b82b413b9 |
fix: Preserve optional MCP input types (#6010)
Closes #6009 ## Summary Preserve machine-readable scalar constraints for every optional MCP input property advertised through `tools/list`. MCP clients now receive the declared string, integer, and boolean types, along with bounds, enums, defaults, and related scalar constraints, instead of empty property schemas. ## Root cause The compact SDK handshake intentionally retained full scalar schemas for required fields and destructive-safety controls, but replaced ordinary optional property schemas with `{}`. Clients therefore lacked the type information needed to serialize values such as `limit`, `verbose`, and `maxDepth` correctly. ## Implementation - Reuse the existing compact scalar-schema projection for every advertised optional property. - Keep descriptions and large structured contracts out of the initial handshake. - Preserve the existing focused-discovery behavior for complete schemas. - Add protocol-level regression coverage through the official MCP SDK for string, integer, and boolean optional inputs. ## Todo - [x] Preserve optional MCP property types and scalar constraints. - [x] Add regression coverage for representative string, integer, and boolean inputs. - [x] Demonstrate the regression test fails before the fix and passes afterward. - [x] Run project-build and CLI MCP/schema tests. - [x] Run relevant typechecks, lint, formatting, and package-boundary validation. - [x] Review fixture impact; no fixture inputs or generated fixture bundles are affected. - [x] Review documentation impact; existing documentation describes the intended typed schema behavior, so no documentation update is required. - [ ] Run agent evaluations after separate explicit approval. ## Verification - `@webstudio-is/project-build`: 2,077 tests passed. - CLI MCP/schema tests: 51 passed. - Project-build and CLI typechecks passed. - Repository lint passed. - Changed-file formatting passed. - Package-boundary validation passed. - `git diff --check` passed. - The protocol regression assertion failed against the previous implementation and passed after the fix. Agent evaluations were not run because repository policy requires separate explicit approval. |
||
|
|
08e1e19b3f |
fix: expose existing text bindings in mixed content (#6008)
Closes #5992 ## Summary Expose the existing **Text content** binding control when a directly text-capable selected instance contains expressions alongside other content. The supplied reading-time span keeps its existing child sequence: - static prefix text - bound expression No data migration or new Settings editor is introduced. Normalization happens only when the user explicitly resets a binding. Expression-bearing nodes are excluded from canvas text editing because the canvas editor cannot represent bindings safely. Literal descendants in mixed trees remain canvas-editable, while bindings remain editable through Settings. ## Implementation - Reuse the existing scalar Text content and binding UI. - Target expression children with indexed `instances.updateText` mutations, preserving instance boundaries and unrelated siblings. - Fail closed when the selected instance is missing or no longer has a safe text target. - Evaluate expressions through the binding control's existing live scope. - Centralize text-content target classification in project-build for reuse by the engine and Builder. - Reset every expression atomically through the engine's `instances.setTextContent` operation, validate the complete replacement set, and coalesce adjacent text nodes without crossing nested-instance boundaries. - Centralize expression-free canvas text-editor targeting in the project-build lookup module. - Route double-click, Enter, post-insert editing, cursor generation, and keyboard navigation through the shared lookup rules. - Exclude single-expression and mixed/nested expression targets from the canvas editor in every mode. - Preserve canvas editing for literal descendants inside otherwise mixed content. - Share canvas fixtures and simplify binding-removal capability to an optional handler. ## Verification - [x] Settings exposes and edits mixed text/expression targets without replacing siblings. - [x] Reset binding converts every expression on the instance and normalizes adjacent text. - [x] Missing, unsupported, stale, and incomplete replacement sets fail closed. - [x] Double-click and Enter do not open bound nodes in the canvas editor. - [x] Literal descendants within mixed trees remain canvas-editable. - [x] Complete Builder suite passes (2,497 tests). - [x] Complete project-build suite passes (2,070 tests). - [x] New targeted Builder and project-build regression tests pass (175 tests). - [x] Builder and project-build typechecks pass. - [x] Repository lint passes. - [x] Package-boundary validation passes. - [x] Generated runtime operation contracts are updated from source. - [x] Fixture inputs and outputs are unaffected. - [x] Documentation impact reviewed: no documentation update is needed. - [ ] Interactive browser smoke test was unavailable because the in-app browser failed to initialize. - [ ] Agent evaluations were not run because they require separate approval. ## CI note The previous head's Main workflow failed while pulling the E2E database image with Docker Hub `toomanyrequests: Rate exceeded`. Lost Pixel failed separately with a certificate error. Both are external infrastructure failures; branch formatting, lint, package boundaries, generated contracts/docs, tests, and typechecks were successful in that run. Supersedes #5993, which GitHub closed automatically when its head branch was renamed. |
||
|
|
17947e47fa |
fix: Constrain the asset settings popover width (#6002)
## Summary - Set the asset settings popover to a fixed 250px width using the existing `css` prop. ## Root cause The popover used a minimum width while its shared content style allowed intrinsic `max-content` sizing. Long descriptions could therefore expand the popover beyond the intended layout. ## Impact Asset settings now stay consistently sized, and long descriptions remain contained within the popover. ## Todo - [x] Constrain the asset settings popover width. - [x] Keep styling on the existing `css` prop. - [x] Avoid a constant-only regression test, in line with the existing agent testing guidance. - [x] Confirm fixture inputs and outputs are unaffected. - [x] Review documentation impact; no user-facing documentation changes are needed. - [x] Run targeted tests, formatting, linting, and Builder typecheck. ## Verification - `pnpm --filter=@webstudio-is/builder test -- asset-settings.test.tsx` - `pnpm exec oxfmt --check apps/builder/app/builder/shared/asset-manager/asset-settings.tsx` - `pnpm exec oxlint --deny-warnings apps/builder/app/builder/shared/asset-manager/asset-settings.tsx` - `pnpm --filter=@webstudio-is/builder typecheck` Closes #6001 |
||
|
|
1ca01e96a3 |
docs: Guide MCP agents to build dynamic JSON-LD (#5998)
## Summary Clarify how MCP agents should author JSON-LD without serializing dynamic values prematurely. Static structured data remains a validated compact JSON string, while runtime-backed structured data uses an expression that evaluates directly to an object or array. The focused guide now provides machine-readable input recipes for both paths. ## Implementation - [x] Update the focused `components.get` JSON-LD guidance. - [x] Update the JSON-LD `meta.guide` workflow and include `bind-props`. - [x] Add structured `fixedCodeUpdate` and `dynamicCodeBinding` recipes. - [x] Document that expression source is stored as text while its evaluated value must be an object or array. - [x] Warn agents not to call `JSON.stringify` or assemble JSON with string concatenation. - [x] Update CLI use-case documentation and generated docs. - [x] Parse the fixed JSON and dynamic expression AST in regression coverage, including the `post.title` runtime binding. - [x] Demonstrate that the semantic regression test fails when the structured recipe is absent. ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,066 tests passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter webstudio typecheck` - Focused MCP semantic regression tests - `pnpm oxfmt --check ...` - `pnpm oxlint packages/project-build/src/mcp.ts packages/project-build/src/mcp.test.ts` - `pnpm check:generated-docs` - Fixtures not run: documentation and MCP guidance do not affect fixture inputs or generated fixture bundles. - Agent evaluations not run: explicit approval was not provided. Closes #5997 |
||
|
|
74d88a3fb2 |
fix: Resolve structured Asset paths in queries (#5995)
## Summary Resolve portable relative Asset paths stored in Markdown frontmatter and structured JSON properties to canonical runtime Asset URLs inside the content engine. The authored source remains unchanged. Asset resource consumers now receive canonical URLs without Image, CSS, JSON-LD, or other binding-specific transformations. ## Root cause Markdown body links already recorded relative Asset references for runtime rewriting, but structured values bypassed that pipeline. Browsers therefore resolved values such as `./assets/hero.png` against the page URL instead of the source document folder. ## Implementation - Recursively discover unique structured Asset references using the existing canonical path resolver and the platform URL parser. - Store optional `assetValueReferences` in content artifacts and runtime projections. - Include referenced Assets in publication/runtime dependency collection and validation. - Resolve values before filtering, sorting, and projection in normal and document-graph queries. - Rewrite materialized query items at runtime without mutating canonical documents or compiled rows. - Merge authored query parameters and fragments with canonical Asset URLs. - Keep queries whose filter/sort semantics depend on runtime Asset URLs out of compile-time materialization. - Add an explicit content-compilation cache generation so pre-feature artifacts are recompiled. - Refresh fixture bundle versions and the generated asset-query runtime. - Document relative references in Markdown frontmatter and JSON content. ## Checklist - [x] Add structured reference discovery for nested objects and arrays - [x] Support Markdown frontmatter and JSON document properties - [x] Preserve URL query strings and fragments - [x] Thread references through build/runtime artifacts and publication dependencies - [x] Resolve normal, materialized, and document-graph query results - [x] Apply resolved values to filtering, sorting, and projection - [x] Preserve compatibility with artifacts that omit the optional field - [x] Add fail/pass regression coverage - [x] Run package tests, typechecks, lint, and generated API checks - [x] Regenerate and build all fixtures - [x] Review documentation impact and update the Assets guide ## Verification - `pnpm --filter @webstudio-is/content-engine test` — 269 passed - `pnpm --filter @webstudio-is/content-engine typecheck` — passed - `pnpm --filter @webstudio-is/asset-uploader test` — 184 passed - `pnpm --filter @webstudio-is/asset-uploader typecheck` — passed - `pnpm --filter @webstudio-is/protocol test` — 88 passed - `pnpm lint` — passed - `pnpm check:generated-api` — passed; generated files clean - `pnpm --filter webstudio build:content-runtime && pnpm -r fixtures:build` — passed for all fixtures - Assets documentation — internal links resolve and `git diff --check` passes - Regression proof: neutralizing structured discovery/replacement caused 8 expected failures across source compilation, standard queries, document-graph queries, and materialized queries; restoring the implementation passed all tests. - `pnpm evaluations` — not run because explicit approval is required. ## Compatibility The artifact field is optional, so older artifacts continue to parse and execute. Existing absolute, protocol-relative, root-relative, fragment-only, query-only, external-scheme, malformed, missing, and ambiguous values remain unchanged. |
||
|
|
1f4095cf9a |
fix: Improve generated MCP documentation (#5991)
## Summary
- render the generated MCP version as visible body content immediately
below the page heading
- keep the GitBook navigation label stable as `MCP`
- stamp only the CLI version placeholder during release publication,
leaving Markdown content owned by the template
- remove empty `{}` blocks from the rendered MCP argument examples while
preserving meaningful examples and complete structured JSON data
## Root cause
GitBook uses the `SUMMARY.md` link label as the published page heading
and suppresses the Markdown H1 from the document body. The generated
version was therefore present in source but absent from the rendered
page.
The release workflow also coupled version stamping to the complete
rendered Markdown line. It now replaces and verifies only the standard
`0.0.0-webstudio-version` placeholder.
## Verification
- live page structure inspected: published H1 is `MCP`
- MCP manual regression test demonstrated failing before empty argument
blocks were filtered, then passing after the fix
- release placeholder stamping simulated against the generated page
- `pnpm --filter webstudio exec vitest run src/commands/man.test.ts`
- `pnpm --filter @webstudio-is/project-build typecheck`
- `pnpm --filter webstudio typecheck`
- `pnpm check:generated-docs`
- `pnpm lint`
- `pnpm oxfmt --check packages/project-build/src/mcp.ts
packages/cli/src/commands/man.ts packages/cli/src/commands/man.test.ts`
- `git diff --check`
Fixture inputs and outputs are unaffected.
## Todo
- [x] Generate the release version as visible GitBook body content.
- [x] Decouple release stamping from the rendered Markdown content.
- [x] Remove empty MCP argument example blocks.
- [x] Validate generated output and regression coverage.
- [ ] Merge this pull request.
- [ ] Publish the latest released revision to the `docs` branch.
- [ ] Verify the version on the live GitBook page.
Ref #5986
|
||
|
|
e6a29b5d36 |
fix: Show released CLI version in MCP docs (#5990)
## Summary - make the MCP page generator render the CLI package version directly in the page title - publish `Webstudio MCP v<release>` from the exact generated page in each successful release - merge each successful release tag into the publication-only `docs` branch - serialize publication and ignore reruns or older release tags already contained in `docs` ## Root cause The first publication design advanced `docs` to the release commit without putting the CLI package version into the generated page. The repository uses `0.0.0-webstudio-version` until release time, so the release workflow now replaces that existing version placeholder with the successful tag version before publishing. ## Todo - [x] Generate the CLI version in the MCP page title. - [x] Publish the generated page from the exact release revision. - [x] Make publication idempotent and prevent version downgrades. - [x] Validate generation, formatting, linting, and release-branch behavior. - [ ] Merge this pull request. - [ ] Publish `0.285.0` as the initial version on the existing `docs` branch. ## Verification - `pnpm docs:mcp:test` - `pnpm docs:mcp:typecheck` - `pnpm check:generated-docs` - `pnpm lint` - `pnpm oxfmt --check` - `git diff --check` - isolated Git simulation for release merge, exact generated-page selection, version replacement, and rerun detection - regression tests demonstrated failing without version rendering and validation, then passing after restoration Ref #59860.285.1 |
||
|
|
99371187dc |
docs: Move product documentation into Builder (#5987)
## Summary - move the complete GitBook documentation tree and assets into Builder under `/docs` - generate the exhaustive MCP page from the local CLI source in the same change - publish GitBook from a release-gated `docs` branch containing the exact successfully released revision - run MCP documentation tests, typechecking, and stale-output checks with the existing generated-docs check - remove links to the Community Discussions repository ## Technical choices - Import the current documentation as a linear snapshot so the branch satisfies Builder's required-linear-history protection. - Keep the Markdown wrapper separate from the TypeScript generator at `scripts/docs/mcp-page.md`. - Generate through `packages/cli/local.js` so CLI guidance and its documentation are reviewed together. - Let `check:generated-docs` reject CLI changes that leave the committed MCP page stale. - After both GitHub release creation and package publication succeed, fast-forward the read-only `docs` branch to the immutable release tag commit. A divergent update fails instead of publishing a different revision. - Configure GitBook to publish `/docs` from the `docs` branch, not directly from `main`. - Exclude `/docs` from the repository-wide `oxfmt` scan so imported GitBook Markdown retains its established formatting; generator tests and stale-output checks still validate the MCP page. - Exclude `transcripts/` and GitHub Discussions from the migration. ## Todo - [x] Import documentation, navigation, includes, and assets under `/docs`. - [x] Generate the MCP page from the local CLI source. - [x] Move MCP generation and validation into Builder. - [x] Require MCP documentation updates alongside CLI changes. - [x] Publish released revisions through a read-only `docs` branch. - [x] Remove Community repository links from Builder and the migrated docs. - [x] Preserve and verify a final Community Git bundle locally. - [ ] Merge this pull request. - [ ] Let the next successful release create or advance the `docs` branch. - [ ] Repoint GitBook Git Sync to `webstudio-is/webstudio`, branch `docs`, root directory `/docs`. - [ ] Verify `docs.webstudio.is`, navigation, assets, anchors, and the MCP page in production. - [ ] Delete `webstudio-is/webstudio-community`. ## Verification - `pnpm check:generated-docs` - `pnpm lint` - `pnpm oxfmt --check` - `git diff --check origin/main...HEAD` - generator regression test demonstrated failing when the GitBook wrapper behavior was removed, then passing after restoration - no fixture inputs or outputs are affected ## Known limitation All documentation merged after the previous release waits for the next successful release before GitBook publishes it. This deliberately keeps the public MCP reference aligned with an installable CLI revision. Ref #5986 |
||
|
|
cf0e76f96a |
fix: Validate authored fragments against HTML content models (#5988)
## Summary Prevent authored fragment insertion from creating invalid HTML structures while preserving the Builder's warning-only behavior for legacy clipboard content. Also show an explicit loading state while Assets resource diagnostics are fetched lazily, instead of briefly reporting that no diagnostics are available. Allow established text assets to be edited without their preserved creation timestamp being mistaken for an expired upload reservation. ## Root cause The shared insert-fragment runtime mutation did not validate the final HTML content model. Builder copy and paste uses the same mutation for legacy project content. The compatibility path must tolerate only violations already present in the copied fragment while still rejecting new violations caused by its destination. The diagnostics inspector had no pending state, and an unkeyed pending state could be cleared by an older request after the inspected resource changed. Asset revisions preserve the original file's `createdAt` value, but upload finalization used `createdAt` to enforce the 30-minute upload-ticket lifetime. ## Implementation - [x] Enforce HTML content-model validation at the shared fragment-insertion mutation boundary. - [x] Centralize fragment placement warning collection with the existing matcher logic. - [x] Keep the legacy compatibility switch out of the public runtime/MCP contract. - [x] Pass compatibility through trusted Builder runtime context only. - [x] Ignore only violations already present in legacy clipboard content and reject new destination violations. - [x] Preserve warning-only behavior across the shared Builder paste helper and instance-copy path. - [x] Key diagnostics loading state to the active resource request. - [x] Validate upload-ticket freshness with `updatedAt` while preserving logical asset `createdAt`. - [x] Regenerate the runtime operation contract. - [x] Add regression coverage for strict insertion, legacy compatibility, destination validation, paste context propagation, diagnostics request races, and established text assets. ## Impact MCP and other public authored-fragment callers remain strictly validated and cannot opt out. Legacy Builder clipboard content remains pasteable with warnings, but compatibility cannot introduce a new violation at the selected destination. Assets diagnostics retain their loading state when an older request settles, and established text assets can be updated after 30 minutes without changing their displayed creation date. ## Verification - [x] Project-build targeted tests: 80 passed. - [x] Builder targeted tests: 86 passed. - [x] Asset-uploader tests: 184 passed. - [x] Builder typecheck passed. - [x] Project-build typecheck passed. - [x] Asset-uploader typecheck passed. - [x] Generated runtime operation contracts are current. - [x] New regression tests were demonstrated failing without their fixes and passing after restoration. - [x] Fresh GitHub Main workflow passed, including both test/typecheck matrices and all six Builder E2E shards. Shard 3 was rerun successfully after Docker Hub rate-limited its initial database-image pull. ## External CI status - Lost Pixel failed on an external TLS certificate handshake after Storybook built successfully. - The staging deployment workflow failed before executing job steps, independently of code checks. |
||
|
|
5cefbc0320 |
perf: Speed up Builder resource loading (#5980)
## Summary Remove avoidable latency from Builder resource loading and make Assets resources use the content database efficiently. ## Why Builder currently applies a one-second debounce to every uncached resource request. Assets queries also perform server-side preparation work that should be reused or deferred, making pagination and route changes noticeably slower than expected. ## Implementation plan - [x] Dispatch the complete set of currently computable page resources without the one-second debounce. - [x] Preserve batching, deduplication, exact-request caching, invalidation, and bounded queue draining. - [x] Add regression tests for immediate dispatch, batching, deduplication, invalidation, and queue draining. - [x] Cache compiled Assets content databases by the relevant project/build and asset revision. - [x] Run pagination, filtering, sorting, and metadata selection against the cached database without rebuilding it for each request. - [x] Fetch only referenced document content that is required by the query and keep graph reads parallel. - [x] Avoid generating and returning full diagnostics artifacts for ordinary canvas resource loads; load detailed diagnostics on demand. - [x] Preserve distinct loading and confirmed-empty states for article and author resources. - [x] Add coverage for paginated overview and article navigation behavior. - [x] Deep-review the complete change and remove redundant plan construction, duplicated JSON comparison, path-based diagnostics inference, and synthetic canvas diagnostics. - [x] Make resource and diagnostics invalidation race-safe, including invalidation during in-flight requests. - [x] Run formatting, tests, lint, type checking, package-boundary checks, and affected fixtures. ## Verification - `pnpm oxfmt --check` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm --filter @webstudio-is/content-engine test` (262 tests) - `pnpm --filter @webstudio-is/asset-uploader test` (184 tests) - `pnpm --filter @webstudio-is/builder test` (2,483 tests) - Typechecks for Content Engine, Project Build, Asset Uploader, and Builder - `pnpm fixtures` (passed; no fixture diff) The new invalidation regression tests were verified to fail against the previous behavior and pass with the fix. Agent evaluations were not run because they require separate approval. ## Known limitations None identified. |
||
|
|
e855a1e7cf |
fix: Skip unenumerated dynamic SSG pages (#5982)
## Outcome Restore SSG downloads for projects that contain dynamic pages without enumerable Assets query paths. Static pages continue to export, while unsupported dynamic routes are omitted as they were before Assets-backed SSG prerendering was introduced. Closes #5981 ## Root cause Assets-backed dynamic prerendering changed the SSG framework from skipping every dynamic route to throwing whenever the computed prerender path list was empty. That empty list also represents existing dynamic routes without a configured Assets query, so otherwise valid static downloads began failing during scaffolding. ## Implementation - Return no framework files for dynamic pages whose prerender path list is empty. - Preserve generated Vike routes for Assets-backed pages that enumerate at least one path. - Preserve the existing prebuild validation errors for Assets queries that bind parameters incompletely or cannot enumerate every query branch. - Add an integration regression test covering a static home page alongside `/blog/:slug` with no Assets query. ## Todo - [x] Reproduce the production failure in a regression test - [x] Restore omission of unenumerated dynamic routes - [x] Verify Assets-backed dynamic SSG behavior remains passing - [x] Run focused lint, formatting, typecheck, and integration tests ## Verification - [x] New regression test demonstrated failing before the implementation change and passing afterward - [x] `pnpm --filter webstudio test -- src/prebuild.test.ts` — 49 passed - [x] `pnpm --filter webstudio typecheck` - [x] `pnpm exec oxfmt --check packages/cli/src/framework-vike-ssg.ts packages/cli/src/prebuild.test.ts` - [x] `pnpm exec oxlint --deny-warnings packages/cli/src/framework-vike-ssg.ts packages/cli/src/prebuild.test.ts` - [x] `git diff --check` ## Notes - No fixture inputs or generated fixture outputs are affected. - The agent evaluation suite was not run because repository policy requires separate explicit approval. - Production failure: https://github.com/webstudio-is/webstudio-saas/actions/runs/30769678212/job/91554478283 |
||
|
|
92084aeea3 |
fix: Remove MCP workflow friction (#5974)
## Summary - Make MCP discoverable from the CLI README and expose direct MCP tool calls as restart-free CLI subcommands. - Preserve required discriminator fields in compact MCP SDK schemas and surface the `set-text-content` contract. - Return instance props by default from `inspect-instance` and improve the `list-instances` input hint. - Add a Builder context-menu **Move** submenu as an accessible alternative to drag-and-drop sibling reordering. Companion generated documentation: https://github.com/webstudio-is/webstudio-community/pull/274 ## Technical choices and compatibility - Compact SDK schemas retain required fields only inside root composition branches, avoiding broad schema expansion. - `inspect-instance` now defaults to `props` only; larger styles, bindings, sources, children, and ancestors remain opt-in. - Existing move commands and shortcuts back the new menu, so command behavior stays centralized. - No migrations, fixture inputs, generated fixture bundles, or generated API contracts are affected. ## Todo - [x] Add direct CLI MCP discovery and restart guidance. - [x] Preserve discriminated-union requirements for SDK clients. - [x] Improve instance inspection and input diagnostics. - [x] Add accessible menu-based instance movement. - [x] Add regression coverage and verify fail/pass behavior. - [x] Run targeted tests, typechecks, lint, package-boundary, and generated-doc checks. - [ ] Deferred: run `pnpm evaluations` after separate explicit approval, as required by repository policy. ## Verification - `@webstudio-is/project-build`: 172 targeted tests passed. - `@webstudio-is/protocol`: 8 targeted tests passed; typecheck passed. - `@webstudio-is/builder`: 8 targeted tests passed; typecheck passed. - CLI and project-build typechecks passed. - Root lint, package-boundary check, generated-doc check, and diff checks passed. - New and modified regression tests were demonstrated failing before their fixes and passing afterward. ## Known limitations Synthetic drag-and-drop behavior is unchanged. The new menu and existing keyboard shortcuts provide the automatable and accessible reordering path. Agent evaluations were not run because explicit approval was not provided. |
||
|
|
aefe532a73 |
fix: Preserve instance deep links on Builder reload (#5977)
## Summary Preserve exact Builder instance selections during initial load, authentication, and hard reload, including shared content rendered through multiple Slot instances. ## Implementation - [x] Store the complete selector in one comma-separated `instance` URL parameter. - [x] Reuse `canResolveInstanceSelector` to validate every selector path before restoring it. - [x] Resolve the selected page from the selector root. - [x] Wait for the authoritative Builder data-loaded state before applying initial URL state. - [x] Keep selection-to-URL synchronization paused until initial URL state is resolved. - [x] Let the existing auth loader derive `returnTo` directly from Builder requests. - [x] Update generated Builder links, including pre-publish audit links, to use full selectors. - [x] Add regression coverage for incomplete sync data and duplicate shared-slot child IDs. ## Verification - [x] A fresh browser session authenticates and opens a direct selector deep link. - [x] Hard reload retains the exact selector URL and selection. - [x] Clicking the first shared child creates an `instance` URL for the first Slot path; reload restores the first occurrence. - [x] Clicking the second shared child creates a distinct `instance` URL for the second Slot path; reload restores the second occurrence. - [x] Focused Vitest suite: 8 tests passed. - [x] Builder TypeScript typecheck. - [x] Focused oxlint. - [x] Focused oxfmt check. - [x] `git diff --check`. ## Compatibility and limitations No schema, migration, or public API changes. This change uses one canonical full-selector URL format; ID-only deep links are not retained as a compatibility path. |
||
|
|
9fe63c7501 |
fix: Submit webhook forms only once (#5979)
## Summary Webhook Form action resources were being persisted both as prop-bound actions and render-time data sources. Generated sites could therefore execute the POST while rendering and again when the visitor submitted the form. This change keeps prop-bound resources action-only and hardens generation for existing builds that still contain a stale data-source binding. Ref #5806 ## Implementation - Keep `resources.upsertProp` resources out of render-time data and remove stale exposure when an action is edited. - Make the mutation's `dataSourceId` result optional and regenerate the runtime contract. - Exclude action-bound resources from the generated data-resource map, preserving them only in the action map. - Extend the Webhook Form E2E with a local request-counting endpoint. ## Todo - [x] Prevent new Form actions from creating render-time data sources. - [x] Protect existing persisted builds from loading action resources during rendering. - [x] Regenerate the runtime operation contract. - [x] Add mutation, generation, Builder-store, and generated-site regression coverage. - [x] Verify zero calls on page load and one populated POST on submit. ## Verification - [x] Focused Builder E2E: `Webhook Form action submits once and persists after reload` - [x] Project Build test suite: 2,062 tests - [x] SDK test suite: 505 tests - [x] Builder resource mutation test file: 25 tests - [x] SDK, Project Build, and Builder typechecks - [x] Changed-file lint, formatting, and diff checks - [x] Generated API cleanliness check - [ ] Agent evaluation suite (not run; requires explicit approval) ## Notes No fixture inputs or generated fixture bundles are affected. |
||
|
|
22642fc90b |
fix: Show publish feedback immediately (#5978)
## Summary Move the optimistic publishing state update ahead of the asynchronous content-database diagnostics request. The publish button now shows its pending animation immediately after a valid click instead of waiting for that network round trip. ## Root cause The content-database publish diagnostics were added before the function that set `isPublishing`. Any latency in that request left the publish button looking idle. ## Implementation - Start the optimistic publishing state at the beginning of the publish transition. - Preserve the existing pre-publish audit, content-database warning, publish request, polling, and error behavior. ## Todo - [x] Trace the publish click and pending-state sequence. - [x] Move pending feedback ahead of asynchronous diagnostics. - [x] Run targeted lint and Builder typecheck. - [x] Run the complete Builder test suite. ## Verification - `pnpm exec oxlint --deny-warnings apps/builder/app/builder/features/publish/publish.tsx` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm --filter @webstudio-is/builder test` — 211 files, 2,472 tests passed No fixture inputs or generated outputs are affected. Closes #5976 |
||
|
|
ca08919b13 |
fix: Confirm conflicting root styles on page paste (#5971)
## Summary Prevent page, template, folder, and marketplace page imports from silently replacing local declarations on the shared global root. When incoming root styles differ at the same property, breakpoint, and state, Builder now asks whether to preserve the project values or use the incoming values. Cancellation happens before the runtime mutation. ## Technical choices - Compare CSS values by their serialized meaning so equivalent keyword and unparsed values do not create false conflicts. - Plan breakpoint remapping with the same insertion path used by fragment paste, including ID collisions and breakpoint limits. - Keep named-token conflict resolution separate because token conflicts support suffixing and merging, while a shared root-local declaration has only an existing or incoming value. - Default the root-style dialog to **Keep existing** because global root styles affect every page, and show the breakpoint plus current and incoming values for each conflict. - Re-read current project data after the asynchronous token dialog before detecting root conflicts. - Leave no-conflict resolution undefined so the runtime performs a final conflict check instead of treating it as an explicit **Use incoming** choice. - Resolve root conflicts at the page-copy boundary before using the generic fragment/style insertion path. - Reuse one root-conflict UI resolver for clipboard paste and marketplace imports, one page-transfer traversal helper in the UI and runtime, and one presentational shell for token and root-style conflict dialogs. - Require an explicit `rootStyleConflictResolution` for conflicting `pageTransfer.insert` and `pages.copy` runtime operations so non-UI callers cannot overwrite global values accidentally. - Document that `ours` keeps target-project values and `theirs` uses incoming values in both generated runtime contracts. ## Todo - [x] Detect conflicting root-local declarations by property, breakpoint, and state - [x] Add keep-existing, use-incoming, and cancel behavior - [x] Cover page, template, nested-folder, marketplace, and direct runtime transfer paths - [x] Preserve non-conflicting incoming root declarations with either resolution - [x] Avoid false conflicts for equivalent CSS values and colliding breakpoint IDs - [x] Revalidate root styles after asynchronous token resolution - [x] Preserve existing named-token conflict behavior - [x] Remove duplicated transfer traversal, conflict resolution mapping, and dialog layout - [x] Regenerate the runtime operation contract - [x] Verify regression tests fail when their corresponding behavior is disabled - [x] Run targeted tests, typechecks, formatting, and lint ## Verification - `pnpm --filter @webstudio-is/project-build test -- src/runtime/style-copy.test.ts src/runtime/fragment.test.tsx src/runtime/page-copy.test.tsx` — 80 passed - `pnpm --filter @webstudio-is/builder test -- app/shared/copy-paste/plugin-page.test.ts app/shared/root-style-conflict-dialog.test.tsx app/shared/token-conflict-dialog.test.tsx` — 17 passed - Retrospective fail/pass audit covered semantic CSS equality, breakpoint ID collisions, both runtime guards, both resolution directions, folder/template paths, conflict detail rendering, and stale target data after token resolution - `pnpm --filter @webstudio-is/project-build typecheck` — passed - `pnpm --filter @webstudio-is/builder typecheck` — passed - `pnpm lint` — passed - Runtime contract regeneration was repeated and produced identical output - Fixture pipeline not run locally: no fixture inputs or outputs are affected; GitHub fixture checks passed on the previous revision - Agent evaluations not run: repository guidance requires separate explicit approval before running them ## Compatibility and limitations The new runtime inputs are optional for non-conflicting imports. Existing imports continue unchanged; only imports that would overwrite a conflicting shared root-local declaration require an explicit resolution. No migrations or persistence changes are required. Closes #5970 |
||
|
|
f335340a54 |
fix: Correct content database sizing and Markdown references (#5972)
## Summary - Report only serialized content-database bytes that are actually included in the published bundle. - Replace the ambiguous `markdown-body` query mode with the strict `markdown-body-ref` mode. - Require every selected Markdown body to have a document-graph node; compilation now fails instead of embedding source bytes as a fallback. - Apply the same Markdown eligibility rule during compilation and runtime query execution, excluding non-Markdown files from reference-only databases and results. - Highlight database sizes in red only when documents were omitted because of the size limit. - Refresh Assets diagnostics after an Assets resource edit is confirmed by the server. - Update CLI/MCP guidance, examples, schemas, generated contracts, and fixtures to use the reference-only mode. ## Root cause Dynamic Markdown-body queries conservatively treated unrelated files, including remote images, as possible hydration candidates. The old mode could also fall back to embedding a Markdown body when graph resolution was unavailable, despite its intended storage-backed behavior. Compilation and runtime selection did not previously share the same content-mode eligibility check. Diagnostics displayed the unbounded pre-limit estimate instead of the serialized bundled size, did not carry the omission reason into query-preview diagnostics, and an early cached preview could leave the merged measurement stale until reload. ## Impact Content database diagnostics and publish warnings now reflect bundled database bytes rather than remote source-file sizes. Saved query filters trigger a post-sync diagnostics refresh. Markdown detail queries must use `content.mode: "markdown-body-ref"`; the old `markdown-body` value is rejected, missing graph support is an explicit compilation error, and non-Markdown assets cannot be selected or counted by a reference-only query. Ref #5966 ## Verification - Content engine: 39 files / 261 tests passed. - Asset uploader: 22 files / 183 tests passed. - SDK: 29 files / 505 tests passed. - Protocol: 9 files / 86 tests passed. - Project build: 82 files / 2,055 tests passed. - CLI: full suite previously passed (57 files / 933 tests); final prebuild verification passed 48 tests. - Focused Builder diagnostics tests: 4 files / 10 tests passed. - Typechecks passed for Builder, content engine, asset uploader, SDK, protocol, project build, and CLI. - Generated API contracts and docs are current. - Fixture build passed and is reproducible after the final review changes. - Formatting, lint, package-boundary checks, and diff checks passed. - New strict-reference, runtime-selection, compilation-selection, and size-highlight regression tests were demonstrated failing without their implementations and passing with them. - Agent evaluations were not run because this follow-up did not receive separate evaluation approval. |
||
|
|
56a22fde8a |
feat: Add storage-backed document graph resolution (#5966)
## Summary Introduce a document graph architecture for Assets resources so structured documents can reference one another while keeping full document payloads on CDN-backed storage. The content database will retain the searchable index and dependency graph. At runtime, the server will select a root document, determine its complete dependency set before performing I/O, fetch each unique document concurrently, and assemble the final result server-side. ## Implementation todos ### Document graph foundation - [x] Add normalized internal reference contracts for whole documents, JSON paths, Markdown body, and Markdown frontmatter. - [x] Add an immutable graph abstraction with deterministic ordering, dependency traversal, revision validation, and cycle detection. - [x] Add a storage-independent resolver with dependency closure, bounded parallel loading, shared-content deduplication, representation selection, assembly hooks, cancellation, and structured errors. - [x] Add focused unit coverage for the isolated document-graph abstraction. - [x] Define and validate the external remote-document reference syntax. - [x] Add a pure graph compiler that resolves canonical document URLs into IDs and revisions and validates missing, duplicate, and cyclic dependencies. ### Build-time graph - [x] Add a storage-independent source-catalog compiler for bounded parallel reference discovery and deterministic graph compilation. - [x] Add a versioned deterministic document graph artifact with canonical serialization and integrity verification. - [x] Discover and normalize statically declared references while Assets resources are processed. - [x] Resolve document identities and revisions and report missing, stale, or cyclic dependencies with document context. - [x] Persist document nodes and dependency edges alongside searchable resource metadata. - [x] Include persisted graph data in artifact integrity and size validation. ### Document representations - [x] Add a standalone JSON document adapter for exact reference markers, compiler occurrences, JSON path selection, and immutable assembly. - [x] Add a standalone Markdown document adapter for bounded decoding, frontmatter references, immutable assembly, and source, body, and frontmatter selection. - [x] Parse fetched JSON and Markdown documents through format-specific adapters. - [x] Select complete documents, JSON fragments, Markdown body, and Markdown frontmatter through the shared reference model. - [x] Assemble nested and shared references into the final server-side value. ### Runtime resolution - [x] Enforce reachable-document, per-document byte, and aggregate-byte limits before parsing and assembly. - [x] Add a revision-keyed bounded source-cache wrapper with replayable bytes, stale-entry fallback, and in-flight deduplication. - [x] Add a storage-neutral loaded-source contract that rejects revision mismatches before parsing. - [x] Resolve graph-backed property paths before filtering, sorting, pagination, and projection; skip graph loading for unrelated queries. - [x] Add an injected HTTP/CDN document loader with revision metadata validation. - [x] Apply runtime payload limits, bounded concurrency, caching, and structured failure mapping. - [x] Ensure shared documents are fetched and parsed once per resolution. ### Product integration - [x] Integrate equivalent behavior in local preview, SSR, SSG, and published runtime paths. - [x] Preserve existing embedded Assets resource behavior without requiring migration. - [x] Add observability for graph loading, document fetching, caching, and resolution failures. - [x] Document the public reference and resolution behavior. ### Review hardening - [x] Enforce graph, artifact, cache, and published-storage identity consistency. - [x] Compile only graph sources reachable from selected build entries. - [x] Resolve graph-backed fields before query evaluation and avoid unnecessary graph loading. - [x] Consolidate duplicated graph schemas, utilities, and document content-type detection. - [x] Correct runtime documentation and use structural evaluation validation. ### Verification - [x] Keep a deterministic high-impact agent evaluation for Markdown-to-JSON references across the dynamic blog overview and article routes. - [x] Add a separate discoverability evaluation that must learn the reference workflow from MCP guidance without prompt-supplied syntax, queries, bindings, or call order. - [ ] Re-run the complete local agent evaluation suite after the discoverability fixture change and compare every fixture with its accepted baseline. - [x] Add integration coverage for CDN-backed hydration, parallel fetching, caching, and shared dependencies. - [x] Add integration coverage for missing references, cycles, revision changes, limits, and cancellation. - [x] Verify equivalent behavior across preview, SSR, SSG, and published deployments. - [x] Verify that existing embedded Assets resources retain their current behavior. ## Intended outcome - Storage-backed documents do not require their complete payloads to be embedded in the content database. - The server knows the complete statically discoverable dependency set before fetching document content. - Shared dependencies are fetched once per resolution and independent resources can be fetched in parallel. - JSON fragments and Markdown body/frontmatter representations use the same document-resolution system. - Reference and payload revisions cannot be mixed silently. - Existing Assets resources continue to work without migration. ## Verification results - `@webstudio-is/content-engine`: 37 files / 244 tests passed; typecheck passed. - `@webstudio-is/asset-uploader`: 22 files / 182 tests passed; typecheck passed. - CLI: 57 files / 925 tests passed, including generated SSR and SSG build/prerender coverage; typecheck passed. - Repository-wide `pnpm oxfmt --check` passed across 2,757 files. - Package-boundary validation passed. - Previous `pnpm evaluations` run: all 4 original high-impact fixtures passed. The complete 5-fixture rerun is pending explicit approval after adding the discoverability fixture. |
||
|
|
3ccb46cec7 |
fix: restore Marketplace settings and optimize Assets publishing (#5964)
## Outcome Restore the Marketplace section for projects without existing marketplace metadata, make the complete review-submission workflow available over MCP, clarify shared Assets database diagnostics, and reduce published database size by materializing fully static Assets queries. ## Implementation ### Marketplace and MCP - Initialize the Marketplace form from a safe partial default instead of rendering nothing when metadata is unconfigured. - Keep review submission disabled until the complete metadata schema is valid. - Allow `get-marketplace-product` to return `null` and `update-marketplace-product` to create the first marketplace product through ProjectSession/MCP. - Add a confirmed `submit-marketplace-product` server operation that validates configured metadata before setting review status to `PENDING`. - Document the MCP workflow: upload the thumbnail, update metadata, publish production, then submit. - Correct the Marketplace thumbnail upload example to use the current MCP input field. ### Assets database - Show query size and merged published-database size separately in resource diagnostics. - Clarify that only the merged database counts toward the publish limit. - Allow the Assets query editor to scroll long query source. - Materialize fully static metadata-only Assets queries at publish time. - Store materialized results as compact field columns and rows keyed by a deterministic normalized-query hash. - Serve materialized rows through the existing Assets response contract without candidate documents or a runtime field catalog. - Keep route- or variable-dependent queries on the existing document-backed runtime path. - Exclude overview-only fields from dynamic detail documents so the merged database does not duplicate them. - Preserve byte-limit selection, truncation diagnostics, integrity verification, caching, and backward compatibility with existing artifacts. ### Release - Keep the release lockfile stable when preparing the CLI package. - Regenerate runtime contracts, server-only API metadata, and CLI documentation where required. ## Todo - [x] Restore the empty Marketplace settings state - [x] Prevent empty review submissions - [x] Support first-time Marketplace metadata creation over MCP - [x] Add MCP review submission - [x] Document the end-to-end MCP workflow - [x] Correct query and merged-database diagnostics - [x] Make long Assets query source scrollable - [x] Materialize static overview queries - [x] Preserve dynamic detail-query behavior - [x] Add regression coverage with fail/pass proof - [x] Run relevant package and integration checks ## Verification - [x] Content engine tests: 158 passed - [x] Asset uploader tests: 179 passed - [x] SDK tests: 505 passed - [x] CLI tests: 921 passed - [x] CLI prebuild integration tests: 46 passed - [x] Builder Assets resource and diagnostics tests: 14 passed - [x] Project runtime and ProjectSession tests: 133 passed - [x] Builder API router tests: 30 passed - [x] Protocol operation tests: 18 passed - [x] Content engine build and declaration generation - [x] Content engine, asset uploader, SDK, Builder, and CLI typechecks - [x] Repository lint and formatting checks - [x] Generated API and documentation checks - [x] New materialization tests demonstrated failing with the implementation disabled and passing after restoration ## Notes - The representative five-post overview fixture shrinks from 2,122 bytes to 1,197 bytes while returning the same sorted and paginated result. - Materialization is intentionally limited to static, metadata-only field queries without runtime asset fields. Unsupported or data-incompatible queries safely use the existing runtime database. - The complete `pnpm evaluations` agent suite was not run because repository policy requires separate explicit approval. - No database schema or migration changes are required. |
||
|
|
3aeb4b3f61 |
fix: Reuse npm launcher for generated previews (#5962)
## Summary Generated previews now reuse the npm CLI path supplied by the npx launcher instead of rediscovering npm or npm.cmd through the MCP subprocess PATH. The same invocation is used for dependency installation, production builds, and preview server startup, with the existing platform command retained as a fallback for direct launches. ## Technical choices - Invoke npm-cli.js with the current Node executable when npm_execpath identifies npm as the launcher. - Parse Windows paths with the platform path implementation. - Keep npm and npm.cmd fallback behavior when Webstudio was not launched through npm. - Inject executable paths in tests so launcher behavior is deterministic. ## Todo - [x] Reuse the npx npm launcher during generated dependency installation. - [x] Apply the same launcher to generated build and server commands. - [x] Cover Windows launcher paths and direct-launch fallbacks. - [x] Run focused tests, typecheck, lint, formatting, and production build. ## Verification - pnpm --filter webstudio test -- src/commands/preview.test.ts src/preview-server.test.ts - pnpm --filter webstudio typecheck - pnpm exec oxlint --deny-warnings on the four changed files - pnpm --filter webstudio build - git diff --check All checks passed. The build emitted the existing Radix use-client bundling warnings. Agent evaluations were not run because they require separate explicit approval. |
||
|
|
e210fedc02 |
fix: support Cursor-compatible MCP tool names (#5961)
## Summary - configure Cursor connections to request underscore-only MCP tool names - advertise Cursor-safe names while mapping calls back to canonical Webstudio operations - preserve canonical tool names for other MCP clients and shell workflows ## Verification - pnpm --filter webstudio test -- src/commands/connect.test.ts src/commands/mcp.test.ts - pnpm --filter @webstudio-is/project-build test -- src/mcp.test.ts - pnpm --filter webstudio typecheck - pnpm --filter @webstudio-is/project-build typecheck - pnpm exec oxlint --deny-warnings on changed files - pnpm exec oxfmt on changed files - pnpm evaluations not run (requires separate explicit approval) Closes #5960 |
||
|
|
efbc3098c4 |
feat: add queryable Assets resources (#5946)
Closes #5919 Ref #5920 ## Outcome Extend the existing Assets system resource with optional queries for Markdown, JSON, and standard file metadata. Unconfigured Assets resources retain the existing fetch-all behavior and activate none of the content-query infrastructure. Files are the authoring model. A standalone content engine converts an immutable snapshot of only the files required by configured queries into one bounded, deterministic runtime database. Builder preview, SSR, and SSG use the same query semantics without requiring a database service for a published site. ## Final architecture ```text Markdown / JSON files │ ▼ ContentSource adapter (FS or Webstudio Assets) │ immutable snapshot ▼ ContentCompilationPlan (union of configured query requirements) │ ▼ ContentCompiler (parse, normalize, discover fields, enforce budget) │ ▼ ContentArtifact (bounded, deterministic, immutable JSON) │ ▼ ContentDatabase (filter, OR groups, sort, paginate, project, read content) │ ├── Builder preview ├── SSR runtime └── SSG build only ``` The authoring/storage layer owns mutable files. The content engine consumes immutable snapshots and produces immutable, disposable artifacts. Query authoring is a separate OpenAPI-driven path: ```text Assets REST OpenAPI operation + standard request JSON Schema + dynamic field paths │ ▼ Generic OpenAPI adapter │ resolved schemas, controls, paths, and transport mapping ▼ Generic query-builder core and React renderer │ arbitrary provider-defined value ▼ Assets REST request adapter │ ▼ { query: value } ``` The selected standard OpenAPI operation is the only source of query UI semantics. Request parameters and JSON Schema describe the editable data; the generic renderer derives controls and owns layout. ### Activation and compilation - The compiler does not index every asset. It combines all reachable configured Assets-resource queries into one `ContentCompilationPlan`. - Static constraints such as folder, path, and file type select candidate files. Dynamic values such as a route-bound slug cannot reduce the build-time candidate set. - The plan contains the union of fields used by filtering, sorting, routing, projection, excerpts, and requested full content. - Documents shared by multiple resources are stored once in one deployment-wide runtime database. - Markdown/frontmatter, JSON properties, excerpts, and full bodies are prepared only when required. - No configured content query means no parsing, artifact, or shipped runtime dependency. Fresh generated apps need no content-runtime cleanup; incremental generation removes stale integration if a previously configured query is deleted. ### Runtime database limit - `CONTENT_DATABASE_MAX_BYTES` limits the complete serialized runtime database, not source files, images, or unrelated assets. - The default is `500 * 1024` bytes and is presented as 500 KiB. - Counted data includes indexed metadata, frontmatter/JSON properties, excerpts, the field catalog, serialization overhead, and full Markdown bodies only when requested. - Prepublish validation builds and serializes the exact database that will be attached to the immutable build, so it knows the unbounded size, bounded size, included documents, omitted documents, and affected resources. - Overflow never stores partial documents. Candidates are ordered by `createdAt` descending, canonical path ascending, and stable document ID ascending. Missing dates follow dated documents. A document that does not fit is skipped while smaller later documents are still considered. - Exceeding the limit warns but does not block publishing. - Builder preview can report exact bounded versus unbounded results when dynamic expressions have concrete preview values. Prepublish warnings remain conservative for future route values. ### Snapshot consistency The source contract guarantees a consistent compilation, while adapters provide the mechanism: - Webstudio Assets captures asset metadata and immutable content references. - Filesystem sources capture file identity and verify files did not change before accepting the artifact. - A changed source retries once, then fails clearly instead of producing a mixed-revision database. - This requires no universal snapshot service, source-tree copy, or new versioned-asset infrastructure. ### Package ownership - `@webstudio-is/content-engine`: runtime artifact schema, query execution, field catalog, compact runtime statistics. - `@webstudio-is/content-engine/compiler`: source snapshots, compilation plans, Markdown/JSON parsing, deterministic compilation, byte accounting, and compiler diagnostics. This entry exists to keep Remark/YAML/future MDX dependencies out of runtime bundles. - `@webstudio-is/query-builder`: resolves standard OpenAPI operation schemas into an internal provider-neutral editor model, validation, mutations, and source serialization. It owns no Assets, provider-authored UI contract, or fixed REST-query semantics. - `@webstudio-is/query-builder/react`: container-neutral schema renderer whose layout is renderer policy. It remains separate from the content engine. - SDK: Webstudio Assets/Resource domain models and mapping Webstudio expressions into generic content requirements. - Protocol: external Assets REST/OpenAPI transport contracts. - Asset uploader/repository: asset and folder mutations, generic metadata, immutable byte references, and storage access. Its hosted adapter supplies Webstudio Assets snapshots and parsed-metadata cache persistence to the content engine; parsing, artifact creation, and query semantics remain engine-owned. - Builder and generated-app integrations decide when to compile, cache, embed, load, or discard a database. ### Runtime lifecycle - Builder caches immutable `ContentDatabase` instances by source revision plus compilation-plan hash and coalesces concurrent compilation. Matching operations reuse the same instance; field discovery uses a dedicated minimal all-properties plan that excludes excerpts and bodies. - SSR attaches the validated bounded database to the build and includes the small runtime only when required. - SSG uses the database only while generating pages and omits it and the runtime from final output unless a future runtime-query feature requires them. - Local development compiles from the filesystem and uses identical query semantics. - Published pages query their local artifact; they do not call Builder REST endpoints. - Published artifacts need no external index store, invalidation, garbage collection, SaaS content proxy, new bucket, or new environment variable. ## Implemented foundation These existing parts remain useful and should be moved behind the final ownership boundaries rather than reimplemented. - [x] Upgrade the existing Assets system resource in place and preserve unconfigured fetch-all behavior. - [x] Implement typed filtering, nested boolean groups, deterministic sorting, pagination, projections, dynamic values, and content hydration. - [x] Add Markdown frontmatter, excerpt, JSON-property, and field-catalog extraction. - [x] Add reusable query-control implementations and a separately imported React UI as a foundation for the final OpenAPI-driven contract. - [x] Add Assets query authoring and dynamic field discovery as existing behavior to migrate into the Assets OpenAPI operation. - [x] Add synchronized visual and editable expression authoring. - [x] Unify Assets REST operations under `/rest/assets/*`. - [x] Define authenticated collection, item, content, upload, folder, query, field-catalog, and OpenAPI operations. - [x] Support Builder cookie authentication and public API token authentication. - [x] Add Builder preview, MCP/CLI operations, SSR execution, SSG path generation, and conditional activation. - [x] Add revision-keyed parsed metadata persistence for the hosted Builder. - [x] Add focused query, API, authorization, Builder, CLI, SSR, SSG, migration, and fixture coverage. ## Remaining implementation plan ### 1. Establish the content engine - [x] Rename the generic `@webstudio-is/asset-resource` implementation to `@webstudio-is/content-engine`. - [x] Move existing behavior instead of creating a parallel implementation. - [x] Keep the primary entry runtime-only and add only the compiler entry needed for bundle separation. - [x] Remove the old package after all consumers migrate. - [x] Ensure the engine has no Builder, SDK, asset-uploader, PostgreSQL, R2, or deployment-target dependency. ### 2. Define source snapshots and compilation plans - [x] Introduce `ContentSource.openSnapshot()` and a revision-bearing `ContentSourceSnapshot`. - [x] Include canonical path, stable document ID, content type, immutable content reference, size, and optional `createdAt`. - [x] Implement Webstudio Assets and filesystem snapshot guarantees using their adapter-specific mechanisms. - [x] Introduce `ContentCompilationPlan` for the union of reachable configured resource requirements. - [x] Separate statically selectable candidates from dynamic runtime predicates. - [x] Add mutation-during-compilation tests for replacement, deletion, folder movement, and filesystem changes. ### 3. Separate storage from content processing - [x] Keep upload, replacement, folders, byte storage, revisions, and generic metadata in the Assets repository/uploader. - [x] Move parsing, excerpts, field discovery, query execution, and artifact creation into the content engine. - [x] Remove content-index coordination from asset mutation business logic. - [x] Preserve original source `createdAt` across content replacement and expose it as optional queryable metadata. - [x] Keep hosted parsed-document persistence behind the content compiler's optional cache interface. ### 4. Build deterministic compilation - [x] Move the existing Markdown, frontmatter, JSON, canonicalization, hashing, document-building, and tests into the compiler. - [x] Keep frontmatter behind a dedicated module and continue using the existing Remark/Micromark pipeline. - [x] Parse only candidate files and only the tiers required by the compilation plan. - [x] Deduplicate documents and fields required by multiple resources. - [x] Define a versioned, deterministic `ContentArtifact` with integrity information. - [x] Keep verbose parse and omission diagnostics outside the runtime artifact. - [x] Reject incompatible artifact versions cleanly. ### 5. Enforce the deployment-wide database budget - [x] Replace the old asset-index limit with `CONTENT_DATABASE_MAX_BYTES`, defaulting to 500 KiB. - [x] Have applications read configuration and pass the byte limit into the compiler. - [x] Measure the exact serialized database, including selected bodies and overhead. - [x] Implement deterministic skip-and-continue packing of complete documents. - [x] Return compiler diagnostics with unbounded/bounded bytes, included/omitted counts, omitted identities, largest contributors, and affected resources. - [x] Expose only compact artifact statistics at runtime through `ContentDatabase.getStats()`. - [x] Add exact boundary, deterministic ordering, deduplication, and oversized-document tests. ### 6. Finalize the runtime database - [x] Define `ContentDatabase` over an immutable artifact. - [x] Preserve filtering, nested AND/OR groups, sorting, offset/limit, projection, field references, and content retrieval. - [x] Expose `getFieldCatalog()` and compact `getStats()`. - [x] Keep Markdown/YAML/compiler dependencies out of the runtime entry. - [x] Add execution guards and maximum-size runtime benchmarks. ### 7. Make query authoring OpenAPI-driven The selected standard OpenAPI operation is the complete query-authoring contract. The query builder resolves parameters and request-body JSON Schema, derives its internal editor model, and applies renderer-owned layout policy. It must not embed or fetch a second capabilities/UI language through `x-webstudio-query` or another side channel. - [x] Remove `x-webstudio-query` and all vendor query-definition metadata from the Assets OpenAPI operation. - [x] Resolve local OpenAPI references and derive the editable request value, defaults, validation, labels, choices, arrays, objects, and unions solely from standard operation parameters and request-body JSON Schema. - [x] Represent dynamic Assets field paths with standard JSON Schema vocabulary in the `queryAssets` request schema. - [x] Keep the normalized editor representation internal to query-builder; do not expose another provider-authored capabilities contract. - [x] Remove provider-controlled layout metadata such as `group`; make compact scalar packing and all other layout renderer policy. - [x] Keep Webstudio expression binding as a consumer/editor concern layered over schema values, not part of the OpenAPI contract. - [x] Preserve the existing Assets filter, sort, output selection, full-content/range selection, limit/offset, editable source, and configured-field behavior. - [x] Keep the Assets resource adapter responsible for serializing the edited query into its request body. - [x] Remove the obsolete Assets query-capabilities endpoint, URL, and UI-side capability parsing. - [x] Add a non-Assets OpenAPI proof with differently named parameters and no vendor metadata. - [x] Verify the generic packages contain no Assets imports, fixed Assets property contract, or provider-authored layout model. - [x] Update focused core, React, SDK, protocol/OpenAPI, Builder, and source round-trip tests. ### 8. Manage ContentDatabase lifecycle in Builder - [x] Cache databases by source revision plus normalized compilation-plan hash. - [x] Coalesce concurrent compilation requests. - [x] Reuse cached database instances across field discovery, autocomplete, query preview, and response preview when their normalized compilation plans match. - [x] Replace it when source revision or query requirements change. - [x] Preserve the optional revision-keyed hosted parsed-document cache without making it a source of truth. - [x] Show exact preview warnings when concrete values reveal missing bounded results. ### 9. Materialize and verify immutable builds - [x] Compile and serialize the exact deployment-wide database during prepublish validation. - [x] Attach that validated bounded database to the immutable build without rebuilding it from later asset state. - [x] Show non-blocking prepublish warnings with database bytes, omissions, and potentially affected resources. - [x] Avoid claiming exact future route matches when dynamic values are unknown. - [x] Include the database/runtime only when a reachable configured query requires them. - [x] Ensure detail resources requesting Markdown content include all statically eligible bodies needed by dynamic routes. ### 10. Integrate all targets - [x] SSR: load the build's bounded database and conditionally include the small runtime. - [x] SSG: query the same database during generation, then omit database/runtime output when no runtime query is needed. - [x] Local/CLI: compile from the filesystem source with the same semantics. - [x] Preserve overview pagination, alternative route fields, draft-as-user-data behavior, and full article rendering. - [x] Verify ordinary Assets and fresh query-free sites perform no parser, artifact, content-runtime dependency install, or cleanup work. ### 11. Correct API and package ownership - [x] Move external Assets REST/OpenAPI contracts to `@webstudio-is/protocol`. - [x] Keep Webstudio domain models and Assets system-resource configuration in the SDK. - [x] Keep both cookie and token authentication behavior on the unified Assets REST surface. - [x] Remove pass-through route wrappers/reexports that add no transport behavior. - [x] Keep published runtime queries local to the artifact rather than routing them through Builder REST. ### 12. Remove superseded deployment infrastructure - [x] Remove external deployment-index upload, fetch, invalidation, cleanup, and garbage-collection code. - [x] Remove the SaaS asset-origin adapter requirement; close webstudio-is/webstudio-saas#652 as superseded because it has no independent purpose. - [x] Remove index-bucket compatibility configuration and avoid adding Infisical variables. - [x] Remove obsolete external-index paths, package dependencies, routes, scripts, and tests. - [x] Consolidate unreleased intermediate migrations where safe and retain only schema required by the final hosted cache/API design. ### 13. Verification and release readiness - [x] Move and preserve existing tests while changing ownership; add new tests only for changed contracts and behavior. - [x] Run content-engine compiler/runtime tests, query-builder tests, SDK/protocol/API tests, Builder tests, CLI tests, and affected typechecks. - [x] Run formatting, generated-file idempotence, fixtures, clean Supabase-compatible migrations, E2E shards, and complete agent evaluations. - [x] Verify SSR and SSG conditional inclusion and query-free generated package manifests. - [x] Run the five-article MCP blog workflow: authoring, field discovery, overview, dynamic detail routes, full Markdown rendering, publishing, and published-site verification. - [x] Run a maximum-budget database test and a mutation-during-compilation test. - [x] Perform a final architecture, security, API compatibility, migration, bundle, correctness, and DRY review. - [x] Reconcile every checkbox and replace the verification section with results from the final architecture before release. ## Future MDX work MDX is intentionally separate from this release. - The compiler contract should allow a future build-only MDX parser. - MDX compilation must not enter the published runtime. - Embedded JSX must use an explicit compiled representation rather than runtime source evaluation. - Webstudio components, tokens, styles, and component allowlists remain Webstudio integration concerns. - The future MDX work should reuse `ContentArtifact` and `ContentDatabase` where practical. ## Superseded design The following earlier design choices are no longer the target architecture: - GROQ or GraphQL as the Assets query language. - One external or long-lived index object per resource/query. - A deployment index fetched by the Worker from SaaS/CDN infrastructure. - Lazy production reads of source Markdown bodies. - A separate index bucket, asset origin, invalidation service, or garbage collector. - A 4 MiB published index limit. - Rebuilding an old build's database from the current mutable asset set. - Bundling query infrastructure into projects without a configured content query. ## Verification baseline The embedded runtime-database architecture previously passed the checks below. The OpenAPI-driven query-authoring change additionally passed: - Query-builder core: 4 files / 19 tests. - Query-builder React: 1 file / 7 tests. - SDK Assets source/config: 1 file / 7 tests. - Protocol Assets OpenAPI: 1 file / 9 tests, including independent OpenAPI validation. - Builder Assets OpenAPI description: 1 file / 5 tests. - Query-builder, React, SDK, protocol, and Builder typechecks. - Package-boundary validation and formatting of every affected file. Local verification baseline: - Content engine: 15 files / 104 tests. - Asset uploader: 24 files / 175 tests. - Builder: 204 files / 2,423 tests. - CLI: 54 files / 866 tests. - Complete workspace typecheck, formatting, lint, package boundaries, generated fixtures, and fixture builds. - The complete migration history applied successfully to a fresh Supabase-compatible database, including every migration after the consolidated Assets migration. - Builder production build and full local E2E suite passed. - Complete agent evaluations passed: authenticated page (170,859 ms), design input (207,101 ms), and font assets (67,050 ms). - Final review additionally verified correct REST edit/view/build permits, cookie and public-token read paths, immutable snapshot retries, exact database budgeting, query-free dependency omission, and SSR/SSG conditional runtime inclusion. Final staging verification passed against the embedded runtime-database architecture: MCP uploaded and updated five Markdown articles, discovered dynamic frontmatter fields, previewed a five-item sorted overview and one full-body slug query, updated both Assets resources, found zero binding issues, rendered `/blog` and `/blog/dynamic-routes` at HTTP 200, published build version 266, and verified both published routes at HTTP 200 with the expected article metadata and Markdown body. The workflow also found and fixed offset-form asset timestamps failing canonical datetime validation and made MCP `preview.start({ port: 0 })` correctly select an available local port. ## Release constraints - No new SaaS content service, bucket, or environment variable. - No published-site database dependency. - No parser/compiler dependency in query-free sites or runtime-only bundles. - The validated content database is immutable build output. - Publishing warnings do not block deployment. - The selected standard OpenAPI operation and its request JSON Schema are the only source of query UI semantics. |
||
|
|
7bc9942774 |
perf: Improve MCP evaluation reliability and efficiency (#5959)
## Summary - capture bounded MCP failure codes, validation issue paths, per-tool latency, mutation timing, uncached input, catalog size, and per-call/per-tool response bytes in every evaluation result - require every raw fixture outcome to have zero failed calls and zero retries, even when the workflow later recovers - update baselines only when all raw outcomes and all regression comparisons pass - refuse to replace an accepted aggregate token baseline with a noisier, higher-token sample - regression-gate aggregate response bytes alongside tokens, calls, focused reads, mutations, errors, and retries - compact repeated SDK schemas while preserving required arguments, destructive safety controls, and ordinary optional fields for common goal-guided tools - omit low-frequency optional argument names until focused discovery, reducing the initial tool handshake without removing callable tools - stop echoing the caller's goal from `meta.guide` responses - make evaluations copy their canonical objective verbatim into `meta.guide`, preventing vague paraphrases from selecting a generic workflow - normalize grouped `styles` and `declarations` maps into canonical flat `update-styles` operations before validation - normalize relative `create-page` paths through the platform URL parser - bundle the four bounded authentication discovery reads into one `inspect-auth-context` call - bound large MCP style-key mutation results while preserving a representative sample and exact total count - combine fragment insertion with immediate persisted binding verification to remove a sequential model turn ## Root causes and impact Recovered MCP failures could previously be reported as successful raw outcomes, and baseline files could be written before the complete comparison result was known. Raw outcomes now fail on any MCP error or retry, and accepted baselines are written only after every fixture and comparison passes. Rejected samples exposed two concrete error sources. A vague authentication objective selected a generic workflow and produced four validation failures, 20 calls, and 1.07M tokens; evaluations now pass the canonical objective verbatim. A relative `create-page.path` caused an `INVALID_INPUT` failure and retry; the adapter now canonicalizes it before validation. The deterministic catalog in the accepted baseline measures **50,864 bytes**, down from **53,317 bytes** (−4.60%). Input schemas fell from **31,190 to 28,737 bytes** (−7.86%). The two composite workflows add two conditionally exposed tools and 360 catalog bytes (about +0.71%) when their backing operations are available. Broad experiments that removed focused descriptions or all goal-specific examples made guide responses smaller but increased token use or caused retries. Those variants were rejected. The current implementation compacts only recognized goal guides, while retaining the detailed `update-styles` schema and the `upload-assets` batch example proven necessary by the evaluations. ## Workflow-churn iteration Authenticated discovery uses one model-visible `inspect-auth-context` call. Fragment authoring can now use `insert-fragment-verified`, which commits the insertion and immediately runs persisted binding verification for up to 200 bindings. This removes the following sequential verification turn without changing mutation or verification counts. Current deterministic workflow shape: - authenticated workflow calls: **14 → 10** (−28.57%) - design workflow calls: **17 → 16** (−5.88%) - aggregate workflow calls: **39 → 34** (−12.82%) - failures: **0** - retries: **0** - authenticated MCP response bytes: **52,524 → 46,900** (−10.71%) - authenticated guide response: **26,782 → 24,358 bytes** (−9.05%) One complete run measured authenticated tokens at **348,225** (−11.44%) and first verification at **38.3s** (−30.14%); design first verification moved to **28.1s** (−27.27%). The final exact-code run also passed with **10/16/8** calls and zero failures/retries, measuring authenticated tokens at **377,802** (−3.92%) and design first verification at **34.5s** (−10.67%). The composite preserves post-commit safety: if verification infrastructure fails after insertion, the result remains `committed:true`, returns `POST_COMMIT_VERIFICATION_FAILED`, and explicitly instructs the agent not to repeat the insertion. A guarded baseline-update run was rejected because stochastic aggregate tokens did not beat the accepted result, so no result artifacts were rewritten. ## Style response compaction Large style mutations previously returned every generated style key. In the design fixture, that single successful response was **19,121 bytes** and remained in context for all later turns. MCP responses now retain the first 20 keys plus `styleKeyCount` and `styleKeysTruncated`; the typed runtime operation remains unchanged. Focused evaluation results: - `update-styles` response: **19,121 → 2,815 bytes** (−85.28%) - design-workflow MCP responses: **70,941 → 54,633 bytes** (−22.99%) - calls: **17 → 17** - failures/retries: **0 / 0** - tokens: **498,764 → 505,136** (+1.28%, treated as noise and not accepted as a new baseline) The subsequent complete `pnpm evaluations` run passed all three fixtures with exact **11/17/8** call sequences and zero failures/retries. The accepted lower-token baseline remains unchanged. ## Goal-guide context compaction Recognized goal guides no longer repeat every selected tool's description and examples. Current Codex clients defer MCP tools and load each named tool's exact contract before invocation, so the guide keeps the goal-specific workflow while returning compact tool references. Free-form guide searches remain fully descriptive. Two complex inputs remain intentionally hydrated: `update-styles` keeps its detailed schema, and `upload-assets` keeps one batch example. Removing the upload example caused five failed attempts in a complete run; restoring only that example returned the font workflow to its exact 8-call, zero-error path. Final complete-suite results: - calls: **10 / 16 / 8** (**34 aggregate**) - failures/retries: **0 / 0** - goal-guide payload: **58,082 → 37,718 bytes** (−35.06%) - authenticated MCP responses: **46,900 → 38,268 bytes** (−18.41%) - design MCP responses: **51,854 → 44,008 bytes** (−15.13%) - aggregate MCP responses versus the accepted baseline: **147,335 → 101,922 bytes** (−30.82%) - aggregate tokens: **1,146,951**, only **+0.33%** above the stricter accepted 1,143,217-token baseline The complete suite and every per-fixture comparison passed. The guarded updater did not replace the accepted artifacts because the aggregate token sample did not beat the existing baseline. ## Responsive verification batching The MCP now exposes `screenshot.responsive` when reusable page capture is available. It accepts one generated route plus 1–8 viewports, refreshes the session preview once, reuses one browser target, and returns bounded evidence for every viewport. Auth and design evaluation workflows use one responsive capture instead of a separate preview start and two screenshot turns. Automatic screenshots now allocate an available preview port and reuse an already-running managed preview port. This prevents an unrelated service on the historical 5173 default from producing an MCP failure. Explicit ports, local previews, and external URLs remain unchanged. The evaluator records the bounded viewport array, counts the batch as verification and visual evidence, and compares its latency, response size, calls, errors, retries, and token consumption on every run. The new regression tests were demonstrated fail-then-pass. Guarded accepted results: - aggregate tokens: **1,143,217 → 990,190** (−13.39%) - aggregate calls: **39 → 30** (−23.08%) - aggregate MCP response bytes: **147,335 → 98,470** (−33.17%) - failures/retries: **0 / 0** - authenticated calls: **14 → 8** (−42.86%) - design calls: **17 → 14** (−17.65%) ## Design and font workflow batching Design discovery now uses one conditionally exposed `inspect-design-context` call to return bounded pages, breakpoints, design tokens, assets, and variables instead of five model-visible reads. Font persistence now uses one `verify-font-assets` call to refresh the asset namespace and return every changed font asset instead of a refresh plus separate verification reads. The evaluation tasks and validators require these composite paths. Both tools retain the underlying operation limits, namespace metadata, persisted-result checks, and zero-error/retry gates. Review also confirmed that SDK schemas must keep `additionalProperties:false` and that non-default MCP safety hints must remain explicit; those protocol constraints were preserved rather than traded for catalog-token savings. Guarded accepted improvements versus the previous responsive-batching baseline: - aggregate tokens: **990,190 → 914,760** (−7.62%) - aggregate calls: **30 → 24** (−20.00%) - aggregate focused reads: **8 → 2** (−75.00%) - aggregate MCP response bytes: **98,470 → 95,614** (−2.90%) - design calls: **14 → 10** (−28.57%) - font calls: **8 → 6** (−25.00%) - failures/retries: **0 / 0** The strict SDK catalog is **51,362 bytes** with **28,964 input-schema bytes**. The two new conditional workflow tools add 355 catalog bytes (+0.70%) and 130 schema bytes (+0.45%) while removing six model-visible workflow turns. ## Terminal responsive verification Auth and design now finish with one conditionally exposed `verify-page-responsive` call. It captures every requested viewport in one browser session and immediately runs the static page audit, removing one sequential model turn per workflow while retaining both kinds of evaluator evidence. The tool inherits the audit operation's permit and read namespaces; strict SDK schemas and MCP safety annotations remain unchanged. Latest complete comparison against the accepted baseline: - aggregate tokens: **914,760 → 869,274** (−4.97%) - aggregate calls: **24 → 22** (−8.33%) - aggregate MCP response bytes: **95,614 → 95,053** (−0.59%) - authenticated calls: **8 → 7** - design calls: **10 → 9** - font calls: **6 → 6** - failures/retries: **0 / 0** - authenticated focused run: **289,078 tokens** (−10.06%) and first verification **55,552 ms** (−17.90%) - design focused run: p95 MCP latency **9,642 ms** (−10.32%); token and first-verification variance increased in that individual sample, so only the complete comparison is used for the aggregate conclusion The complete comparison passed all fixture and aggregate regression gates. Two subsequent guarded `--update-baselines` attempts could not start any fixture because the external Codex runner had reached its usage limit; both exited before the first MCP call and wrote no accepted result files. Therefore the tracked accepted baseline below remains **914,760 tokens / 24 calls**, while **869,274 tokens / 22 calls** is the latest successful complete comparison. Regression coverage was demonstrated fail then pass. After this iteration, project-build MCP tests passed **105/105**, high-impact evaluation tests passed **41/41**, and project/CLI typechecks, lint, package boundaries, generated docs, and diff checks all passed. ## Accepted evaluation baseline | Fixture | Failed | Retries | Calls | Mutations | Tokens | Uncached input | Response bytes | First mutation | First verification | | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | authenticated-page-v1 | 0 | 0 | 8 | 4 | 321,396 | 44,353 | 37,536 | 39,076 ms | 67,660 ms | | design-input-v1 | 0 | 0 | 10 | 6 | 330,580 | 54,441 | 40,036 | 30,419 ms | 36,551 ms | | font-assets-v1 | 0 | 0 | 6 | 3 | 262,784 | 20,704 | 18,042 | 37,609 ms | 47,073 ms | Accepted aggregate: **914,760 tokens**, **24 calls**, **2 focused reads**, and **95,614 MCP response bytes**, with zero failures and zero retries. Compared with the previous accepted baseline, tokens fell **7.62%**, calls fell **20.00%**, focused reads fell **75.00%**, and response bytes fell **2.90%**. ## Verification - [x] Complete `pnpm evaluations -- --update-baselines` - [x] Independent complete `pnpm evaluations` after the composite workflow change - [x] Worse-token and error-containing samples rejected without replacing accepted baselines - [x] Added/changed regression tests demonstrated fail then pass - [x] Project-build MCP tests: 105 passed - [x] Complete high-impact evaluation tests: 41 passed - [x] Project-build and CLI typechecks - [x] `pnpm lint` - [x] `pnpm check:package-boundaries` - [x] `pnpm check:generated-docs` - [x] `git diff --check` - [x] Earlier workspace tests, including 2,356 builder tests - [x] Earlier generated API checks - [ ] Fixture sync/build: sync could not reach `main.development.webstudio.is` and timed out; no local test, evaluation, or code check failed ## Implementation checklist - [x] Error and retry rate enforced at zero for raw and compared outcomes - [x] Relative page paths normalized to prevent a known validation failure and retry - [x] Baseline replacement blocked unless every outcome and comparison passes - [x] Aggregate token baselines cannot ratchet upward - [x] Workflow churn bounded and regression-gated - [x] Authentication discovery collapsed from four model-visible reads to one - [x] Fragment insertion and persisted binding verification combined safely - [x] Large style-key mutation results bounded at the MCP boundary - [x] Token consumption captured, compared, and regression-gated - [x] Response bytes captured per call and tool, summarized, and aggregate regression-gated - [x] Per-tool latency, mutation timing, catalog size, and validation paths captured - [x] Repeated catalog/schema and focused-guide context reduced - [x] Canonical goal selection stabilized for evaluations - [x] Grouped style maps normalized before validation - [x] Responsive verification batches desktop and mobile evidence in one call - [x] Automatic screenshot previews avoid occupied default ports - [x] Responsive viewport evidence is captured and regression-gated - [x] Accepted evaluation artifacts preserve the best measured token baseline |
||
|
|
e80ca3b54c |
fix: Improve MCP authoring and screenshot reliability (#5957)
Closes #5954 Closes #5951 Closes #5950 Closes #5953 ## Summary - route external screenshot `url` and `baseUrl` targets through the self-closing browser path - keep reusable Chromium sessions limited to Webstudio-managed session previews - validate typed style values at the public runtime boundary while retaining CSS strings for design tokens - build MCP and shell validation messages from compact structured issues - advertise typed style objects with a concrete keyword example - persist `update-asset` metadata patches to the related file record and verify the saved value - store multi-sentence page titles and metadata as fixed text without misclassifying sentence punctuation as member access - capture privacy-safe aggregate token usage and MCP workflow metrics in every high-impact evaluation result - compare each evaluation with a compatible checked-in baseline and fail on correctness, token, tool-use, error/retry, broad-read, or MCP-latency regressions ## Root causes ### External screenshot lifecycle The fast iterative preview change made `session` the default preview source. External captures were then treated as managed session-preview captures and opened a reusable Chromium session. One-shot MCP processes do not call `preview.stop`, so the browser kept the process alive and could be orphaned when the caller killed the hung CLI. ### Validation errors and schemas `update-styles` declared `value` as unconstrained input, and design-token objects were checked only for a string `type`. Invalid values therefore passed the advertised/input schema and failed later in the full `StyleValue` parser, exposing the raw Zod union message. Error serialization already carried flattened issues but did not use them for `error.message`. ### Asset metadata persistence `update-asset` correctly produced an `assets/[id]/meta` patch, but asset persistence compared only Asset-table fields. Metadata lives on the related File row, so the patch was treated as unchanged and the successful mutation never wrote the new value. ### Page text expression disambiguation Page text normalization treated a period followed by whitespace and a word as JavaScript member access. Normal prose such as `Marques. Toutes nos marques` was therefore validated as an expression and rejected instead of being stored as a string literal. ### Evaluation observability The evaluation result only stored duration and two call counts, so token cost, failures, retries, mutation flow, verification coverage, and MCP latency could regress without a durable comparison. Results now use a bounded schema-v2 aggregate and never persist prompts, transcripts, stdout/stderr, credentials, arguments, or response payloads. ## Impact - external screenshots complete without retaining browser processes - repeated managed-preview screenshots retain browser reuse - invalid style inputs fail at the public boundary with paths such as `updates.0.value` - `error.message` is concise and actionable instead of a repeated raw union dump - generated schemas no longer advertise primitive or array values for `update-styles` - supported design-token CSS strings remain accepted - `update-asset` font metadata remains changed after commit, refresh, and reload - `create-page` and `update-page` accept ordinary multi-sentence titles and SEO descriptions while preserving computed expressions - every high-impact run reports input, cached-input, cache-write, output, reasoning-output, total-token, and cache-rate aggregates - MCP results report calls, success/failure, retries, focused/broad reads, dry runs, planned/committed mutations, verifications, total/p50/p95 latency, and first-mutation/verification timing - compatible results are compared with accepted baselines using a 15% relative regression threshold; correctness failures and zero-baseline errors, retries, or broad reads remain zero-tolerance - stochastic wall-clock and milestone timings remain visible as deltas without making a single noisy run fail ## Todo - [x] Reproduce external URL browser-session routing - [x] Use self-closing capture for external screenshots - [x] Preserve browser reuse for managed session previews - [x] Reproduce primitive style-value schema acceptance - [x] Validate typed style values at the public boundary - [x] Preserve CSS-string design-token inputs - [x] Format stdio and shell validation messages from structured issues - [x] Regenerate and verify runtime operation contracts - [x] Reproduce dropped asset metadata at the persistence boundary - [x] Persist and verify related File metadata updates - [x] Reproduce multi-sentence page text failures on create and update - [x] Distinguish sentence punctuation from computed member access - [x] Add privacy-safe token and MCP workflow metrics - [x] Add per-fixture baseline comparisons and regression gates - [x] Refresh accepted schema-v2 baselines for all fixtures - [x] Review the complete diff - [x] Run repository checks and the complete agent evaluation suite ## Verification - `pnpm checks` — passed, including workspace tests, typechecks, lint, package-boundary checks, generated API/docs checks, fixture sync, and fixture builds - builder tests — 189 files, 2,356 tests passed - CLI tests — 53 files, 852 tests passed - project-build tests — 81 files, 2,023 tests passed - asset-uploader tests — 11 files, 98 tests passed - targeted evaluation metrics/regression/trace/runner tests — 5 files, 17 tests passed - all four issue regression tests and the new evaluation harness tests were demonstrated failing without their implementations and passing with them - `pnpm evaluations -- --update-baselines` — 3/3 fixtures passed and schema-v2 baselines were updated - a subsequent real `font-assets-v1` result compared successfully after the regression policy was finalized |
||
|
|
c0687e3323 |
fix: Accept CSS strings in animation keyframes (#5956)
## Summary Allow MCP `update-props` callers to configure `animationAction` keyframes with normal CSS strings, including values such as `transform: "translateX(-75%)"`. Use one SDK-owned animation authoring schema in both the Builder UI and MCP so CSS parsing, timing defaults, and validation cannot drift between entry points. ## Root cause The Builder UI and MCP did not share an authoring contract. Builder controls produced Webstudio's structured style values and animation factories supplied timing objects, while MCP passed its input directly toward the persisted prop schema. As a result, normal CSS strings failed deep Zod validation and omitted timing objects were rejected. ## Implementation - Add a shared `createAnimationActionInput` schema factory to the SDK. - Inject the CSS parser into the schema factory to avoid adding an `sdk` → `css-data` dependency cycle. - Use the shared schema in both Builder animation validation and MCP `update-props`. - Accept raw CSS strings or existing structured Webstudio values in `keyframes[].styles`. - Parse string values before persistence and default omitted animation `timing` to an empty options object. - Update Animation Group guidance and regenerate the runtime operation contract. - Preserve strict validation for existing structured animation style values. ## Checklist - [x] Add regression coverage for the reported horizontal scroll payload. - [x] Verify the regression fails before implementation and passes after it. - [x] Add SDK coverage for shared animation authoring normalization. - [x] Use the shared authoring schema in Builder and MCP. - [x] Verify package boundaries and generated runtime contracts. - [x] Run affected typechecks, targeted tests, lint, and formatting. - [x] Run the complete agent evaluation suite. - [ ] Resolve evaluation read-budget failures: `authenticated-page-v1` and `design-input-v1` failed only `boundedReads`. ## Validation Passed: - `pnpm --filter @webstudio-is/sdk test -- src/schema/animation-schema.test.ts` - `pnpm --filter @webstudio-is/project-build test -- src/runtime/props.test.ts src/mcp.test.ts` - `pnpm --filter @webstudio-is/sdk typecheck` - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm check:package-boundaries` - `pnpm exec oxlint --deny-warnings <changed source and test files>` - `pnpm exec oxfmt --check <changed source and test files>` - `pnpm check:generated-api` - `font-assets-v1` agent evaluation Agent evaluation findings: - `authenticated-page-v1`: failed only `boundedReads`; all functional, audit, binding, privacy, and visual checks passed. - `design-input-v1`: failed only `boundedReads`; all functional, audit, responsive, design-system, privacy, and visual checks passed. - `font-assets-v1`: passed all checks. |
||
|
|
77cb5403a3 |
fix: Allow publishing projects with custom elements (#5955)
## Summary Prevent the pre-publish HTML content-model audit from crashing when a project contains a tag that is not present in the generated HTML metadata. Unknown tags on generic Element instances now produce a non-blocking publish warning. Legacy component instances remain permitted for backward compatibility. Known HTML elements continue to use their existing category and child constraints. ## Root cause The content-model validator indexed `elementsByTag` and immediately read `categories` or `children`. A project tag absent from that dataset returned `undefined`, causing the publishing audit to throw before publishing could continue. ## Impact Projects containing unsupported tags can complete the pre-publish audit instead of failing with an uncaught `categories` error. Invalid generic element tags are still reported, and legacy components are not rejected solely because their rendered tag is absent from current HTML metadata. ## Todo - [x] Safely resolve HTML content-model metadata - [x] Preserve validation for known HTML elements - [x] Warn for unknown generic Element tags - [x] Preserve legacy component compatibility - [x] Add pre-publish audit regressions - [x] Run project-build and builder formatting, lint, typecheck, and tests ## Verification - `pnpm exec oxfmt --check packages/project-build/src/runtime/content-model.ts packages/project-build/src/runtime/pre-publish-audit.test.tsx` - `pnpm exec oxlint --deny-warnings packages/project-build/src/runtime/content-model.ts packages/project-build/src/runtime/pre-publish-audit.test.tsx` - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm --filter @webstudio-is/project-build test` — 81 files, 2,021 tests passed - `pnpm --filter @webstudio-is/builder test` — 189 files, 2,356 tests passed |
||
|
|
0b192c7802 |
fix: Sort style sources with temporary local source (#5949)
## Summary - Allow style sources to be reordered when the displayed local source has not been persisted yet. - Submit only attached style source IDs to the runtime reorder operation. - Add regression coverage for reordering tokens alongside a temporary local source. ## Root cause The style panel displays a temporary local style source until local styles are persisted. Sorting included that temporary ID in the runtime mutation, but the runtime accepts only attached style source IDs and rejected the entire reorder. ## Todo - [x] Filter temporary style source IDs from reorder mutations. - [x] Add regression coverage. - [x] Run targeted tests, lint, formatting, and Builder typecheck. ## Verification - `pnpm --filter @webstudio-is/builder test -- app/builder/features/style-panel/style-source-section.test.ts` — 12 tests passed - `pnpm exec oxlint --deny-warnings apps/builder/app/builder/features/style-panel/style-source-section.tsx apps/builder/app/builder/features/style-panel/style-source-section.test.ts` - `pnpm exec oxfmt --check apps/builder/app/builder/features/style-panel/style-source-section.tsx apps/builder/app/builder/features/style-panel/style-source-section.test.ts` - `pnpm --filter @webstudio-is/builder typecheck`0.282.1 |
||
|
|
5141f61f75 |
fix: prevent mixed router dependencies in MCP previews (#5948)
## Summary
- generate MCP previews from the standalone React Router template
- prevent Remix and React Router runtimes from being merged into one
dependency graph
- keep the normal Remix build path unchanged
## Root cause
The preview generator combined the complete React Router template with
the Remix defaults template. That installed React Router 7 alongside
Remix-provided React Router DOM 6, causing Vite to fail on incompatible
exports before the iterative preview server became ready.
## User impact
`preview.start({ source: "session", mode: "iterative" })` can now start
successfully, so agents can reuse the preview for fast edit, reload,
screenshot, and vision cycles.
## Verification
- [x] Generated a preview from production-size project data and received
HTTP 200
- [x] Verified the generated package contains React Router and no Remix
router dependencies
- [x] 55 targeted CLI preview, screenshot, and MCP preview tests
- [x] CLI typecheck and formatting
- [x] `pnpm checks`
- [x] `pnpm evaluations` (all three real agent fixtures passed)
|
||
|
|
b2a34f1713 |
feat: Fast MCP iterative previews (#5947)
## Summary
This PR documents a measured architecture plan for making the MCP
edit-to-screenshot loop fast enough and reliable enough for iterative
site authoring. It intentionally changes no runtime behavior yet.
The current implementation rebuilds a production preview after small
committed mutations. Testing an editable local clone of the production
Webstudio homepage also exposed a correctness gap: a path screenshot
called directly after a mutation can return a stale, byte-identical
image.
## Measured baseline
Repository fixture:
- committed text edit: **24-25 ms**
- post-edit regeneration, production build, and server restart: **7.9
s**
- first screenshot after restart and browser relaunch: **9.1 s**
- combined first post-edit screenshot: **17.1 s**
- unchanged warm screenshot: **1.1 s**
Production homepage, read-only:
- remote refresh: **3.1 s**
- complete production preview preparation/start: **16.0 s**
- cold homepage screenshot: **10.2 s**
- unchanged warm screenshot: **1.36 s**
- predicted post-edit screenshot from measured phases: **approximately
26.2 s**
Editable local production-homepage clone:
- retained **43 routes** and **266 homepage text nodes**
- committed heading mutation: **0.81-0.87 s**
- explicit post-edit preview generation/build/start: **11.6-12.6 s**
- first screenshot after explicit preview start: **9.8-11.8 s**
- complete mutation-to-visible-screenshot cycle: **22.9-25.2 s**
- complete edit, verify, screenshot, restore, and stop run: **52.7 s**
The changed screenshot visibly rendered the test heading, and the
restored screenshot matched the original byte for byte.
## Correctness finding
Calling a path screenshot directly after the committed mutation took
**20.1 s**, but both post-edit captures were byte-identical to the
baseline and rendered the old heading. Explicitly calling
`preview.start({ source: "session" })` made the edit visible.
The reported generated-build version also remained at 1 while the
project session advanced through versions 4 and 5. Current screenshot
output therefore cannot prove that it rendered the mutation it is meant
to verify.
## Proposed direction
- [ ] Introduce explicit iterative and production preview modes under
one controller contract.
- [ ] Keep a Vite development preview and browser alive for MCP
authoring screenshots.
- [ ] Preserve production preview for rendered audits and final
verification.
- [ ] Regenerate from the authoritative project session, wait for Vite
compilation, then normally reload the retained browser page.
- [ ] Make a direct post-mutation path screenshot refresh the latest
committed session without using HMR.
- [ ] Add a project-version freshness handshake so stale screenshots
fail.
- [ ] Serialize and coalesce regeneration after rapid mutations.
- [ ] Return preview mode, rendered project version, and complete phase
timings.
- [ ] Add lifecycle, integration, and local agent evaluation coverage.
## Performance target
Warm edit-to-screenshot latency should be at most **3 seconds p95**
across ten sequential small edits, without invoking `npm run build`,
`npm run start`, or launching another browser.
## Verification
- [x] Measured the source CLI against the authenticated repository
fixture.
- [x] Measured the production homepage without changing production.
- [x] Synchronized the production bundle into a disposable local Builder
project.
- [x] Committed and visually verified a real heading edit through local
MCP.
- [x] Restored the original heading and verified the restored screenshot
byte for byte.
- [x] Reproduced the stale direct-screenshot behavior.
- [x] Formatted the plan with `oxfmt`.
- [x] Verified the documentation diff with `git diff --check`.
The complete architecture, race handling, test matrix, acceptance
criteria, and non-goals are in
`apps/builder/docs/mcp-iterative-preview-plan.md`.
0.282.0
|
||
|
|
9a087c573a |
fix: use local URLs for expression assets in exports (#5945)
Fixes #5763 ## Description Assets selected directly in a project already use the generated app's configured asset base. Assets referenced through `assets.data[...]`, however, were still emitted with builder-only `/cgi/` URLs, so those references broke in Docker and other self-hosted exports. This makes generated asset resources use the same local asset base as direct asset props while keeping their runtime metadata. The live builder continues to use its existing `/cgi/` routes. ## Steps for reproduction 1. Upload an audio file and reference `assets.data["<asset-id>"].url` from the expression editor. 2. Generate a self-hosted project. 3. Inspect `app/__generated__/$resources.assets.ts`. 4. The asset URL is now `/assets/<filename>` instead of the unavailable `/cgi/asset/<filename>?format=raw` route. ## Testing - `pnpm --filter webstudio test -- src/prebuild.test.ts -t "uses the local asset base"` - `pnpm --filter webstudio exec vite build` - `pnpm exec oxfmt --check packages/cli/src/prebuild.ts packages/cli/src/prebuild.test.ts` - `pnpm exec oxlint --deny-warnings packages/cli/src/prebuild.ts packages/cli/src/prebuild.test.ts` ## Code Review @kof, could you please: - [ ] Review the generated asset URL behavior - [ ] Review the implementation and regression test - [ ] Verify an expression-based asset in a self-hosted preview ## Before requesting a review - [x] Made a self-review - [x] Added a comment explaining why generated exports override the runtime URL - [x] Added a regression test --------- Co-authored-by: Sviat Barbutsa <9897782+sviat-barbutsa@users.noreply.github.com> Co-authored-by: Oleg Isonen <oleg008@gmail.com> |
||
|
|
c3c0e32204 |
fix: make MCP font assets editable and deterministic (#5944)
Closes #5943 Closes #5942 ## User impact MCP-managed font assets now keep their identity, metadata, and generated CSS behavior predictable across upload, editing, synchronization, and rendering. ## Changes - Preserve explicit font metadata overrides while validating supported fields and rejecting unsupported metadata instead of silently dropping it. - Expose font metadata through `update-asset`, with partial updates merged into the existing metadata and validated before the mutation is committed. - Prefer the typographic family name when reading font files, so Fontsource and Google font files resolve to the same logical family where the file provides that information. - Deduplicate generated font sources by URL and format, choose a deterministic source when legacy assets collide, and derive the CSS format hint from the filename when historical metadata is stale. - Add MCP and CLI examples explaining font metadata upload and correction. - Add regression coverage for metadata persistence, invalid overrides, family-name extraction, duplicate source handling, stale format metadata, and generated runtime contracts. ## Verification - `pnpm checks` - 46 workspace packages tested, including 2,355 Builder tests, 809 CLI tests, 2,019 project-build tests, and 97 asset-uploader tests. - All workspace typechecks, Oxlint, package-boundary checks, generated API/docs checks, and fixture link/sync/build checks passed. |
||
|
|
a803aa352d |
fix: expand CSS shorthands in MCP style updates (#5941)
Closes #5940 ## What changed - Route shorthand properties from `update-styles`, `update-design-token-styles`, and shared style mutation helpers through the existing CSS parser. - Store expanded longhand declarations so generated CSS and Builder editing use the same data model as JSX fragment insertion. - Preserve breakpoint, pseudo-state, and listed metadata across generated declarations. ## User impact MCP-authored shorthands such as `inset` and `grid-area` no longer disappear from generated CSS or remain as declarations the Builder cannot edit. The three style authoring paths now produce consistent, editable project data. ## Verification - `pnpm --filter @webstudio-is/project-build test` (2,015 tests) - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm oxfmt --check packages/project-build/src/runtime/styles.ts packages/project-build/src/runtime/styles.test.ts` - `pnpm oxlint --deny-warnings packages/project-build/src/runtime/styles.ts packages/project-build/src/runtime/styles.test.ts` - `git diff --check` |
||
|
|
7eb58664b0 |
fix: harden asset folder uploads and selection (#5939)
## Summary Fixes folder uploads and asset-manager selection behavior. ## Changes - Preserve folder IDs for newly uploaded assets. - Place duplicate assets into the dropped folder, including server-side deduplication and assets already uploading. - Handle browser `NotFoundError` cases while reading dropped directories. - Keep lasso selection anchored correctly while scrolling. - Add `Cmd/Ctrl+A` to select all currently rendered assets and folders. - Document the new shortcut in the keyboard shortcuts dialog. - TIFF support was removed in the base branch. ## Verification - [x] Asset upload and directory-drop tests - [x] Asset-manager tests - [x] Keyboard shortcuts dialog tests - [x] Builder typecheck - [x] Formatting and diff checks |
||
|
|
085f705cc4 |
fix: remove unsupported TIFF assets (#5938)
## Summary - Remove `.tif` and `.tiff` from supported asset extensions. - Stop categorizing TIFF files as images in the asset manager. - Update SDK URL coverage to reflect the supported direct-served image formats. ## Why The asset manager classified TIFF files as images, but the browser and image optimization pipeline cannot reliably render TIFF thumbnails. Treating TIFF as supported created broken previews. ## Verification - SDK asset tests: 95 passed - Formatting completed - Diff checked against `main` |
||
|
|
54aa7be145 |
fix: Make MCP authoring reliable across assets, styles, and embeds (#5932)
Closes #5924 Closes #5925 Closes #5926 Closes #5927 Closes #5928 Closes #5929 ## Outcome Makes MCP and CLI authoring predictable across project-wide CSS variables, font uploads, retried asset uploads, destructive asset selection, design-token collisions, and SVG HtmlEmbed edits. ## Delivered ### Project-global CSS variables - [x] `define-css-variable` writes to `ROOT_INSTANCE_ID` / `:root` instead of the home-page Body. - [x] Breakpoint and overwrite behavior is preserved, and compact results identify the root scope. - [x] Existing body-local declarations remain untouched. - [x] Runtime and Builder integration tests cover root selection and generated project behavior. ### Font metadata and upload overrides - [x] Static fonts prefer authoritative `OS/2.usWeightClass`. - [x] Fallback matching normalizes spaces, hyphens, and underscores and checks specific aliases before shorter ones. - [x] Explicit format and partial metadata overrides travel through HTTP, filesystem, and S3 upload paths and are validated after merging with detected metadata. - [x] Regression tests cover ExtraBold, Extra-Bold, Semi Bold Italic, Ultra Light, valid weight classes, invalid weight classes, partial overrides, and invalid overrides. ### Idempotent asset uploads - [x] API uploads compute a project-scoped SHA-256 content hash. - [x] Sequential and concurrent duplicate uploads reuse the existing asset and return `deduplicated: true`. - [x] `force: true` bypasses deduplication for intentional duplicates. - [x] A partial unique index enforces one non-null content hash per uploader project. - [x] Stale reservations are cleaned up and active concurrent uploads are bounded by polling and an actionable retry error. - [x] HTTP, protocol, uploader, and CLI tests cover hash reuse, uniqueness races, force propagation, and result markers. The migration does not backfill historical files. Existing assets begin participating in deduplication when uploaded through the new path; matching content keeps the existing asset's metadata rather than silently rewriting it. ### Consistent asset inputs and permissions output - [x] `delete-asset` exposes exact `assetIds` and explicit `assetIdPrefixes`. - [x] The legacy `assetIdsOrPrefixes` input remains accepted and is marked deprecated. - [x] Exact ids no longer accidentally select longer prefixed ids. - [x] `webstudio permissions` prints a readable role/capability summary by default while `--json` remains unchanged for machine callers. - [x] Help and discovery describe JSON output as optional. - [x] Runtime, CLI, metadata, and generated-contract tests cover canonical and compatibility behavior. ### Deterministic fragment design tokens - [x] Fragment insertion reconciles incoming tokens against project tokens and earlier tokens in the same fragment. - [x] Equal name/style tokens are reused instead of creating suffixed twins. - [x] Same-name/different-style fragments require an explicit `ours`, `theirs`, or `merge` policy at the public runtime boundary. - [x] Builder's established internal paste behavior retains its explicit incoming-value default. - [x] `create-design-token` accepts documented CSS strings through the property-aware CSS parser as well as typed style values. - [x] Tests cover same-fragment reuse/conflicts, persisted tokens, explicit policies, and CSS string parsing. ### Editable SVG HtmlEmbed content - [x] HtmlEmbed validation uses parse5 parser errors and source structure instead of serialization-string equality. - [x] Valid inline SVG is accepted without silently normalizing authored markup. - [x] Fragment insertion now uses the same validator as prop update and text replacement paths. - [x] Malformed markup is rejected before mutation. - [x] Regression tests cover realistic SVG, parser failures, and no-partial-mutation behavior. ## Verification - [x] `pnpm checks`: all workspace tests, typechecks, lint, package boundaries, generated API/docs checks, and fixtures passed on the final committed tree. - [x] `pnpm --filter webstudio test:release-smoke`: packaged install, compact comparison, preview, agent workflow, stdio MCP, and structured commands passed. - [x] Prisma schema validation passed with test connection variables. - [x] Two minimally prompted weak-model subagents independently exercised the changed CLI/MCP discovery and focused workflows. - [x] The subagent-found stale `permissions --help` requirement was fixed, regression-tested, and retested. - [x] Final diff and worktree are clean. |
||
|
|
918e569fd4 |
fix: Show publish warnings immediately (#5935)
## Summary Show client-side pre-publish audit findings as soon as the user starts publishing, and apply the Builder's standard text styling to warning banners. ## Root cause The cloud publish audit ran inside an async form action, while the static export audit ran inside an async transition. React deferred their ordinary state updates until those async operations completed, so warnings could appear only after publishing or export finished even though validation itself ran synchronously on the client. ## Changes - Run the cloud publish audit in the synchronous button click handler before starting the async publish transition. - Run the static export audit before starting its async transition. - Keep warnings non-blocking while preserving blocking audit errors. - Render warning-banner content with the design-system `Text` component. ## Checklist - [x] Show cloud publish warnings before publishing starts - [x] Show static export warnings before export starts - [x] Style warning text consistently - [x] Run Builder tests - [x] Run Builder typecheck - [x] Run lint and formatting checks ## Verification - `pnpm --filter @webstudio-is/builder test` — 2,351 tests passed - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm exec oxlint --deny-warnings apps/builder/app/builder/features/publish/publish.tsx` - `pnpm exec oxfmt apps/builder/app/builder/features/publish/publish.tsx` |
||
|
|
f08cc01c9f |
fix: Preserve tokens when pasting Slot content (#5934)
## Summary Preserve design-token selections on instances nested inside pasted Slot content. ## Root cause Token style sources receive new or reused IDs during fragment insertion. Regular copied instances applied that token ID mapping to their style-source selections, but preserved Slot/portal content copied selections with the stale clipboard IDs. As a result, an Accordion's shared HtmlEmbed icon could lose its visible token after pasting the whole Accordion even though pasting the icon alone worked. ## Changes - Pass the token style-source ID map into Slot/portal style insertion. - Remap token IDs while preserving local style-source IDs. - Add unit coverage for portal selection remapping. - Add a fragment-level regression test using a tokenized HtmlEmbed inside a Slot. ## Checklist - [x] Remap token selections in pasted Slot content - [x] Add regression coverage - [x] Run project-build tests - [x] Run project-build typecheck - [x] Run lint and formatting checks ## Verification - `pnpm --filter @webstudio-is/project-build test` — 1,993 tests passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm exec oxlint --deny-warnings packages/project-build/src/runtime/style-copy.ts packages/project-build/src/runtime/fragment.ts packages/project-build/src/runtime/style-copy.test.ts packages/project-build/src/runtime/fragment.test.tsx` - `pnpm exec oxfmt packages/project-build/src/runtime/style-copy.ts packages/project-build/src/runtime/fragment.ts packages/project-build/src/runtime/style-copy.test.ts packages/project-build/src/runtime/fragment.test.tsx` |
||
|
|
4ea8928880 |
fix: preserve legacy content through validation (#5933)
## Summary - Keep the shared content-model validator strict during normal Builder authoring. - Report HTML and component nesting violations as publish warnings instead of blocking legacy projects. - Allow paste operations to retain violations already contained inside legacy fragments and surface them as warnings. - Continue rejecting new violations introduced at the paste destination boundary. - Remove obsolete empty content models from CodeText and Video so their runtime-supported, HTML-valid children pass validation. ## Root cause The new pre-publish audit applied current authoring constraints to historical project trees. Some legacy structures, including old Accordion triggers containing an h3 inside a button, were created by earlier Webstudio templates and cannot satisfy the current HTML model without migration. Blocking publish or paste would make untouched legacy content unusable. CodeText and Video also had metadata that rejected children their renderers intentionally support. Those verified metadata mismatches are corrected independently of the compatibility policy. ## Behavior - New invalid nesting remains prevented by normal authoring operations. - Existing invalid nesting produces a Publish warning and does not abort publishing. - Webstudio instance, HTML, JSX, and Webflow paste retain fragment-internal violations and show a paste warning. - Paste still validates the destination and cannot introduce a new invalid parent-child relationship. - Resource integrity and missing audit inputs still prevent publishing. ## Verification - [x] Legacy button containing h3 reports a publish warning - [x] Legacy invalid subtree pastes successfully with a warning - [x] New paste destination violations remain rejected or use the closest valid target - [x] Valid legacy CodeText children pass validation - [x] Valid Video source and track children pass validation - [x] Project-build matcher and insert-target tests - [x] Builder instance, HTML, JSX, and Webflow paste tests - [x] Project-build and Builder typechecks - [x] Focused oxlint and formatting checks |
||
|
|
620f8b54ed |
feat: Create blank text assets (#5931)
## Summary - add a **Create text file** action to the Assets toolbar and shared context/dropdown menu - validate filenames against the central editable-asset registry, create the empty file in the current asset folder, and open it in the text editor - keep simultaneous empty uploads distinct by including the filename in the upload fingerprint - keep internal Nano ID storage suffixes out of visible asset names and subsequent content revisions - show the immutable file extension beside the editable basename in Asset settings Asset querying, content hydration, structured data, bindings, generated runtime support, and MCP integration remain owned by #5921. ## Verification - Builder asset/text tests: 34 passed - SDK asset tests: 110 passed - project-build asset tests: 71 passed - asset-uploader revision tests: 5 passed - SDK, project-build, asset-uploader, and Builder typechecks - lint and package-boundary checks Ref #5824 |
||
|
|
5016426bfb |
fix: Preserve resource URL expression formatting (#5916)
## What changed - preserve the user’s original whitespace and newlines in resource URL binding expressions ## Change of plan Automatic expression formatting is not needed. Prop binding expressions already preserve user-entered formatting; only resource URL bindings were losing their newlines. This PR aligns resource URL bindings with the existing prop binding behavior and does not add a formatter or change expression formatting rules. ## Root cause The resource URL expression was stored in an input hidden with the HTML `hidden` attribute. Because its input type still defaulted to `text`, the browser value-sanitization algorithm removed newline characters before the form was serialized. The URL form field now uses `type="hidden"`, which preserves the original expression during form submission. ## Validation - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm lint` - `git diff --check` Closes #5858 |
||
|
|
cfba520e6d |
feat: Open text assets in code editor (#5918)
## What changed - open every textual asset type from the upload registry in an editable CodeMirror dialog - select installed CodeMirror language support by MIME type and use plain text editing as the fallback - support `txt`, `csv`, `md`, `js`, `css`, `json`, `html`, `xml`, and `svg` without adding asset-specific language branches to the shared editor - keep the canvas mounted and interactive behind the dialog - persist edits on blur, `Cmd/Ctrl+S`, or `Cmd/Ctrl+Enter` through the asset replacement pipeline - preserve folder and description metadata and repoint supported asset references - clean up failed replacement uploads instead of leaving orphan assets ## Impact Users can open, edit, and persist all text-based upload formats directly in the builder without replacing or reloading the canvas. New `text/*` upload types will automatically become editable as plain text; installed syntax support is selected by MIME type. ## Validation - `pnpm --filter @webstudio-is/builder test -- app/builder/features/text-file-editor/text-file-utils.test.ts app/builder/shared/assets/replace-asset.test.ts app/builder/shared/asset-manager/asset-manager.test.tsx` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm exec oxlint --deny-warnings <changed files>` - `pnpm exec oxfmt --check <changed files>` - `git diff --check` - verified the running dev server applied the changes through Vite HMR Ref #5824 |
||
|
|
9ce325b94c |
feat: Deep-link Builder instances (#5923)
## Summary - add optional `instanceId` support to the shared Builder link parameters used by `builderPath` and `builderUrl` - synchronize the selected instance into the Builder URL without adding a browser-history entry for every selection - restore the selected page and full instance selector when opening an instance deep link - render a **Show element** link for pre-publish audit findings that identify an instance - switch to the affected page, select and scroll to the instance, and close the publish popover when the link is used ## Why The pre-publish audit introduced in #5922 identifies the invalid page and instance, but its error was text-only. Users still had to locate the offending element manually. A shared instance deep-link parameter also makes these links copyable and reusable outside the audit UI. ## Impact Builder URLs can now include `instanceId` alongside `pageId`. Existing page-opening links continue using the same central `builderPath`/`builderUrl` abstraction. Missing or stale instance IDs safely fall back to the requested page. ## Validation - focused Builder tests passed (4 tests) - `@webstudio-is/builder` typecheck passed - focused Oxlint passed - focused Oxfmt check passed - `git diff --check` passed |
||
|
|
be906afb5b |
fix: validate projects before publishing (#5922)
## Summary - add a reusable pre-publish audit pipeline with normalized findings and extensible checks - validate HTML content-model nesting and existing resource integrity before regular and static publishing - identify the affected page and instance in invalid-markup errors - move generated HTML formatting from automatic `postbuild` to the explicit local `build:debug` command ## Root cause A project contained an invalid stored component hierarchy, with an `h2` nested inside a paragraph. The Builder did not run a holistic content-model validation before publishing, so the invalid hierarchy reached static generation. The static fixture then ran `oxfmt` automatically during `postbuild`; its parse failure made the otherwise completed static build fail. ## Impact Users now see a specific Builder error before publishing, including the affected page and invalid nesting. Static publish CI no longer formats generated HTML automatically, while developers can still produce formatted output locally with `pnpm build:debug`. ## Validation - 65 focused project-build tests passed - `@webstudio-is/project-build` typecheck passed - `@webstudio-is/builder` typecheck passed - focused Oxlint passed - focused Oxfmt check passed - `git diff --check` passed |
||
|
|
0070fa66a1 |
ci: deduplicate builder E2E setup (#5917)
## What changed - reuse the shared CI setup action in both Builder E2E jobs - use one build command for CI and local E2E runs - centralize shard filename parsing and suite-name formatting - remove redundant suite-level shard filtering - parse each E2E filename's shard metadata once ## Why The merged image-asset PR introduced multiple owners for Builder E2E setup, build dependencies, and shard filename semantics. Consolidating them prevents CI and local behavior from drifting as the shard layout evolves. ## Validation - `pnpm --filter=@webstudio-is/builder test -- e2e/test-modules.test.ts` - `pnpm --filter=@webstudio-is/builder typecheck` - `pnpm lint` - `pnpm e2e:builder:build` - shell syntax and YAML parsing - shard discovery returned shards 1–6 |
||
|
|
597642ac2e |
fix: Accept numeric page status codes (#5915)
## Summary - accept fixed page status codes as JSON numbers from 200 through 599 - preserve dynamic status expressions and backwards-compatible numeric strings - remove a stored status when the Builder input is cleared, while leaving omitted status values untouched - advertise the correct number-or-expression contract through runtime and MCP schemas - update CLI guidance and examples to use numeric status values ## Testing - `pnpm --filter @webstudio-is/project-build exec vitest run src/runtime/pages.test.ts src/contracts/builder-runtime.test.ts src/mcp.test.ts` - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` Closes #5913 |
||
|
|
ef94d85ccf |
feat: drag image assets onto canvas (#5912)
## Summary - allow dragging a single image asset from the Assets panel onto the canvas - insert an Image component with its source bound to the dragged asset in one undoable mutation - preserve asset-folder drops and canceled drags - build the Builder once in CI and reuse the compact build artifact across all E2E shards ## E2E timing Recent CI showed shard test runtimes of roughly 101–145 seconds, while every shard also repeated a roughly two-minute Builder build. The four shards are already reasonably balanced, so a fifth shard would not address the primary bottleneck. The shared artifact is about 30 MB uncompressed and roughly 5 MB compressed because checked-out public assets are excluded. This should return individual shard jobs to the 2–3 minute range. ## Validation - 45 focused unit tests - image asset to canvas E2E using the prebuilt-artifact path - image asset to folder regression E2E - Builder typecheck - lint - package-boundary validation - workflow YAML validation - shell syntax validation |
||
|
|
7d7c23d30a |
fix: Center empty asset folder drop state (#5911)
## Summary - center the reusable “Drop files here” state against the full empty-folder area - keep the Back thumbnail independently positioned and interactive - add regression coverage for empty folders with additional content - add a fourth builder E2E shard and split the serial asset-folder workflows using measured CI durations ## Root cause The Back thumbnail participated in the same column flow as the drop state, reducing the drop state’s available height and shifting its center downward. The asset-folder E2E module also accumulated ten serial workflows and became shard 1’s 214-second bottleneck. ## User impact Empty folders now align the drop message consistently with the root empty state and full-panel drag overlay. The E2E split reduces shard 1’s measured workload from about 230 seconds to a projected 113 seconds, with shard 4 at about 100 seconds. ## Validation - focused asset tests: 62 passed - E2E shard discovery test - shard 1 and shard 4 module loading - builder typecheck - workspace typechecks - lint - package boundaries - generated API and docs checks - fixtures - full workspace tests; three CLI subprocess tests initially timed out under concurrent load and passed when rerun in isolation |