mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-08 21:15:18 +09:00
70dd67e2b395e12267a08043597e8f765efa72e4
2478
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a836f29a69 |
fix: Explain asset count limits (#6149)
## Summary Return a specific, safe error when a project reaches its plan's asset-count limit instead of reporting an internal Assets API failure. ## Root cause The uploader enforced `maxAssetsPerProject` by throwing a plain `Error`. The REST boundary correctly treated unknown errors as internal failures, returned HTTP 500, and redacted the useful limit explanation. The Builder then displayed that generic response. ## Technical choices - Represent the expected quota condition with `AssetUploadCountLimitError`. - Map that domain error to HTTP 409 while preserving its existing message. - Keep the generic HTTP 500 response and server logging for unexpected failures. - Reuse the Builder's existing API-error handling; it already displays the returned `errors` value in the upload toast. ## Checklist - [x] Reproduce the generic uploader and REST error behavior - [x] Add regressions and verify they fail before the behavior change - [x] Throw a typed error when the asset-count limit is reached - [x] Return the safe limit explanation through the Assets API - [x] Verify unexpected internal errors remain redacted - [x] Review documentation impact — no documentation change is needed for this error-message correction - [x] Review fixture impact — no fixture inputs or generated outputs are affected - [x] Review the final diff for unrelated changes and duplicated logic ## Verification - `pnpm --filter @webstudio-is/asset-uploader test` — 196 tests passed - Asset uploader typecheck passed - Targeted Builder Assets API and upload client tests — 37 tests passed - Builder typecheck passed - `pnpm lint` Closes #6148 |
||
|
|
cb51d477e1 |
fix: Refresh resource diagnostics metadata (#6113)
## Summary Follow up on #6095 so explicit Diagnostics refreshes update both diagnostic and performance metadata, stale refreshes are cancelled during invalidation, and Assets batch measurements are labeled consistently in the Builder. Ref #6092 ## Technical choices - Cache response diagnostics and performance metadata through one shared path. - Attach an AbortController to each explicit diagnostics request and reject stale results after invalidation. - Accept additive performance fields from newer servers. - Clarify that Assets timings and counters cover the combined batch. - Reuse the measured view-authorization path across repository entry points. ## Implementation checklist - [x] Refresh performance metadata with explicit diagnostics. - [x] Cancel and ignore stale diagnostics requests. - [x] Keep performance parsing forward-compatible with additive fields. - [x] Clarify Assets batch labels and descriptions. - [x] Add regression coverage for refresh, invalidation, and parsing behavior. - [x] Review documentation impact — authoritative `docs/` does not cover this internal Diagnostics tooling, so no update is required. - [ ] Run affected Builder and asset-uploader typechecks. - [ ] Confirm GitHub checks pass. ## Verification - Builder diagnostics/resource tests: 27 passed. - Asset repository tests: 39 passed. - `git diff --check origin/main...HEAD` — passed. |
||
|
|
db2d092268 |
ci: replace Lost Pixel with self-hosted visual regression (#6086)
## Summary Replace the defunct Lost Pixel service and the interim Chromatic workflow with a fast, self-hosted visual comparison pipeline. The workflow indexes the existing CSF stories without building Storybook, builds and serves a lightweight browser app with Vite, renders the merge base and current revision through Webstudio's shared browser tooling, and compares screenshots with Webstudio's pixel-diff and OCR engine. It uses GitHub Actions cache and artifacts only—no R2 bucket or external visual-testing service. Closes #6064 ## Implementation - [x] Remove the Lost Pixel workflow, configuration, acknowledgement, and global two-second wait. - [x] Remove the interim Chromatic workflow and settings. - [x] Extract source-agnostic capture, diff, OCR, audit, cache, and report tooling into `@webstudio-is/vision`; rename the Webstudio-specific preview boundary to `@webstudio-is/project-build/preview`. - [x] Expose the reusable browser capture session through the shared vision boundary. - [x] Make OCR and diff-artifact generation conditional on detected pixel changes. - [x] Render existing CSF stories through a typed, lightweight browser harness built with Vite. - [x] Replace the embedded HTML and handwritten HTTP/MIME server with a real HTML entry, Vite production build, and Vite preview server; isolate declarative build configuration in `story-build.ts`. - [x] Apply Storybook preview annotations, decorators, global CSS, backgrounds, and story metadata. - [x] Store story scopes as shared data and load each revision's own configuration. - [x] Discover changed, added, and removed stories from both revisions. - [x] Populate private story sources symmetrically in the baseline worktree. - [x] Isolate every story with a fresh React root and deterministic time, randomness, intervals, focus, animation, and layout readiness. - [x] Preserve story-owned visual options for masking, settling, and interval control. - [x] Reuse Vite preview servers, one Chromium process, grouped browser pages, production bundles, and a bounded CPU worker pool for image comparison. - [x] Recheck initial pixel differences with serial captures, then recapture persistent baseline/current pairs on the same browser page so renderer variance cannot create false failures. - [x] Report individual story render failures without discarding successful captures. - [x] Enforce a 0.1 per-pixel threshold and 0.001% total mismatch tolerance. - [x] Run OCR only for changed comparisons and include text-change evidence. - [x] Move the generic report model, writer, static viewer, and opener into the shared Vision package for reuse by CI and future CLI comparisons. - [x] Bundle report HTML, styling, and browser behavior as static Vision assets without runtime source-file lookups. - [x] Copy external screenshot inputs into self-contained report artifacts for CLI reuse. - [x] Handle cached removed-only comparisons without rendering the removed story on the current server. - [x] Support focused local reproduction and opening the report with one command. - [x] Pin CI to the lockfile's Playwright Chromium, cache complete revision screenshots with matching restore/save paths and automatically derived runtime invalidation, and render both revisions on a miss. - [x] Keep cache archives bounded to one revision instead of accumulating the cache history. - [x] Run the complete visual suite in one CI job and upload one report as a 14-day artifact. - [x] Fail PR checks on visual differences, empty runs, missing screenshots, missing or empty report artifacts, and infrastructure failures. - [x] Rerun fork checks when `safe-to-deploy` is added. - [x] Allow reviewed visual-only differences through `visual-change-approved` and invalidate approval after new commits. - [x] Keep capture, pixel diff, OCR, and report generation source-agnostic for future draft-versus-published project comparisons. - [x] Use Vite for the complete story HTML, module, asset, production-build, and preview-server lifecycle; inline the selected stories and skip ineffective tree-shaking to keep the cached run under one minute. - [x] Review Builder product documentation impact: no user-facing Builder documentation is affected; contributor usage is documented in `scripts/visual-regression/README.md`. - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected. ## Verification - [x] Project-build Vision tests, including the reusable report test, and entrypoint contract tests pass. - [x] CLI screenshot, preview, and browser-session tests pass. - [x] Project-build, CLI, Builder, design-system, and visual-runner typechecks pass. - [x] Visual runner tests pass (10), and the complete Vision package passes (79), including demonstrated fail-before/pass-after coverage. - [x] Full Storybook production build passes. - [x] Full local Vite run completes all 238 stories in 69.9s cold and 50.3s with a cached baseline plus two same-page serial verifications, with zero differences; identical-image comparison remains sub-second. - [x] The report writer passes a bundled-output smoke test and materializes external screenshot assets. - [x] The generated report validates all 238 entries and referenced images. - [x] Hosted cached-baseline comparison completes all 238 stories in 52.9s with zero differences; the cache-miss fallback completes in 101.3s. - [x] Cache-miss fallback renders both Git revisions on demand. - [x] Visual differences produce baseline, current, diff, OCR, JSON, and HTML evidence and fail without approval. - [x] Hosted single-job visual workflow restores both the pinned browser and baseline cache, validates all 238 public and private stories with zero differences, and uploads the report. - [x] The final Vite production build renders all 238 stories without dependency invalidation or duplicate React runtimes, and restores `NODE_ENV` so cached serial fallback installs the baseline's dev dependencies. - [x] Root lint, package-boundary validation, and relevant formatting checks pass. - [x] Workflow YAML parses successfully. - [x] `git diff --check`, staged-diff review, and final worktree review pass. ## Usage Run the complete local comparison and open the visual report: ```sh pnpm visual-regression:ui ``` Focus one component while iterating: ```sh pnpm visual-regression:ui -- --grep "Design system/Button" ``` Reopen the latest report without rerunning: ```sh pnpm visual-regression:report ``` The CI report is available as the `visual-regression-report` artifact. ## Tradeoffs - Baseline screenshots are a disposable acceleration cache, not source of truth. A missing or invalid cache renders the merge base directly from Git. - GitHub artifact storage provides downloadable one-click reports; permanently hosted browser links would require another hosting surface. - OCR runs after pixel triage because invoking Tesseract for every unchanged story would make the common path unnecessarily slow. - Vite production builds add Rollup's module graph and HTML/asset pipeline. The runner emits one bundle because every selected story is rendered, and skips tree-shaking because it removed little while increasing build time. - The verified local path is 50.3s cached and 69.9s cold. The hosted path is 52.9s cached and 101.3s cold. A new browser/runtime cache must render its baseline once; the pinned browser keeps later runners on the reusable path. - The complete suite stays in one Actions job; browser-page concurrency is internal and bounded. |
||
|
|
11d76eb43d |
perf: Diagnose and reduce Assets resource latency (#6095)
## Summary Adds Builder-only resource performance metrics to grouped Diagnostics tables, removes duplicate object-store reads from the Assets query path, scopes compiled-artifact reuse to one repository request, and compiles unpinned Builder previews from their concrete query values instead of hydrating the complete saved dynamic deployment plan. Nothing is precomputed or retained in a warm serverless process after the request finishes. Ref #6092 ## Technical choices - Keep `__performance__` as internal response metadata and strip it before resource values enter expression-visible caches. - Record Builder round-trip, server duration, response size, Assets phases, document work, completed storage reads, and cumulative compiler/document-graph storage-read durations. - Present Diagnostics as collapsible sections ordered Database and sizes, Timing, Query work, then detailed database/result inspectors. Open only the first available section by default. Every metric keeps an explanatory tooltip, with info icons revealed only when the label cell is hovered or keyboard-focused. - Add a copy action to every section header. It copies that section's raw structured data as formatted JSON without opening a collapsed section. - Keep Index preparation as an inclusive parent duration and explain that relationship in Diagnostics. - Compile ordinary unpinned Builder preview requests from a union of their concrete query values. A detail route therefore hydrates only documents that can satisfy that request. - Continue using the saved artifact-producing plan for revision-pinned requests. - Keep publication and prepublication preparation unchanged. - Load only `props`, `dataSources`, and `resources` when constructing the single-query Builder preview plan, matching the already-narrow batch path instead of downloading and parsing the complete dev Build row. - Build the deployment-wide saved plan only when detailed Diagnostics requests its Published database statistics. Report that work as the separate inclusive `Published diagnostics` timing and exclude its child phases and fetch counters from the normal query measurements. - Reuse successfully read content bytes across compiler preparation, document graph construction, and runtime resolution within one query or batch. Graph-fetched bytes are size-validated before entering the revision-keyed request map, and graph additions stop when the request cache reaches the 2 MiB hydrated-content limit. - Before repairing canonical metadata, load candidate metadata once and prove its revision, base document, and prepared metadata tier match the open source snapshot. Skip synchronization when it is already current; retain recovery and repair for stale, missing, insufficient-tier, or inconsistent rows. - Key request-local bytes by content reference and revision so source-change retries cannot reuse stale data. - Instantiate compiled-artifact reuse per `PostgresAssetRepository`; repeated preparations inside one request can reuse or coalesce work, but later requests and other serverless instances cannot. - Remove the module-level 32-entry compiled-artifact cache introduced in #5946. - Introduce no precomputed, persisted, process-local, or cross-request content cache. ## Findings and measurements The supplied production post resource was bimodal before removing the process cache: - Warm process: approximately 1.0–1.5 seconds. - Cold process: approximately 5.7–6.7 seconds. - Ordinary response: approximately 4.6 kB. The earlier development capture was a process-cache hit: 542.6 ms server time and 932.5 ms Builder round trip. A later hit measured 491.5 ms server time and 739.1 ms round trip. Those results demonstrated the old module cache's nondeterministic serverless behavior rather than cold-path performance. After request-scoped reuse replaced the process cache, the supplied cold capture measured 3,848.5 ms server time. Index preparation was 3,259.7 ms. The saved dynamic plan caused 25 compiler content fetches and 301 kB of compiler input even though the concrete post query resolved only two documents. The published database contained 28 documents and used 45.4 kB bounded / 512 kB unbounded. Tracing compilation also exposed duplicate request-time I/O: selected Markdown was fetched for compiler input, document graph construction, and runtime document resolution. Request-local byte reuse changes that representative path from three object-store reads to one. The remaining dominant issue was therefore query breadth, not response serialization or runtime result resolution. The Builder was compiling the deployment-wide dynamic plan to answer a concrete post request. The new preview path compiles the concrete values; regression coverage demonstrates that a saved two-post dynamic plan reads only `post-a` when previewing `post-a`. The next cold capture confirmed that change: Builder round trip fell from 4,391.4 ms to 2,245.2 ms, server duration from 3,848.5 ms to 1,601.8 ms, and index preparation from 3,259.7 ms to 1,044.9 ms. Compiler content fetches fell from 25 to 1 and document-graph content fetches from 3 to 1. Canonical metadata remained 239.2 ms because an unchanged request still performed a repair synchronization round and then loaded the same stored metadata again. The new fast path reduces that normal case to one recovery-safe candidate metadata read. A subsequent capture confirmed the canonical metadata fast path: server duration fell from 1,601.8 ms to 1,401.0 ms, index preparation from 1,044.9 ms to 684.8 ms, and canonical metadata from 239.2 ms to 74.7 ms. The post query remained narrow at one compiler fetch and one document-graph fetch. Builder round trip rose from 2,245.2 ms to 2,411.1 ms while the server improved, so that difference is outside the measured server work and is consistent with browser/network/development-environment variance. At that point `buildPlan` was the largest remaining isolated phase at 242.8 ms. Single-query preview was still loading every dev Build column and parsing pages, styles, instances, deployment data, and other fields that are not inputs to the Assets compilation plan. The narrow loader now requests and parses only the three content-engine fields used by plan construction. The next capture confirmed that optimization: build plan fell from 242.8 ms to 99.0 ms, server duration from 1,401.0 ms to 1,056.8 ms, and the concrete post query remained at one compiler fetch and one document-graph fetch. Index preparation stayed effectively flat at 679.7 ms, making compiler entries (142.3 ms), source snapshot (119.2 ms), source validation (119.1 ms), and document graph (114.0 ms) the next candidates. The new child timings separate cumulative storage waiting from the remaining compiler/document-graph work before choosing another behavioral optimization. The storage timing capture then showed that I/O dominated the remaining compiler and graph phases: compiler storage was 114.6 ms of 125.9 ms, while document-graph storage was 114.0 ms of 147.6 ms. The graph path consulted compiler-cached bytes but did not retain newly fetched graph documents, so runtime reference resolution fetched the same two-document chain again. Retaining validated graph bytes in the same request reduces the regression fixture from four physical object-store reads to two without changing its resolved result. Final three-run measurements after same-request graph-byte reuse were stable: median Builder round trip was 926.2 ms, median server duration was 681.9 ms, median index preparation was 407.9 ms, and median document resolution was 3.7 ms. Compared with the uncached 3,848.5 ms server / 3,259.7 ms index baseline, that is approximately 82% less server time and 87% less index-preparation time for this post query. A final DRY/correctness review centralized request-local byte-cache keying and its 2 MiB accounting, removed repeated Diagnostics size rows and SDK metadata assembly, typed phase keys, and corrected response-size measurement so internal performance metadata is excluded as the UI promises. The module cache was also only bounded for completed entries. Many simultaneous unique-project compilations in one process could exceed 32 pending entries until they settled. Scoping reuse to one repository request removes cross-user retention and tenant cache competition while preserving duplicate-work elimination inside the request. ## Todo - [x] Add generic resource timing and response-size metrics. - [x] Add Assets phase, document graph, source validation, storage-read count/byte metrics, and compiler/document-graph storage-read durations. - [x] Render ordered collapsible Diagnostics sections with only the first open by default, per-metric explanations, interaction-only info icons, and per-section JSON copy actions. - [x] Reuse compiler and document-graph content bytes through runtime resolution within the current request, without precomputation. - [x] Remove cross-request process caching and retain request-scoped compilation reuse. - [x] Compile unpinned previews from concrete query values. - [x] Separate deployment-wide diagnostic preparation from normal query phase counters. - [x] Skip redundant canonical metadata synchronization when stored candidates already match the source snapshot and requested tier. - [x] Narrow single-query Build reads to the three fields required by Assets plan construction. - [x] Expose cumulative compiler and document-graph storage-read timing as explained child rows. - [x] Add regression coverage, including red/green verification. - [x] Review the final diff for correctness, duplication, and unnecessary complexity. - [x] Verify concrete-query compilation against the supplied post resource: compiler fetches fell from 25 to 1. - [x] Remeasure the canonical metadata fast path: canonical metadata fell from 239.2 ms to 74.7 ms and index preparation from 1,044.9 ms to 684.8 ms. - [x] Review documentation impact: no authoritative `docs/` page covers this internal Diagnostics tooling, so no documentation update is required. - [x] Run focused tests, affected package typechecks, lint, formatting, and the fixture pipeline. ## Verification - Content engine tests: 23 passed. - Asset uploader tests: 195 passed, including repository, canonical synchronization, request-cache, and storage-timing coverage. - Builder focused Diagnostics tests: 10 passed in the latest storage-timing pass; 15 passed in the preceding final pass and 35 across the earlier instrumentation scope. The collapsible view test verifies section order, default state, and deferred content interaction. - Project tests: 84 passed, including 5 focused preview tests. The focused regression failed against the full-Build loader and passed after switching the single-query path to the narrow content-engine loader. - SDK resource loader tests: 24 passed. - Current canonical metadata regressions failed under the old always-synchronize expectations and pass with one metadata load and no synchronization; stale metadata still exercises and passes the repair fallback. - The Timing clipboard test failed with an empty payload and passed with the complete raw duration/phase JSON; copying a collapsed section is also verified not to open it. - The collapsible default-state test failed when Timing was temporarily opened alongside Database and sizes, then passed after restoring the first-section-only behavior. - The concrete-preview regression failed before the optimization by reading both `post-a` and `post-b`, then passed by reading only `post-a`. - A repository-reuse regression failed without the request cache and passed when reuse became the repository default. - The content-read regression failed before the original compiler reuse optimization with three storage calls and passed afterward with one. - The two-document graph regression failed with four physical storage calls and passed with two after graph reads populated the request-local runtime cache. - The response-size regression failed at 127 bytes when internal performance metadata was included and passed at the actual 66-byte payload after separating that metadata. - Builder, content engine, asset uploader, project, and SDK typechecks passed. - Oxfmt, oxlint, and `git diff --check` passed. - The full fixture link/sync/build pipeline passed with no tracked fixture changes after each runtime change. ## Known limitations - Detailed Diagnostics intentionally prepares both the concrete query database and the deployment-wide Published database. `Published diagnostics` reports the latter separately; normal resource loads do not perform it. - Builder round-trip and server duration cover the complete resource batch and therefore include Published diagnostics when the detailed view requests it. - Phase durations are aggregated when a batch contains multiple Assets queries. - Compiler and document-graph storage-read timings sum completed fetch durations. They exclude request-local byte-cache hits and can exceed wall-clock parent phases when reads run concurrently. - Content-read counters report completed normal-query reads; deployment-wide diagnostic reads are excluded, and failed storage reads are represented by the enclosing phase timing and error. - Request-local byte reuse retains selected content only until the current query or batch finishes. Document-graph additions are capped by the existing 2 MiB hydrated-content limit; content beyond the cap is still streamed and can be fetched again at runtime. - Source snapshot and final source validation remain separate reads. The metadata fast path removes redundant repair work without weakening that concurrent-change check. ## Measurement gate PR deployments use the development backend. The supplied production project returns 500 on both the branch deployment and `main.development.webstudio.is`, while the production host returns 200. Final phase timings for the exact project require its corresponding development project/session or an explicitly authorized production-backed deployment. An unrelated fixture will not be used to claim the production improvement. |
||
|
|
db3b11970f |
fix: Optimize images in Markdown Embed (#6089)
## Summary Markdown Embed now renders image tags with the same optimized attributes and canvas behavior as the SDK Image component. The implementation shares the complete attribute-resolution path without rendering React inside the Markdown pipeline: - `@webstudio-is/image` exposes one framework-independent `getImageAttributes` function for optimization, placeholder fallback, loading, decoding, dimensions, alternative text, and responsive sources. - React-only element props such as `className`, `style`, handlers, context, and refs stay in React callers. - The SDK Image component and Markdown renderer both use `getSdkImageProps` for canvas-specific loading, decoding, asset identity, and incomplete-upload handling. - Markdown retains only the necessary HTML attribute-name conversion, sanitization, and Safari-safe `sizes` / `srcset` / `src` ordering. - The redundant low-level React Image primitive was removed. Its callers now render native `img` elements, and the image package no longer has React runtime or peer dependencies. ## Compatibility and tradeoffs - The SDK Image component remains the public React component because it owns React context and ref forwarding. - The removed low-level `@webstudio-is/image` Image export is replaced by the pure attribute function for internal callers. - No data migration or schema change is required. - Loader output is sanitized after transformation, while unsafe input URLs are sanitized before reaching the loader. ## Todo - [x] Share image attribute resolution between native, SDK, and Markdown images. - [x] Preserve SDK canvas behavior for Markdown images. - [x] Preserve safe URL sanitization and Safari-safe responsive attribute ordering. - [x] Remove the redundant low-level React image primitive and migrate its callers. - [x] Remove the overlapping `getImageProps` abstraction. - [x] Add regression coverage comparing Markdown, SDK Image, and native attribute output. - [x] Review documentation impact and update the Markdown Embed documentation. - [x] Run targeted tests, typechecks, builds, lint, formatting, package-boundary checks, and fixture generation. ## Verification - `pnpm --filter @webstudio-is/image test` - `pnpm --filter @webstudio-is/image typecheck` - `pnpm --filter @webstudio-is/image build` - `pnpm --filter @webstudio-is/image dts` - `pnpm --filter @webstudio-is/sdk-components-react test` - `pnpm --filter @webstudio-is/sdk-components-react typecheck` - `pnpm --filter @webstudio-is/sdk-components-react build` - `pnpm --filter @webstudio-is/sdk-components-react dts` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm --filter @webstudio-is/design-system typecheck` - Targeted Oxlint and Oxfmt checks - `pnpm check:package-boundaries` - `pnpm fixtures` (no fixture diff) Ref #6014 |
||
|
|
41c8283a70 |
fix: Allow removal of invalid audited selectors (#6074)
## Summary Allow all targeted style-deletion paths to remove an invalid state selector that already exists, including Builder UI deletion of local and token declarations and CLI/MCP design-token remediation. Creation and update validation remain strict. ## Root cause The style audit reads legacy declarations directly and can report selectors that the current selector validator rejects. Deletion reused the creation/update validator, so the system could identify an invalid stored declaration but could not represent its coordinates for targeted removal. The first fix addressed only design-token deletion, leaving Builder UI and the generic style APIs inconsistent. ## Implementation - [x] Give style deletions a shared deletion-only state-selector contract. - [x] Accept an invalid selector only when the exact target, breakpoint, property, and state already exist. - [x] Reject arbitrary invalid selectors that do not identify an existing declaration. - [x] Reuse one matcher for local, selected/token, and design-token deletions. - [x] Keep creation and update selector validation strict. - [x] Add Builder UI regression coverage for token and local declaration deletion. - [x] Add an audit regression that deletes the reported design-token selector, applies the patch, and confirms the warning is cleared. - [x] Regenerate the public runtime operation contract. - [x] Complete the DRY review: deletion matching, validation, key deduplication, and stored-style scanning are centralized. - [x] Review documentation impact: no authored documentation changes are required; generated operation contracts describe the behavior. - [x] Review fixture impact: no fixture inputs or generated fixture bundles are affected. - [x] Run relevant tests, typechecks, lint, formatting, package-boundary, generated-API, and generated-documentation checks. - [ ] Agent evaluations — not run because repository policy requires separate explicit approval. ## Verification - The two Builder UI regression tests failed with `Operation input is invalid` before the shared fix and passed afterward. - Project-build suite: 82 files, 2,097 tests passed. - CLI suite: 60 files, 968 tests passed. - Builder style-data target: 7 tests passed. - Audit and styles targets: 195 tests passed. - Project-build, Builder, and CLI typechecks passed. - Full repository lint passed. - Package-boundary, generated-API, and generated-documentation checks passed. - Formatting and `git diff --check` passed. Closes #6062 |
||
|
|
d5b3f3ab80 |
fix: Improve MCP authoring reliability (#6056)
## Summary This consolidates the reported MCP reliability fixes into one delivery. - validate all inserted fragment expressions with the shared runtime rules and reject text/expression children when component content models require elements - return an actionable error for unsupported existing-resource references in JSX - preserve siblings rendered before expression children - accept unresolved CSS-variable shorthand expansion and eliminate dynamic-alt/`htmlFor` audit false positives - resolve exposed underscore MCP names during focused discovery - omit unavailable stopped-preview fields and restart stale iterative previews for external clients - bound single and responsive screenshot capture, return `SCREENSHOT_TIMEOUT`, and discard failed reusable browser sessions - dispose previews when shared MCP runs fail or stdio clients disconnect, including complete Windows process-tree cleanup - resolve generated route templates from the CLI-managed preview workspace during responsive verification - retry a browser that exits during rendered-audit startup and report sanitized exit diagnostics with a concrete browser-path recovery action - materialize complete current session data before preview generation so route order and project styles cannot collapse from missing lazy namespaces - always include CLI and Node.js version fields in generated issue reports, with explicit legacy-client fallbacks - document the updated preview and screenshot contracts and regenerate the CLI manual The current branch also retains the protections already present on `main` for dry-run isolation, CSS rewrite truncation metadata, stderr-only progress, shortcut argument forwarding, strict MCP schemas, and refreshed conflict diagnostics. ## Technical choices - MCP command orchestration stays in `mcp.ts`; preview port/retry behavior lives with `mcp-preview`, and persisted checkpoint storage lives in `mcp-checkpoint`. Each module owns its matching tests. - Expression validation lives on the shared fragment input schema, reuses `listFragmentExpressions`, and emits the same structured validation issues as prop bindings, so JSX-derived and structured fragments follow one contract across fragment, collection, and runtime UI insertion. - Element-child requirements come from component registry content models during fragment insertion; no component names are hardcoded in the JSX parser. `CollapsibleTrigger` metadata now matches its enforced `asChild` implementation. - Stopped preview status returns only `running: false`; unavailable `url`, `pid`, and `mode` fields are optional and omitted from JSON. - Explicit `preview.start` restarts a stale compatible iterative preview; managed screenshots keep their optimized refresh path. - Screenshot operations share one timeout utility. A single capture or complete responsive batch is bounded after preview readiness; lower-level CDP deadlines use the same stable error code. - Failed managed captures close and forget their browser session. A closed browser session cannot restart itself while cancellation is in progress, which prevents orphaned Chromium processes. - One ownership helper disposes one-shot and multi-project MCP hosts on success or failure. Shared `mcp run` hosts dispose in one `finally` boundary, long-running MCP hosts dispose on connection close, and Windows uses `taskkill /T /F` instead of killing only the npm wrapper. - Framework template readers receive the absolute template directory captured from the build root, so later async work cannot redirect them to the linked project's cwd. The same option drives cleanup for React Router, Remix, and Vike. - Browser startup gets one bounded retry before a rendered capture batch fails. Persistent failures report only the exit code, signal, or spawn error code plus the supported `WEBSTUDIO_BROWSER_PATH` recovery action; local paths and raw browser output are not exposed. - CLI and MCP preview share one session materializer that ensures the canonical Builder namespace set before writing `.webstudio/data.json`. Serialization rejects incomplete snapshots instead of converting missing style/instance namespaces into valid-looking empty arrays, and preview freshness records the post-materialization project version. - The CLI injects its package version and `process.versions.node`; issue formatting now keeps both fields visible even for legacy reports that omit runtime metadata. ## Checklist - [x] Add regression coverage for every changed behavior - [x] Demonstrate new regression tests fail without the corresponding fixes and pass with them - [x] Run affected package test suites and typechecks - [x] Run lint, package-boundary, and generated API checks - [x] Review fixture impact — no fixture inputs or outputs are affected - [x] Review documentation impact and update the authoritative MCP CLI manual source/generated output - [x] Run the complete local agent evaluation suite ## Verification - `@webstudio-is/project-build`: 2,090 tests passed - MCP asset query result modes are preserved across create, read, and update serialization - complete local agent evaluation suite: all 5 fixtures passed, 1,308,276 aggregate tokens - `@webstudio-is/react-sdk`: 140 tests passed - `@webstudio-is/template`: 43 tests passed - `webstudio` CLI: 956 tests passed - issue reporter: 5 targeted tests passed - MCP host disposal regression was demonstrated failing without the shared ownership boundary and passing with it - relevant package typechecks passed - `pnpm lint` passed - `pnpm check:package-boundaries` passed - `pnpm check:generated-api` passed - generated-doc tests, typecheck, sync, and regeneration passed; the aggregate clean-tree command reports the intentionally changed generated CLI manual - stalled single capture, stalled four-viewport capture, startup retry across a four-viewport batch, sanitized browser-exit diagnostics, complete preview materialization, post-refresh version tracking, closed-session restart, Windows process-tree cleanup, and preview-workspace regressions were demonstrated failing without their fixes and passing with them ## Known limitations - External `baseUrl` screenshots remain caller-owned and intentionally do not regenerate, restart, or stop that external server. Closes #6034 Closes #6035 Closes #6038 Closes #6042 Closes #6043 Closes #6044 Closes #6045 Closes #6046 Closes #6047 Closes #6048 Closes #6049 Closes #6050 Closes #6051 Closes #6052 Closes #6059 Closes #6060 |
||
|
|
2ec78c183d |
feat: Add single-result modes to Assets queries (#6040)
## Summary - Add `many`, `one`, `first`, and `last` result modes to Assets queries while keeping `many` as the backward-compatible default. - Return direct items for single-result modes, validate deterministic ordering, and report duplicate `one` matches as a structured `MULTIPLE_RESULTS` error. - Update Builder controls, preview/published runtime handling, SDK resource encoding, MCP/CLI guidance, generated contracts, and fixtures. ## Implementation TODOs - [x] Add result-mode schemas and core execution behavior. - [x] Select single results before content hydration and preserve deterministic ID tie-breaking. - [x] Add structured duplicate-match transport errors. - [x] Update Builder controls and hide/reset pagination for single-result modes. - [x] Keep existing settings first, then Output and Result, without a duplicate Return label. - [x] Preserve legacy saved resources with an implicit `many` default. - [x] Update preview, published runtime, SDK, protocol, MCP, and CLI behavior. - [x] Regenerate runtime contracts, server metadata, CLI docs, and fixtures. - [x] Review documentation impact and update the authoritative MCP/CLI guidance. - [x] Add regression coverage and verify the new tests fail without the implementation. - [ ] Run the agent evaluation suite (not run; requires explicit user approval). ## Compatibility and behavior - Existing queries without `result` continue to behave as `many` and retain the ID-keyed collection shape. - `one` returns an item or `null`, but fails when more than one asset matches. - `first` and `last` require explicit sorting; the existing asset-ID tie-breaker makes equal sort values deterministic. - Single-result modes ignore and do not persist pagination controls. Materialized collection queries remain collection-only; single-result queries execute dynamically. ## Verification - Content engine typecheck and full test suite (291 tests). - Query builder, query-builder React, SDK, protocol, asset uploader, project build, Builder, and CLI targeted typechecks/tests. - Root lint. - MCP documentation tests, typecheck, sync check, and generated-doc checks. - Generated API contract checks. - Fixture generation pipeline. - Final focused content-engine regression run (53 tests). - Final DRY review: affected typechecks, focused tests, lint, package boundaries, generated checks, and fixtures. Closes #6039 |
||
|
|
d8491ea736 |
fix: Make bound fields read-only (#6028)
Closes #6027 ## Summary Bound values currently remain editable when the expression directly references a mutable variable. Editing the field writes a temporary runtime override while leaving the binding in place, which makes the source of truth unclear and behaves differently across Builder fields. This change makes every expression-bound field read-only. To enter a literal value, remove the binding first. ## Implementation - Simplify binding state to two states: unbound/editable and bound/read-only. - Remove temporary data-variable override writes and the overwritten/reset binding UI. - Remove `allowBindingOverwrite` and bound-value parsing APIs and their call-site exceptions. - Guard pending draft saves so a draft started before binding cannot replace the new binding. - Add query-builder regression coverage for string and numeric filters bound to mutable variables. ## Checklist - [x] Add regression tests and confirm they fail with the previous behavior. - [x] Make all expression-bound controls read-only. - [x] Remove temporary override state and UI. - [x] Verify literal controls remain editable. - [x] Run the full Builder unit test suite. - [x] Run Builder typecheck and repository lint. - [x] Review documentation impact: no documentation change is needed; this makes the existing remove-binding-before-edit interaction consistent. - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected. ## Verification - `pnpm --filter @webstudio-is/builder test` — 2,509 tests passed across 217 files. - `pnpm --filter @webstudio-is/builder typecheck` — passed. - `pnpm lint` — passed. - Agent evaluations were not run because they require separate explicit approval and this change does not modify agent-facing behavior. |
||
|
|
8e7a8a21aa |
feat: Report anonymous MCP reliability issues (#6021)
Closes #6020 ## Summary Adds the first end-to-end slice for anonymous, LLM-authored reliability reports from the CLI and MCP. The shared report contract captures the generalized user story, attempted workflow, expectation, actual result, recovery attempts, user impact, technical context, acceptance criteria, and agent runtime (client, provider, model, version, and reasoning effort). Guidance requires removing any user- or project-identifying information before submission. ## Architecture - Adds a project-authenticated `api.reports.issue` tRPC mutation as the reusable product boundary. - Maps that mutation to the public `report-issue` operation for CLI and MCP callers. - Keeps the endpoint directly callable from a future Builder UI through the existing tRPC client. - Publishes through a server-side GitHub App installation, so end users do not need GitHub accounts or tokens. - Discovers the App installation for the fixed Webstudio reporting repository instead of requiring deployment-specific installation or repository configuration. - Searches for a hidden anonymous technical marker before creation to avoid obvious duplicates. ## Todo 1. [x] Define a shared anonymous LLM-authored report contract. 2. [x] Include the user story, attempted workflow, expected and actual behavior, recovery attempts, impact, technical context, and acceptance criteria. 3. [x] Include the LLM client, provider, model, client version when known, and reasoning effort. 4. [x] Attach sanitized CLI, Node.js, operating-system, architecture, execution-mode, and API-contract metadata automatically. 5. [x] Add the Builder-reusable project tRPC mutation. 6. [x] Expose the mutation to CLI and MCP as `report-issue`. 7. [x] Add GitHub App authentication and issue publication. 8. [x] Reduce deployment configuration to the App ID and private key. 9. [x] Add marker-based duplicate detection. 10. [x] Add guidance for explicit user-requested reports and qualifying repeated-friction reports. 11. [x] Review and simplify repeated GitHub request handling and public protocol exports. 12. [ ] Add server-side throttling and harden concurrent duplicate creation. 13. [x] Configure and install the reporting GitHub App in deployed environments. 14. [x] Exercise the deployed endpoint with a controlled test report. 15. [ ] Run the complete agent evaluation suite after explicit approval. 16. [x] Review documentation impact and update the generated MCP documentation. ## Verification - Protocol issue-report contract tests: passed (3) - Builder GitHub reporting tests: passed (4) - Builder API router tests: passed (30) - CLI schema, command-doc, MCP, and project-session tests: passed - Protocol, HTTP client, project-build, CLI, and Builder typechecks: passed - Root lint: passed - Generated API and documentation checks: passed - New and changed regression tests were demonstrated failing against the previous behavior, then passing after implementation - No fixture inputs or outputs are affected - Agent evaluations were not run because they require explicit approval ## Deployment notes The Builder only needs `GITHUB_ISSUE_REPORT_APP_ID` and `GITHUB_ISSUE_REPORT_PRIVATE_KEY`. The server discovers the App installation for `webstudio-is/webstudio` and creates a short-lived installation token. The App needs repository metadata read access and Issues write access. ## Known limitations Duplicate detection currently uses GitHub issue search and can race when identical reports arrive concurrently. The endpoint is project-authenticated, but dedicated server-side throttling remains a follow-up before production rollout. No Builder UI is included yet; the tRPC boundary is intentionally ready for one. |
||
|
|
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 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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` |
||
|
|
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` |
||
|
|
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 |
||
|
|
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 |
||
|
|
cca9f93e3d |
feat: Improve asset folder move workflows (#5908)
## Summary - use the design-system native scroll area and auto-scroll long asset lists during internal drag operations - add a shared **Move** action to thumbnail and context menus for individual and multiselected assets and folders - add a folder-only move dialog that excludes invalid descendant destinations - consolidate bulk move, duplicate, delete, and clipboard behavior into shared asset-manager operations with undo/redo coverage - simplify dialog state, folder exclusion traversal, and long-list E2E setup ## User impact Users can drag assets or folders to destinations outside the currently visible part of a long panel, and can move one or many selected items through an explicit folder picker. ## Validation - `pnpm --filter @webstudio-is/builder test app/builder/shared/asset-manager` — 126 tests passed - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - focused builder E2E: dragging auto-scrolls a long folder list - focused builder E2E: multiselected assets move from the context menu ## Review note The current validation prevents missing destinations and folder cycles. A small follow-up is still needed to disable moves when every selected item is already in the chosen destination, avoiding a no-op mutation and announcement. |
||
|
|
878d6f1de1 |
feat: Add asset folders to asset manager and improve asset manager UX (#5892)
Closes https://github.com/webstudio-is/webstudio/issues/5877 Closes https://github.com/webstudio-is/webstudio/issues/4775 - Organize assets into nested folders. - Navigate folders with breadcrumbs and Back controls. - Select and manage multiple assets and folders at once. - Drag, copy, cut, paste, duplicate, move, and delete items. - Use context menus and familiar keyboard shortcuts for common actions. - Search and sort assets and folders, with folders grouped first. - Upload files directly into the active folder. - Manage folder placement from asset and folder settings. - Automate asset and folder management through MCP. |
||
|
|
d440e02990 |
feat: Add safer MCP authoring and draft-page verification (#5905)
- **Restore points for agent work**: Create named restore points before major edits, review changes with a dry run, and safely revert project content if needed. - **Shared Slot authoring**: Agents can turn existing sections into shared Slots and insert linked copies across pages, including valid nested Slots. - **DTCG and Figma token imports**: Import design tokens and CSS variables through CLI, MCP, or direct paste, with aliases, modes, composite values, and mappings supported. - **Consistent token conflict handling**: Every paste workflow now offers the same preserve, rename, or merge choices instead of silently overwriting existing design tokens. - **Draft-page previews**: Agents can generate and inspect previews of draft pages without publishing them or exposing drafts in production builds. - **Safer MCP mutations**: Destructive operations require explicit confirmation, invalid raw patches and invented record IDs are rejected, and restore operations commit atomically. - **More dependable agent contracts**: New tools have complete runtime schemas, clearer validation errors, and consistent behavior across CLI, MCP, Builder, and server APIs. |
||
|
|
13c0351a03 |
fix: Move agent connection setup from Builder to the CLI (#5899)
## Summary - remove the misleading **Connect your agent** section from Builder Project Settings - make the CLI the sole owner of MCP client configuration - verify the linked project endpoint and credential before changing client configuration - safely merge Webstudio into existing Claude Code, Cursor, and VS Code MCP files - print the explicit global registration command for Codex instead of editing its global configuration silently - document the agent-led setup flow and safe handling of editable share links ## Why Builder runs in the browser and cannot configure files or global settings on a user's local machine. The previous Project Settings UI duplicated client definitions in the protocol package, exposed a setup command containing the project credential, and could appear successful without proving that the local agent was connected. This moves local-client concerns into the CLI, removes the browser-only setup surface, and makes configuration success depend on a valid, reachable project link. ## User impact A user can ask their agent to connect the current folder to Webstudio. The agent links and synchronizes the project, runs `webstudio connect <client>`, reloads the client, and verifies the connection by listing project pages. Invalid or stale links fail before any client file is changed, with a credential-safe recovery message. ## Validation - full CLI suite: 50 files, 786 tests - full Builder suite: 163 files, 2,148 tests - protocol suite: 73 tests - CLI, Builder, and protocol typechecks - root lint and package-boundary checks - generated API and documentation checks - real VS Code MCP handshake against a saved project: 156 tools discovered - fresh weak-model subagent test: repeated connection remained idempotent and `meta.index` returned `ok: true` |
||
|
|
98d5c607ee |
feat: Improve MCP safety, context efficiency, and agent workflows (#5895)
## Summary This combines the three reported MCP improvements into one release-ready change: - Safer mutation planning and confirmation for destructive operations. - Much smaller MCP handshake and default discovery responses. - Better agent workflows for checkpoints, multi-project work, and page duplication. ## Safer destructive operations - Exposes `dryRun` in MCP schemas for every local-capable mutation. - Returns planned transactions through `meta.session.transaction`. - Requires a two-step confirmation flow for destructive semantic operations. - Returns a short-lived token bound to the project, build version, input, and exact generated patch plan. - Rejects expired tokens, altered inputs, changed versions, and changed plans. - Sets `destructiveHint: true` only for operations that actually require confirmation. - Explicitly protects destructive operations whose names do not begin with delete or replace, including replacing all redirects and clearing all styles from a style source. ## Smaller, focused MCP context - Defers oversized tool input schemas from the initial MCP handshake. - Keeps complete focused schemas available through `meta.get_more_tools` and CLI schema inspection. - Makes template registry lists compact while preserving complete payloads through focused get calls. - Makes component summaries compact by default and supports paginated component details. - Replaces placeholder operation descriptions with useful command descriptions. - Constrains previously untyped JSON schema fields so clients can validate inputs earlier. - Keeps runtime output schemas compatible with strict MCP clients. ## Better agent workflows - Allows read-only discovery and inspection while a workflow checkpoint is awaiting acknowledgement. - Continues blocking mutations until the checkpoint is acknowledged. - Checks persisted checkpoints before every workflow call rather than only the first call. - Adds `--project` support so saved projects can be selected without relinking the current directory. - Isolates project sessions and checkpoints by selected project. - Adds atomic `duplicate-page` substitutions for copied fixed text and copied variable values. - Prevents substitutions from modifying source content or global root state. - Rejects ambiguous or missing copied variables without leaving a partial duplicate. ## Realistic agent verification Minimal-context tests used a weak agent against the local packaged CLI and stdio MCP: - Planned a page deletion, stopped for explicit user confirmation, committed the unchanged plan, and verified the page was absent. - Tried to reuse a confirmation token with altered input; Webstudio returned `DESTRUCTIVE_CONFIRMATION_INVALID` and preserved both pages. - Verified compact handshake schemas and focused retrieval of the complete oversized schema. - Verified compact template and component discovery responses. - Selected a saved project explicitly without relying on the directory link. - Verified checkpointed workflows permit reads but block mutations. - Duplicated a London page into a Paris page with atomic text and variable substitutions. - Verified source content remained London, copied content became Paris, and temporary pages were removed. ## Validation - Project-build focused suites: 188 tests passed. - CLI focused suites: 183 tests passed. - Protocol focused suites: 21 tests passed. - CLI, project-build, and protocol typechecks passed. - Repository lint passed with zero warnings. - Package-boundary validation passed. - Generated runtime operation contracts were regenerated from source. - Real local CLI/MCP tests passed against a running Builder server. Closes #5887 Closes #5888 Closes #5889 |
||
|
|
27eecd1a29 |
fix: remap conflicting pasted breakpoint ids (#5898)
## What changed - Remap pasted breakpoint IDs when the same ID already belongs to a different breakpoint in the destination project. - Carry the remapped ID into pasted style declarations. - Add a regression test for inserting a fragment whose breakpoint ID conflicts with an existing project breakpoint. ## Why HTML and Tailwind conversion uses compact fragment-local breakpoint IDs such as `"0"` and `"1"`. In non-empty projects, one of those IDs can already identify a different breakpoint. The fragment copy path previously retained the incoming ID, causing the runtime to reject the mutation with `Generated record id "1" already exists`. ## Impact Pasting HTML with Tailwind classes now works in existing projects even when generated fragment breakpoint IDs overlap project breakpoint IDs. Matching breakpoints continue to be reused. ## Validation - `pnpm --filter @webstudio-is/project-build test -- src/runtime/components.test.ts` - `pnpm --filter @webstudio-is/project-build test -- src/runtime/fragment.test.tsx src/runtime/breakpoints.test.ts` - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm exec oxlint packages/project-build/src/runtime/fragment.ts packages/project-build/src/runtime/components.test.ts` - `pnpm exec oxfmt --check packages/project-build/src/runtime/fragment.ts packages/project-build/src/runtime/components.test.ts` - `git diff --check` |
||
|
|
b395556d7a |
fix: wait for db over TCP in dev/backend.sh to avoid false-positive readiness (#5891)
## Description `builder_backend_wait_for_db` checks readiness by running `psql` inside the `db` container, which connects over the **unix socket**. The official `postgres` image's entrypoint starts a temporary server with `listen_addresses=''` (socket only) while it runs its init phase. During that window the socket probe succeeds, but host-side clients (prisma migrate, postgrest) connecting over TCP still get `connection refused` . so the wait can return before the database is actually reachable. It's a timing race: it rarely bites with a fast init, but it's reproducible with slower images/machines (we hit it consistently in our fork's CI, which uses a pg image with a longer init phase). Fix: make the readiness probe connect the same way real clients do. Over TCP (`psql -h 127.0.0.1`). `PGPASSWORD` is needed because host connections use password auth, unlike the socket which is `trust`. Same one-line change to the probe in `builder_backend_wait_for_db`; behavior is otherwise identical. ## Steps for reproduction 1. `docker compose down -v` in `apps/builder` (force a fresh initdb) 2. run `dev/run-local.sh` (or anything using `builder_backend_wait_for_db`) 3. on a slow machine the wait returns during the init phase and the following `prisma migrate` / postgrest startup fails with `connection refused`; with this patch the wait only returns once TCP is accepting connections ## Code Review - [ ] hi @kof, I need you to do - detailed review (it's a one-line probe change in `dev/backend.sh`) ## Before requesting a review - [x] made a self-review - [x] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated test cases document n/a (dev tooling only) - [ ] added tests -> n/a (shell dev script) - [x] if any new env variables are added, added them to `.env` file -> none added Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
12ad74584a |
feat: Improve MCP authoring, auditing, and verification (#5886)
## Summary This improves how coding agents discover, author, verify, and audit Webstudio projects through the CLI and MCP. The work focuses on making agents more reliable with less context, while keeping edits semantic and Builder-editable. ## What changes for users - Agents can verify dynamic bindings after authoring and receive actionable diagnostics when expressions, resources, scopes, or component props do not line up. - Agents can create complete resource-backed runtime UI through a semantic operation instead of coordinating fragile low-level edits. - MCP discovery and command output are compact by default, with pagination and focused verbose detail when an agent needs more context. - Asset, style, token, font, page, and component inspection provides stronger usage context so agents can preserve the existing design system. - Rendered audits provide better evidence for responsive behavior, geometry, contrast, generated-build size, and large-project runs. - Cross-project MCP workflows can run from a manifest with explicit mutation approval, isolated failures, resumable progress, and persistent checkpoints. - Project-specific agent onboarding is clearer and does not add telemetry. - Packaged CLI releases gain stronger smoke verification for install, MCP startup, authoring, preview, screenshots, and audits. ## Reliability and architecture - Runtime operation output schemas are generated from the runtime registry and remain client-compatible. - Project-build exports are consolidated around architectural boundaries instead of feature-by-feature convenience entry points. - HTTP, preview, screenshot, and project-session paths are hardened for longer autonomous workflows. - Craft compatibility work is read-only and provenance-aware; it does not silently opt ordinary projects into Craft behavior. - A minimal-context evaluation harness exercises key workflows with a weaker model and stores bounded, privacy-safe evidence. ## Validation - Rebased on the latest `origin/main`. - `pnpm lint` - Repository-wide `oxfmt --check` - CLI typecheck and full test suite: 773 tests passed. - Project-build typecheck and full test suite: 1,866 tests passed. - Protocol typecheck and full test suite: 83 tests passed. - HTTP client tests: 23 passed. - CSS data tests: 3,620 passed, 1 skipped. - Focused Builder tests: 67 passed. - Package-boundary, generated API, and generated documentation checks passed. - Minimal-context agent evaluations passed for authenticated resource-backed UI and design-system-aware responsive authoring. |
||
|
|
d579607ed8 |
feat: Add draft pages (#5885)
Closes https://github.com/webstudio-is/webstudio/issues/3036 ## Summary - add an optional page-level draft state with a presentation-only `[Draft]` prefix in Builder - add **Mark as draft** and **Stage for publish** actions to the Page details header menu - keep drafts editable, previewable, linkable, duplicable, and path-reserving in Builder - exclude drafts from generated routes, public page collections, sitemap output, staging, and production builds - expose draft state and usage guidance through the runtime API, HTTP client, CLI docs, and MCP contracts ## Why Pages need a way to remain unfinished inside Builder without being included in the next site deployment. Draft is an exclusion flag, not a separate revision or publishing workflow state. ## Behavior and fixes - home and `/*` catch-all pages cannot be drafts - draft pages must be staged before becoming the home page - restricted features used only on draft pages no longer block publishing the publishable site - **Stage for publish** only clears draft state; it does not deploy the site - missing or explicit `false` draft state remains backward-compatible and publishable ## Validation - 5,179 package tests passed across SDK, migrations, project-build, CLI, and Builder - targeted Builder browser E2E passed for draft/stage actions, persistence, home-page guidance, copy, duplicate, delete, and generated-app build behavior - all affected package typechecks passed - lint and package-boundary checks passed - generated runtime contracts and CLI docs are reproducible - `git diff --check` passed |
||
|
|
dde30ffb54 |
feat: Improve MCP authoring, compact output, and agent onboarding (#5883)
## Summary This improves how agents discover, author, inspect, and verify Webstudio projects while reducing unnecessary MCP context usage. ## What changed - Adds an **Agents** section to Project Settings with ready-to-run setup commands and client configuration for Claude Code, Codex, Cursor, and VS Code. - Makes large list and schema responses compact and paginated by default, with **verbose** available when complete records or diagnostics are needed. - Applies consistent compact output to assets, instances, styles, design tokens, CLI schemas, and project-session metadata. - Returns actionable expression warnings for props, resources, and Collection bindings, including unknown variables and risky render-time mutation resources. - Improves Collection expression guidance so agents can bind array items with the correct scoped variables. - Reports rendered audit outcomes explicitly as complete, partial, confirmation-required, or failed. - Expands runtime output schemas so MCP clients can validate responses reliably. - Strengthens the packaged CLI smoke workflow with a realistic seven-page stdio MCP scenario. ## Architecture - Consolidates `project-build` from 65 file-oriented entrypoints to 11 architecture-owned surfaces. - Separates the core model, contracts, runtime authoring, transfer, state, project sessions, MCP, visual tooling, persistence codecs, and authenticated server services. - Isolates Node-only JSX evaluation from browser-safe transfer utilities and authenticated server modules. - Keeps persistence codecs independent from authenticated database services, preventing unrelated module initialization. - Defines shared instance-path types once and reuses them across runtime modules. - Preserves Immer initialization through explicit package side-effect metadata. - Adds package tests that prevent a return to source-file entrypoints or generic exposure of Node-only surfaces. ## Validation - Full repository checks, tests, typechecks, generated-file checks, and fixtures - All 163 Builder test files and 2,141 tests - All 71 project-build test files and 1,794 tests - Lint and package-boundary validation - Full packed CLI release smoke test, including install, preview, agent setup, seven-page stdio MCP workflow, rendered audit, and structured commands |