mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 14:03:33 +09:00
0.296.0
495
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a8c1726418 |
fix: stabilize CLI bundle contract after publish (#6293)
## Summary - bundle Zod into the published CLI because `bundleVersion` derives from Zod schema internals - bundle `@emotion/hash`, which produces the contract identifier - prevent compatible dependency updates at install time from changing an already-published CLI's contract - add regression coverage for the CLI bundling boundary ## Root cause `webstudio@0.294.0` externalized `zod` and declared `^4.4.3`. The Builder was built with the lockfile version, while a fresh `npx webstudio@latest` installation resolved Zod 4.5.4. Because the project bundle contract is calculated at runtime from Zod definitions, the Builder expected `bundle-1mym82p` while the freshly installed CLI sent `bundle-8e39e9` despite both being the same Webstudio release. ## Packaged CLI reproduction Tested the CLI built from the parent commit and this branch in the same isolated `webstudio@0.294.0` installation with Zod 4.5.4. Both builds executed the real local `webstudio sync` command against the same capture server. - Before: `{"label":"before","zod":"4.5.4","bundleVersion":"bundle-8e39e9"}` - After: `{"label":"after","zod":"4.5.4","bundleVersion":"bundle-1mym82p"}` - Live Builder: `{"bundleVersion":"bundle-1mym82p"}` The fixed local CLI now sends the exact contract required by the live Builder even though the install environment still contains Zod 4.5.4. ## Verification - isolated before/after packaged CLI test through the real `sync` request path - `pnpm --filter webstudio exec vitest run src/cli-bundle-externals.test.ts` - `pnpm --filter webstudio typecheck` - `pnpm --filter webstudio build` - verified emitted CLI files contain no external imports from `zod` or `@emotion/hash` - `pnpm exec oxfmt --check packages/cli/vite.config.ts packages/cli/src/cli-bundle-externals.test.ts` - `git diff --check` |
||
|
|
bc8630f413 |
fix: Gate Builder releases on the published CLI contract (#6282)
Closes #6280 ## Summary - Expose the deployed Builder's CLI-facing bundle contract through a non-cached, read-only endpoint. - Resolve and execute the exact `webstudio@latest` registry artifact, observe the bundle version sent by its real `sync` request, and require an exact match before assigning the release staging alias. - Include expected and received bundle versions in runtime and release-gate errors. ## Technical choices - The existing generated `bundleVersion` remains the single compatibility boundary. Builder-only changes outside that project-bundle contract do not require a CLI release. - The CLI sync probe runs against a local fixture API and temporary directory. It reads the deployed runtime contract but never reads or modifies a Cloud project. - Verification runs after Vercel creates the exact production-built deployment and before the release staging alias is assigned. A mismatch therefore leaves production domains untouched. - Registry resolution requires version and integrity metadata, then executes the resolved immutable version rather than source from the checkout. - The gate requires the deployed Builder origin and cannot fall back to the checkout's contract. ## Todo 1. [x] Add the deployed Builder contract endpoint. 2. [x] Probe the exact published CLI through its real sync request. 3. [x] Gate the release staging alias on an exact contract match. 4. [x] Report expected and received versions for compatibility failures. 5. [x] Add regression tests and verify the production Builder build. 6. [x] Review documentation and fixture impact. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run app/services/build-router.server.test.ts app/services/cli-compatibility-route.node.test.ts` — 12 passed. - `pnpm --filter webstudio exec vitest run scripts/builder-contract-gate.test.ts scripts/release-smoke-registry.test.ts` — 7 passed. - Rebased onto `main` at `9ec4c820e1`. - Builder and CLI typechecks passed. - `pnpm lint` and changed-file formatting passed. - `pnpm --filter @webstudio-is/builder build` passed and emitted `/rest/cli-compatibility`. - The changed GitHub Action parses as valid YAML. - Real registry probe passed for `webstudio@0.293.0` against `bundle-kzb45v`. - Real registry probe correctly blocked current Builder contract `bundle-1mym82p` and reported expected `bundle-1mym82p`, received `bundle-kzb45v`. - Missing staged Builder origin fails closed before registry execution. - GitHub CI passed all four workflows, including all six Builder E2E shards. - The formerly failing empty-MDX insertion workflow passed 8 repeated runs with 4 workers locally, then passed in Builder E2E shard 4 in CI. - Full browser-based release smoke was not run, per the request not to use Chrome. Agent evaluations were not run because no evaluation approval was requested or received. - Documentation: no user-facing documentation changes are required. - Fixtures/generated outputs: no fixture inputs or generated outputs are affected. ## Operational boundary The check needs the exact deployed runtime, so Vercel creates an unaliased `--skip-domain` deployment before verification. A failed check cannot affect production domains or the normal release alias. Repository automation cannot prevent a Vercel administrator from manually promoting an arbitrary deployment outside this release path. |
||
|
|
9ec4c820e1 |
fix: Use writable npm cache for previews (#6272)
## Summary - Use a writable `.webstudio/preview/.npm-cache` for npm preview installs when `npm_config_cache` is not explicitly configured. - Preserve explicit npm cache settings and pnpm behavior. - Document a safe recovery path that requires no cache deletion. This removes preview startup failures caused by an unwritable default npm cache. Initial dependency installation and its network/download cost still remain when preview dependencies are not already installed. ## Technical choices - Keep the cache beside the isolated generated preview because that directory is already writable and reused across regenerations. - Let an explicit `npm_config_cache` continue to take precedence. - Do not retry arbitrary install failures or classify package-manager prose. ## Todo - [x] Reproduce npm dependency installation against an unwritable cache before changing code. - [x] Reproduce #6274 at the same dependency-install stage used by session-backed screenshots. - [x] Demonstrate the regression assertion failing before the fix and passing afterward. - [x] Use the preview-local cache only for npm without an explicit cache. - [x] Preserve explicit npm cache configuration and pnpm behavior. - [x] Verify the real dependency installer against an unwritable project npm cache. - [x] Verify session-backed screenshot flow proceeds from successful preview preparation to browser capture. - [x] Review documentation impact and update the CLI manual plus generated MCP documentation. - [x] Review fixture impact; no project fixture inputs or outputs are affected. - [x] Review the final diff for correctness, duplication, and unnecessary complexity. ## Verification - Actual npm install reproduced #6269 and #6274 with `EPERM` against an unwritable cache. - Real preview dependency installation passed after the fix while project npm configuration still pointed at that cache. - Fail-before/pass-after regression demonstrated. - `pnpm --filter webstudio test` — 65 files, 1,044 tests passed. - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm check:generated-docs` - Formatting and diff checks passed. - GitHub CI after rebasing onto current `main` — 30 checks passed, 7 skipped, no failures. - Agent evaluations were not run because they require separate explicit approval. Closes #6269 Closes #6274 |
||
|
|
1b48716ff4 |
docs: Document MDX-backed Content Blocks (#6273)
## Summary - Document how people create, connect, edit, validate, and publish MDX-backed Content Blocks. - Document the complete MCP workflow, including scoped expression sources, frontmatter updates, diagnostics, conflicts, and disconnect behavior. - Add two focused screenshots for the human workflow. - Fix issues found by a low-reasoning MCP agent while executing every documented workflow. Ref #6182 ## Implementation notes - Connection confirmation uses the public `confirmReplacement` field because `confirm` is reserved as a hidden transport field. - MCP edits frontmatter with `update-content-block-frontmatter`; materialized MDX elements are not persistent targets for generic instance mutation tools. - Reload now intentionally discards a conflicted local source and accepts the Asset's latest storage revision before an edit is reapplied. - Generated MCP documentation and runtime contracts are updated from their source files. ## Checklist - [x] Document the human MDX Content Block workflow. - [x] Document MCP discovery, connection, editing, diagnostics, frontmatter, dynamic sources, conflicts, and disconnection. - [x] Add only screenshots that clarify otherwise hard-to-describe UI steps. - [x] Test every documented MDX capability through the local MCP CLI with a low-reasoning agent. - [x] Reproduce and fix the replacement-confirmation schema mismatch. - [x] Reproduce and fix persistent-session conflict reload and reapply. - [x] Add regression tests that failed before each product fix and pass afterward. - [x] Regenerate runtime contracts and generated MCP documentation. - [x] Review authoritative `docs/` content and update affected pages. - [x] Run affected tests, typechecks, formatting, and diff checks. ## Verification - Project Build: 208 affected tests passed. - Content Engine Asset session: 8 tests passed. - CLI documentation tests: 14 tests passed. - MCP docs generator: 3 tests passed. - Content Engine, Project Build, CLI, and MCP docs typechecks passed. - `pnpm oxfmt --check` passed. - `git diff --check` passed. - Low-reasoning MCP evaluation passed all documented workflows, including a real two-client revision conflict, reload, reapply, and final saved inspection. |
||
|
|
8718feb465 |
test: simplify browser testing infrastructure (#6271)
## Summary Unifies frontend testing around three intentional boundaries: - Vitest Node projects for pure and server tests - Vitest Browser Mode with Playwright/Chromium for DOM and component tests - Playwright Test for Builder end-to-end workflows The Builder no longer uses jsdom. Ordinary E2E workflows use an automatically managed isolated `page` fixture; explicit contexts remain only for simultaneous identities and suite-scoped setup. ## Technical choices - Split Builder tests into one Node project and independent browser projects so each Chromium/Vite process has a bounded workload. - Added shared Browser Mode configuration for the affected SDK React packages. - Preserve the Builder's production top-window bridge ownership; Browser Mode uses explicit test-only installation seams. - Centralized Playwright context options and kept action/navigation timeouts bounded. - Validate Playwright filters before Docker, migrations, browser installation, or Builder builds start. - Preserve the first failed E2E attempt's report, traces, screenshots, and videos when CI retries a shard. - Split static checks, typechecks, CLI tests, core package tests, browser package tests, and Builder projects into parallel CI jobs with five-minute hard ceilings. - Distribute Builder E2E tests across ten isolated shards with two workers; parallel suites create unique per-worker setup data. - Reuse color contrast DOM/canvas samples so the exhaustive theme sweep takes about four seconds instead of timing out at 30 seconds. - The removed cost is jsdom behavior drift, oversized serial check jobs, and unnecessary E2E startup for empty selections. Real browser startup and E2E environment setup remain. ## Todo - [x] Split Builder pure/server tests from browser/component tests. - [x] Migrate Builder DOM tests from jsdom to Vitest Browser Mode. - [x] Migrate affected SDK React DOM tests to the shared Browser Mode setup. - [x] Remove jsdom annotations, dependencies, and compatibility setup. - [x] Replace ordinary manual E2E contexts with the isolated `page` fixture. - [x] Keep explicit contexts only for concurrent identities and `beforeAll` setup. - [x] Preserve setup authentication isolation from workflow pages. - [x] Add bounded Playwright action and navigation timeouts. - [x] Preserve first-attempt E2E failure evidence across CI retry. - [x] Reject empty E2E selections before expensive environment setup. - [x] Parallelize repository checks into bounded CI shards. - [x] Isolate parallel E2E setup data across workers. - [x] Remove the color contrast sweep bottleneck. - [x] Update E2E contributor documentation. - [x] Review product documentation impact; no user-facing product docs are affected. - [x] Run the full repository tests and typechecks. - [x] Run formatting, lint, package-boundary, generated-file, and fixture checks. - [x] Complete final correctness and simplification review. ## Verification - `pnpm --filter @webstudio-is/builder test` - `pnpm -r typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` - `pnpm fixtures` - Design-system: 222 tests pass locally. - Builder: all seven Vitest projects pass locally. - The formerly slow E2E shard passes locally in 1m55s. - Full database-backed Builder E2E execution passes in CI. - All CI jobs pass; the slowest completed in 4m58s. - No fixture inputs/outputs or generated files changed. Ref #6270 |
||
|
|
f9681dc30f |
feat: MDX-backed Content Blocks (#6234)
## Summary Supersede #6182 with a clean implementation of MDX-backed Content Blocks on top of the unchanged `main` Content Block editing model. A connected `.mdx` Asset changes where authored children are loaded and saved; it must not change how Content mode inserts, edits, selects, moves, copies, or deletes instances. The previous implementation remains available in `agent/mdx-content-block-6124` and `agent/mdx-content-block-6124-review`. Reuse its independently tested parsers, converters, schemas, Asset repository, template resolution, publication, MCP, and UI work where those pieces fit the corrected architecture. Do not port its per-operation storage routing, projected editing stores, MDX undo/history, or atomic multi-root machinery. Ref #6124 Ref #6182 Closes #6261 ## Locked behavior - `.md` keeps its existing Markdown behavior; `.mdx` enables MDX. - Standard Markdown structures are stored as Markdown. JSX is used only for structures Markdown cannot represent losslessly. - Generic elements use `<ws.element ws:tag="…">`; template instances use `<ws.element ws:name="…">`. - Invalid, unsafe, or unsupported MDX never prevents editing the file or publishing the project. Builder and publication use the same recovery result: recoverable nodes are skipped with source-located warnings, while an unrecoverable document renders no authored file content in either environment. - Connecting a source never serializes existing Content Block children into the file. **Connect** removes ordinary persisted children, preserves Templates, sets `src`, and uses file content. - Disconnecting resets `src`, discards derived instances, leaves the Content Block empty, and never changes the Asset. - While connected, normal Content Block mutations update in-memory instances synchronously. Asset persistence happens afterward and never blocks rendering. - Genuine external revision conflicts use the standard reload-required flow. Rapid local edits are ordered/coalesced and must never conflict with each other. - Repeated scopes use Content Block ID plus Collection item identity. - Multiple Content Blocks may intentionally share one MDX Asset. They share one revisioned document session and edits propagate to every connected occurrence. - Missing templates show warnings/placeholders only in Builder and are skipped on published sites. ## Reuse strategy - [x] Audit all 62 original implementation commits and 5 later review/fix commits - [x] Reuse the shared Content Engine Markdown/MDX AST, parser, serializer, diagnostics, reference discovery, and tests - [x] Reuse SDK source schemas, instance-name utilities, unique template naming, and source-integrity validation - [x] Reuse template resolution/materialization and authored-tree conversion after removing storage-operation coupling - [x] Reuse revisioned Asset content repository, authorization, limits, and browser/server transport - [x] Reuse publication, document-graph, CLI, MCP, source-control UI, frontmatter UI, and E2E work where contracts remain valid - [x] Reuse tests as behavioral specifications; rewrite tests that assert the rejected projection/routing architecture - [x] Do not port per-operation MDX routing, alternate projected mutation stores, semantic reconciliation after each command, MDX Builder history/undo, atomic multi-file rollback, or canvas loading/saving UI ## Old-branch porting map — do not rewrite Before implementing any checklist batch, inspect the named implementation and tests on `agent/mdx-content-block-6124-review`. Move the implementation and its tests first; change only the boundary that conflicts with the rebuilt architecture. Do not create a second implementation under a new name. When a test encodes the rejected projected-store architecture, retain its behavioral assertion and replace only its setup. ### Already ported - `parseMarkdownAst`, `createMdxDocumentFromMarkdown`, `parseMdxDocument`, `serializeMdxDocument`, `preferMarkdownSyntax`, `discoverMdxBodyAssetReferences`, `discoverMdxAssetReferences`, and `previewMarkdownToMdxConversion` - Asset-reference, byte-stream, document-graph, Markdown, and MDX helpers included in commit `76bc388ba9` - Tests: the corresponding `packages/content-engine/src/**/*.test.ts` files already on this branch ### Port with their existing tests | Area | Functions to move or adapt | Tests to move with them | | --- | --- | --- | | Source contract and integrity | `parseContentBlockSourceProp`, `getContentBlockSource`, `isEqualContentBlockSource`, `formatContentBlockSourceIntegrityIssue`, `getContentBlockSourceIntegrityIssues`, `allocateUniqueContentBlockTemplateName` | `packages/sdk/src/content-block.test.ts`, `packages/sdk/src/schema/content-block.test.ts` | | Existing instance/name utilities | `findChildReferenceIndex`, `findParentInstanceReference`, `getInstanceName` | `packages/sdk/src/instances-utils.test.tsx` | | Template naming in mutations | `assignUniqueBlockTemplateNamesMutable`, `findBlockTemplateNameCollision`, `getSourceBackedBlockTemplateContext`, `getBlockTemplateNameConfirmation`, `getBlockTemplateInsertionIndex` | `packages/project-build/src/runtime/block.test.ts` | | Content-mode property permissions | `getContentModePropEligibility`; preserve its distinction between editable, design-only, incompatible, and unknown props | `packages/project-build/src/runtime/content-mode-permissions.test.ts` | | Template resolution | `resolveMdxTemplates` | `packages/project-build/src/runtime/mdx-template-resolution.test.ts` | | Template materialization | `createMdxScopeIdGenerator`, `materializeMdxTemplates` | `packages/project-build/src/runtime/mdx-materialization.test.ts` | | MDX → instances and instances → MDX | `isMaterializedMdxAuthoredContentRoot`, `preserveMdxAuthoredContentIds`, `materializeMdxAuthoredContent`, `reconcileMdxAuthoredContent`, `omitTransientEmptyParagraphs`, `serializeMdxTemplateInsertion` | `packages/project-build/src/runtime/mdx-authored-content.test.ts`; retain the pure serialization cases from `mdx-storage-adapter.test.ts` | | Revisioned Asset I/O | `createAssetContentRevision`, `readAssetContentBytes`, the package-owned `createHttpAssetContentRepository`, the thin Builder `createBuilderHttpAssetContentRepository`, `createAssetContentBridge`, `initAssetContentBridge`, `getAssetContentBridge`; keep one repository implementation rather than copying the old Builder duplicate | `packages/asset-uploader/src/content-repository.test.ts`, `apps/builder/app/builder/shared/assets/mdx-content-repository.test.ts`, `apps/builder/app/shared/asset-content-bridge.client.test.ts` | | Source lifecycle planning | `createContentBlockBodyRemoval`, `prepareContentBlockConnect`, `prepareContentBlockDisconnect`, `prepareContentBlockSwitch`, `ContentBlockSourceRevisionConflictError` | `packages/project-build/src/runtime/content-block-source-lifecycle.test.ts` | | Per-Asset revision/session behavior | `getContentBlockSessionSource`, `isContentBlockSessionSourceCommitted`; reuse the loading, authorization, revision, queue, conflict, retry, cancellation, and source-replacement internals of `createMdxAssetEditingSession`, but key the rebuilt session by Asset rather than Content Block/render root | Port the applicable cases from `packages/project-build/src/runtime/mdx-asset-session.test.ts`; replace root-projection setup with in-memory snapshot setup | | Template migrations | `validateMdxTemplateMigrationConfirmation`, `planMdxTemplateMigration` | `packages/project-build/src/runtime/mdx-template-migration.test.ts` | | Publication | `createPublishedMdxMaterializationCache`, `materializePublishedMdx`, `getPublishedMdxContentDatabaseMaxBytes`, `getDynamicPublishedMdxSourceBlockIds`, `hasDynamicPublishedMdxSources`, `createPublishedBuildContentCompilationPlan`, `resolvePublishedMdxDependencyClosure`, `resolvePublishedMdxAssetCandidates` | `packages/project-build/src/runtime/published-mdx.test.ts`, `packages/project-build/src/content-database.test.ts` | | Build/import integrity | `assertContentBlockSourceIntegrity` and the Content Block cases in `getBuildIntegrityIssues`/`formatBuildIntegrityIssue` | `packages/project-build/src/build-integrity.test.ts` | | MDX paste/MCP insertion | `insertMdxText` and its input/result schemas; retain parsing, confirmation, template-resolution, and insertion-index logic, then invoke the normal mutation path | `packages/project-build/src/runtime/mdx-paste.test.ts` | | Builder source control | `createContentBlockSourceController`, `createBuilderContentBlockSourceController` and the existing source-control components | `content-block-source-controller.test.ts`, `content-block-source.test.tsx` | | Diagnostics | `formatContentBlockDiagnostic`, `deduplicateContentBlockDiagnostics`, `takeNewContentBlockDiagnostics` | Port only their focused cases from `apps/builder/app/shared/content-block-content.test.ts` | ### Explicitly do not port - `projectContentStorageChanges`, `createContentStorageProjection`, `createContentStorageSelectorProjection`, `executeContentStorageMutation`, `executeContentStorageTextReplacement`, `executeContentStoragePropMutation`, and `executeContentStorageStructuralMutation` - `applyMdxContentStorageChanges` and `prepareMdxContentStorageWrites`; replace them with one post-mutation snapshot serializer built from the reusable pure `reconcileMdxAuthoredContent` converter - `createContentBlockApplicationOperations` and the persistence-plan wrappers that route individual editing commands - Builder `$runtime*` projected stores, materialized mutation functions, alternate selector/tree helpers, pending projected-change state, and MDX-specific mutation sequences from `content-block-content.ts` - Canvas loading/saving/open-file presentation state, MDX history/undo, and atomic rollback machinery ## Implementation checklist ### 1. Preserve the `main` editing architecture - [x] Keep normal synchronous insert, text, Enter, slash menu, property, delete, move, wrap, copy/paste, selection, and focus mutations unchanged - [x] Materialize connected content through the same runtime instance interfaces used by ordinary Content Blocks - [x] Keep connected authored children in memory and exclude them from persisted build data - [x] Route persistence only after a synchronous mutation has updated the canvas - [x] Never wait for Asset loading, conversion, or saving before rendering an interaction - [x] Add no MDX-specific implementation to individual editing commands ### 2. Shared Markdown and MDX conversion - [x] Parse Markdown and the Markdown portion of MDX through one shared AST and plugin configuration - [x] Implement one shared MDX-to-instances converter and one shared instances-to-MDX converter - [x] Serialize headings, paragraphs, links, images, lists, tables, task lists, blockquotes, thematic breaks, code, emphasis, strong, strikethrough, and other supported GFM structures as Markdown - [x] Serialize only non-lossless/custom structures as Webstudio JSX - [x] Preserve nested Markdown in MDX elements, frontmatter, comments, tight/loose list semantics, code whitespace, reference links, and Asset references - [x] Omit transient empty draft paragraphs instead of emitting `<ws.element ws:tag="p" />` - [x] Preserve unsupported source text and authored metadata whenever it cannot be converted safely - [x] Add deterministic round-trip and canonical-output coverage for every supported Markdown structure ### 3. Invalid and unsafe MDX - [x] Preserve file source exactly; never silently repair or rewrite invalid source - [x] Ignore imports, exports, expressions, executable JavaScript, invalid properties, and other unsupported nodes when they can be isolated - [x] Continue rendering valid siblings and report every skipped subtree once with filename, line, and column - [x] Use the same recovery pipeline in Builder and publication so both render the same authored result for the current file revision - [x] When structural syntax prevents recovery, render no authored file content in Builder or publication instead of retaining a stale materialization - [x] Skip an unrecoverable Content Block on published sites and continue the build with a warning - [x] Keep invalid and unsafe files editable and reconnectable - [x] Enforce UTF-8, byte-size, depth, node-count, property-count, and generated-output limits with source-located diagnostics where possible ### 4. File formats and Asset creation - [x] Keep `.md` parsing and raw-HTML behavior unchanged - [x] Support creating, opening, editing, deleting, and recreating `.mdx` files through the normal text-file UI - [x] Open `.mdx` in the same editor experience as `.md` - [x] Always create an independent empty MDX Asset even when identical empty files exist - [x] Allow renaming `.md` to `.mdx` without converting or rewriting its contents; after rename, handle invalid contents through the normal MDX diagnostics and recovery pipeline - [x] Update an already-open MDX editor immediately after canvas persistence - [x] Bound read/write buffering and verify the returned Asset identity and revision ### 5. Source contracts and lifecycle - [x] Support direct Asset bindings and dynamic expression bindings - [x] Keep source mutation controls available only in Design mode; show the connected filename and **Open** action read-only in Content mode - [x] Reject duplicate source props, unsupported prop types, missing Assets, non-MDX Assets, and unauthorized Assets - [x] Analyze selected file diagnostics before confirmation without modifying the block or file; MDX syntax diagnostics do not block connection - [x] For a non-empty block, show **Abort** and **Connect** and explain that ordinary children will be replaced - [x] On connect, remove every non-template child, preserve Templates, set `src`, and materialize file content - [x] Replace disconnect handoff with normal `src` reset; discard derived content and leave the block empty - [x] Remove disconnect confirmation and conversion; resetting a repeated binding leaves every occurrence empty - [x] Switching sources validates/loads the target before replacing the usable binding and leaves both files unchanged - [x] Revalidate Asset revision and project version when confirmation is submitted - [x] Make repeated connect/disconnect operations idempotent - [x] Prevent disposed, stale, or out-of-order loads from replacing the newest source - [x] Keep loading, saving, conflict, empty-file, and open-file actions off canvas ### 6. Asynchronous persistence and conflicts - [x] Snapshot the current in-memory authored root after normal mutations - [x] Serialize/coalesce rapid edits per resolved Asset and always prepare against the latest local snapshot - [x] Allow independent Assets to save concurrently without scope leakage - [x] Use one revisioned document session and one ordered save queue per Asset, even when multiple Content Blocks or render scopes reference it - [x] After a shared Asset changes, rematerialize every connected occurrence without persisting their generated instances to project data - [x] Pin the resolved Asset and exact loaded revision for each write - [x] Recheck authorization immediately before storage - [x] Ensure local queued edits never produce stale-revision conflicts with each other - [x] On a genuine external revision conflict, preserve local content, stop writes, and enter the standard reload-required state - [x] Keep failed non-conflicting writes retryable without discarding local content - [x] Finish already accepted persistence writes after a Content Block unmounts or switches source - [x] Cancel obsolete loads, materializations, and UI updates after unmount, reload, or source switch - [x] Dispose project-scoped roots, queues, parse caches, failure state, generations, and session subscriptions when the Asset session is replaced - [x] Invalidate Asset resources and synchronize open file editors after successful writes - [x] Keep multi-root persistence ordered, serial, and non-atomic; report partial completion without rollback - [x] Do not add Asset-history undo/redo; native text-editor undo remains local to the open editor ### 7. Content mode parity - [x] Empty connected blocks remain selectable and expose the normal Content-mode `+` affordance - [x] First insertion renders immediately - [x] Enter creates and focuses the next paragraph immediately - [x] Slash commands work in newly created empty paragraphs - [x] Deleting one selected instance deletes exactly that instance - [x] Mouse and keyboard moves use the same operation and permissions - [x] Preserve sibling reorder, nested reparenting, and moves between editable Content Blocks where `main` permits them - [x] Preserve content-editable props such as Link `href` - [x] Preserve copy, paste, cut, multi-cut, wrapping, unwrapping, grid insertion, selection, Navigator order, and canvas order - [x] Cover mutation routing centrally, retain the full unconnected Builder suite, and exercise representative connected interactions in real Builder E2E ### 8. Template names and permissions - [x] Resolve only exact user-facing names from the direct flat Templates list - [x] Enforce unique names within each Templates list - [x] Reject duplicate names during rename with inline validation - [x] Allocate unique names during insert, paste, duplicate, move, wrap, and unwrap - [x] Apply valid template properties using the same permissions as Content mode - [x] Preserve and warn about ignored design-only, invalid, or stale properties - [x] Preserve template shell provenance without serializing expanded template internals - [x] Generate deterministic materialized IDs from source identity, render scope, and authored usage path so focus/selection survives saves - [x] Warn before renaming or deleting referenced templates; files remain unchanged - [x] Provide shared AST-based rename/remove migration operations for MCP-assisted multi-file cleanup ### 9. Scope, frontmatter, and diagnostics - [x] Scope materialized content by Content Block ID plus exact Collection-item/render context - [x] Prevent repeated instances and dynamic candidates from leaking generated IDs, template resolution, or diagnostics across scopes while sharing the underlying Asset source and revision where applicable - [x] Remove frontmatter editing from Settings; edit the exact YAML through the MDX Asset file editor - [x] Preserve the exact frontmatter source byte-for-byte during canvas body saves - [x] Route canvas body changes and complete-file editor saves through one revisioned per-Asset coordinator - [x] Show a source warning indicator in Settings and precise source-located diagnostics in the Asset editor - [x] Deduplicate repeated diagnostics without losing distinct locations - [x] Keep unresolved-template placeholders selectable and accessible only in Builder ### 10. Asset references, transfer, and integrity - [x] Discover and rewrite Asset references in frontmatter, Markdown links/images, and MDX properties - [x] Preserve Asset references while editing unrelated content - [x] Include referenced Asset and template revisions in dependency/cache identity - [x] Route referenced Assets through published URL rewriting - [x] Validate Content Block source integrity during project import, fragment/page transfer, copy/paste, build integrity, and pre-publish audit - [x] Allow multiple Content Blocks and dynamic render scopes to reference the same MDX Asset without treating the connection as an integrity error - [x] Preserve Templates when copying a connected Content Block - [x] Preserve direct and dynamic Content Block source bindings when copying or pasting within the same project - [x] When copying only one rendered Collection item, resolve that item’s current MDX Asset and replace the copied Content Block’s dynamic source with a direct binding to that same Asset - [x] When copying an entire Collection, preserve the Collection, its instances, and its dynamic source bindings - [x] Preserve the complete MDX source and frontmatter by reference; copying a connected block must not rewrite the shared file - [x] During cross-project transfer, copy every discoverable distinct bound MDX Asset and rewrite transferred bindings to the destination Assets - [x] If some cross-project dynamic candidates cannot be discovered or copied, continue with successful copies, preserve what can be represented safely, and warn about skipped candidates - [x] Revalidate source revisions and the destination project before applying a cross-project transfer - [x] If cross-project Asset creation or project insertion fails, leave the source project unchanged and clean up any newly reserved destination Asset - [x] Use the same transfer operation through Builder and MCP ### 11. Dynamic sources and publication - [x] Resolve dynamic bindings once per render/save scope - [x] Require finite, discoverable candidate sets for publication and load no unrelated MDX - [x] Warn and skip unbounded, missing, unreadable, malformed, or unsafe sources without failing the complete build - [x] Materialize only rendered Content Blocks; ignore Templates definitions and `src` on non-Content-Block instances - [x] Skip unresolved template subtrees while keeping valid siblings - [x] Include selected template styles, fonts, resources, unresolved names, and referenced Asset revisions in generated dependency output - [x] Keep draft-only MDX Assets out of publication retention ### 12. Builder, MCP, CLI, and shared operations - [x] Use the same converters, source lifecycle, revision checks, persistence service, diagnostics, and template migrations in Builder and MCP - [x] Keep frontmatter editing file-based; retain whole-frontmatter runtime operations only where compatibility requires them - [x] Avoid Builder-only or MCP-only mutation/conversion implementations - [x] Regenerate runtime/API contracts from their source definitions - [x] Update CLI Content Engine reference and generated MCP documentation ### 13. Verification and delivery - [x] Add regression tests that reproduce failures from the previous implementation, including double deletion and blocked rendering - [x] Cover two Content Blocks sharing one Asset: edits from either block serialize once, update both canvases, preserve scope-specific Templates, and cannot overwrite a newer local snapshot - [x] Verify new tests fail against the broken implementation and pass with the corrected behavior - [x] Run SDK, Content Engine, Asset Uploader, Project Build, Builder, React SDK, CLI, Protocol, and HTTP Client affected suites and typechecks - [x] Run real Builder E2E for source lifecycle, live file refresh, empty insertion, Enter/slash focus, Link props, delete, keyboard reorder, switching, disconnect, conflicts, unresolved templates, dynamic sources, and repeated scopes - [x] Regenerate shared project fixture bundles and verify a second generation leaves the tree clean - [x] Run lint, package boundaries, `pnpm oxfmt --check`, and `git diff --check` - [x] Review and update authoritative `docs/` content and navigation - [ ] Run the complete agent evaluation suite — not run because it requires separate explicit approval ### 14. Content-mode parity and disconnect handoff - [x] Allow keyboard reordering in Content mode through the normal move command while keeping the editable Content Block boundary - [x] Let already accepted Asset writes drain independently before resetting the source; disconnect does not load, flush, or convert the file - [x] Remove MDX-to-instance copying from disconnect - [x] Reset `src`, remove the derived tree, and leave the ordinary Content Block empty - [x] Preserve automatic text-editor focus after inserting editable content from the template menu - [x] Remove Builder frontmatter-save UI and report complete-file save failures through the Asset editor - [x] Add regression coverage for keyboard movement, disconnect teardown, source switching, insertion focus, and paragraph deletion focus restoration - [x] Run the complete six-scenario MDX Content Block Builder E2E suite ### 15. Final architecture review fixes - [x] Keep one canonical ordered pending document per Asset so shared Content Block occurrences cannot conflict with one another - [x] Merge ordered local edits from different occurrences while preserving text changes, insertions, deletions, and sibling reordering; keep external revisions on the strict reload-required path - [x] Centralize typed render-scope parsing, repeated-occurrence detection, scoped variable lookup, and dynamic Asset resolution across Canvas, Settings, source lifecycle, and copy/paste - [x] Capture the owning Asset session when a save is accepted so normal unmount/source-switch teardown cannot redirect or lose it - [x] Dispose project-owned roots, queues, caches, generations, failure state, and subscriptions when replacing the project Asset session - [x] Add regression coverage for same-Asset edits from two occurrences, same-node last-write ordering, structural reorder, insertion preservation, scoped source resolution, and project cleanup - [x] Re-run affected full unit suites, typechecks, production build, static checks, and all six MDX Content Block Builder E2E scenarios ### 16. Final persistence and transfer hardening - [x] Drain every accepted per-Asset edit before project-session teardown while retaining the owning authorization context - [x] Drain canvas serialization queues and revisioned Asset writes before pre-publish audit and publication - [x] Block publication on a queued serialization failure or Asset revision conflict - [x] Copy actual Asset bytes during cross-project paste, preserve MDX reference names, rewrite direct and Collection-backed Asset IDs, and clean up newly created Assets when insertion fails - [x] Include every resolved dynamic MDX source when copying an entire Collection and warn while preserving successful copies when individual Assets cannot be transferred - [x] Keep MDX editor save failures visible with retry and route conflicts through the standard reload-required flow - [x] Give keyboard nested reparenting the same editable Content Block boundary used by pointer movement - [x] Add regression coverage and rerun the complete Content Engine and Builder unit suites plus type, lint, formatting, package-boundary, and diff checks ## Current rebuild status - The connected Content Block now owns one complete MDX document: frontmatter feeds designed-shell bindings and the explicit Body outlet owns the authored MDX body. - Builder and published output resolve the same frontmatter document graph, including nested document references and Asset references. - Direct frontmatter text/property edits use the existing ordered per-Asset session; referenced-document values remain file-owned. - Repeated Collection occurrences keep isolated runtime shell/Body identities and occurrence-specific document values. - The local blog article layout has been upgraded to the document/Body model and its bindings validate cleanly. - Full affected package suites and typechecks pass; every new regression was demonstrated fail/pass. - `pnpm lint`, package boundaries, `pnpm oxfmt --check`, generated API/docs checks, fixture builds, and `git diff --check` pass. - Full fixture synchronization is blocked by the development API rejecting this local CLI version before fixture generation; existing fixture bundles build successfully. - Complete agent evaluations remain pending explicit approval. ### 17. Treat Content Block source as a property - [x] Declare Content Block `src` in component metadata as a Design-mode initial property labeled **Source** - [x] Add the short property description: “Create an .mdx file in Assets, then select or bind it here.” - [x] Accept only a direct Asset or an expression resolving to an Asset ID; reject URL/string sources, missing Assets, and non-MDX Assets - [x] Extract and reuse the Image-style Asset picker and binding presentation without duplicating source-control UI - [x] Render Source through the normal properties section and remove the separate source-section placement and special `src` filtering - [x] Route Source changes through Content Block connect, switch, and disconnect lifecycle operations instead of generic prop updates - [x] Keep connect confirmation, Open, diagnostics, and persistence state attached to Source; remove frontmatter and disconnect UI - [x] Add regression coverage for direct Assets, dynamic Asset bindings, invalid resolved values, lifecycle operations, and Design/Content mode visibility - [x] Re-review authoritative `docs/` content for the Source-property UI change and update it if required ### 18. Source property UX - [x] Show one full-width bindable Connect .mdx file button while disconnected - [x] Show equal-width filename and Open buttons while connected - [x] Switch files from the filename button through the source lifecycle - [x] Override PropertyLabel reset and Alt-click with the disconnect lifecycle - [x] Preserve confirmation, pending, failure, repeated-scope, and dynamic-source behavior - [x] Add regression coverage for connect, switch, binding, reset, and disconnect - [x] Update Content Block documentation - [x] Run affected tests, typecheck, lint, formatting, package boundaries, and diff checks ### 19. Reduced file-owned frontmatter follow-up This checklist supersedes the earlier structured-frontmatter and disconnect-copy behavior. Frontmatter remains file-owned and is edited only in the MDX Asset editor. #### A. Remove structured frontmatter UI - [x] Remove the JSON frontmatter editor and unused Builder controller/state - [x] Keep source mutation Design-mode-only; show connected Source read-only in Content mode and allow authorized editors to open the complete file - [x] Retain runtime frontmatter APIs only where compatibility requires them #### B. Preserve source and separate validation - [x] Preserve the exact frontmatter envelope during every canvas body save without parsing/stringifying YAML - [x] Preserve comments, ordering, quoting, whitespace, BOM, newline style, delimiters, and invalid but closed YAML - [x] Keep the existing unsupported-node/property MDX recovery; do not add an ad hoc partial parser - [x] Parse body and frontmatter independently so either valid half remains usable - [x] Keep bounded Asset-query frontmatter extraction unchanged - [x] Treat structurally malformed MDX as having no safe body tree #### C. Share Asset state with the raw editor - [x] Route canvas and complete-file changes through one ordered, non-blocking per-Asset coordinator - [x] Update canvas and clean raw editors immediately from shared in-memory source - [x] Reject stale dirty-editor saves, preserve unsaved text, and require reload; never force-overwrite - [x] Drain accepted writes after source replacement/disconnect and report background failures globally - [x] Dispose sessions only after they have no consumers and no queued work #### D. Connect, replace, and disconnect - [x] Load and diagnose before connect; block only unreadable/unauthorized/non-MDX Assets - [x] Show **Abort / Connect** for non-empty blocks, including diagnostics and the recoverable-content warning - [x] Set `src` and delete persisted children through one runtime mutation - [x] Switch to a loaded source without waiting for the previous Asset's network save - [x] Remove disconnect confirmation and conversion - [x] Reset `src` immediately, discard the derived tree, leave the block empty, and preserve the Asset - [x] Resetting a bound source leaves every repeated occurrence empty #### E. Dynamic and shared sources - [x] Keep one source/revision state per Asset and a separate derived instances tree per occurrence - [x] Resolve Templates independently per Content Block and preserve Builder-only missing-template placeholders - [x] Resolve bound `src` from the selected Collection occurrence - [x] Make **Open** use the occurrence's resolved Asset; update the filename and disable Open when unresolved - [x] Add direct/bound tests including Collection item A opening `a.mdx` and item B opening `b.mdx` #### F. Diagnostics, MCP, and publication - [x] Show an accessible warning icon beside Source with the first diagnostic, line/column, and remaining count - [x] Show precise YAML/MDX diagnostics in the Asset editor without repetitive canvas/toast UI - [x] Reuse parser/diagnostic/revision contracts in Builder, build, publication, and MCP - [x] Keep MCP frontmatter editing file-based and return structured diagnostics for complete-source writes - [x] Emit build warnings; published sites skip invalid/unsupported content without diagnostic UI #### G. Verification and documentation - [x] Add fail/pass regressions for source preservation, independent validation, stale raw saves, lifecycle, dynamic Open, shared Assets, and cleanup - [x] Run affected tests, typechecks, lint, formatting, package boundaries, fixtures, and diff checks - [x] Open Markdown and MDX editors at twice the default dialog size with the right-side preview visible initially - [x] Document canvas body editing, file-owned frontmatter, Content-mode Asset access, and cloning an MDX Asset for a new post - [x] Perform a final correctness, data-loss, DRY, simplification, accessibility, and performance review - [x] Keep this checklist synchronized with implementation status ### 20. Content-mode component properties - [x] Show a connected Content Block Source read-only in Content mode with an active **Open** action - [x] Keep source switching, binding, reset, and disconnect available only in Design mode - [x] Expose HTML Embed code and preserve Code Text's code-editor metadata on authored Text Content - [x] Audit every registered component and expose authored payload while keeping design, structure, and behavior controls in Design mode - [x] Keep media dimensions and Code Text theme Design-only while preserving adapter-owned intrinsic Image metadata during MDX round trips - [x] Add exact component-permission and regression coverage - [x] Update authoritative component documentation - [x] Run affected full suites, typechecks, formatting, lint, package boundaries, and generated contract/documentation checks ### 21. Designed document shell and Body outlet - [x] Add one structural **Content Block Body** outlet and keep legacy Content Blocks without it compatible - [x] Materialize and persist only `document.body` children through the Body outlet while preserving the surrounding designed shell and Templates - [x] Expose the connected document frontmatter through a Content Block `document` parameter for shell text and property bindings - [x] Write direct frontmatter-bound text and properties back through the same ordered per-Asset session without blocking canvas mutations - [x] Resolve document `$ref` dependencies and Asset references consistently in Builder and published output - [x] Keep referenced-document values read-only on canvas and direct editors to the referenced file - [x] Isolate repeated Collection occurrences while retaining occurrence-specific source, frontmatter, shell, and Body content - [x] Render the same designed shell, frontmatter values, and Body substitution in generated/published output - [x] Upgrade the local blog article layout to bind title, excerpt, dates, author data, and images from frontmatter and render MDX through Body - [x] Add fail/pass regressions for nested Body discovery, lifecycle, permissions, repeated values, document references, and generated shell rendering - [x] Update authoritative Content Block documentation - [x] Run affected tests and typechecks, formatting, lint, package boundaries, generated API/docs checks, and fixture builds ### 22. Final nested references and frontmatter editing - [x] Keep direct frontmatter-bound text and property controls editable in Content mode without exposing or replacing their bindings - [x] Keep referenced-document values read-only and preserve legacy instance-property name normalization - [x] Render direct frontmatter text bindings through the plain-text editing path - [x] Resolve nested legacy and structured Asset references from referenced Markdown/MDX frontmatter - [x] Preserve missing Asset references, emit structured `ASSET_NOT_FOUND` diagnostics, and keep them out of the document graph - [x] Add fail/pass regressions for the real Settings control and root/nested missing Asset-reference cases - [x] Fix exact Content Block selection after the Body node appears in Navigator - [x] Run full affected suites/typechecks, all six MDX Content Block E2E scenarios, deterministic fixture builds, generated checks, lint, formatting, package boundaries, and diff checks ### Before merge - [x] Resolve #6261: Nested Asset references in referenced Markdown frontmatter work consistently in Assets queries, previews, publication, and static export ### 23. Explicit writable expression bindings - [x] Add an explicit `readwrite` mode to expression bindings; existing expressions remain read-only by default - [x] Accept `readwrite` only for direct static member paths and centralize their parsing and validation - [x] Require the expression root to provide a writable data source; initially support the connected Content Block document frontmatter - [x] Update Content Block permissions, canvas text editing, and property controls to require a valid writable binding - [x] Persist direct frontmatter edits through the existing ordered per-Asset session - [x] Create new direct frontmatter bindings with `readwrite` mode and migrate existing compatible bindings - [x] Preserve writable mode through schemas, serialization, loading, copy/paste, transfer, and export - [x] Add fail/pass regressions for valid paths, derived expressions, unsupported sources, permissions, persistence, and compatibility - [x] Review authoritative `docs/` content and update it if the persisted binding contract affects user-facing documentation - [x] Reject unsafe frontmatter paths and reject `readwrite` bindings outside a connected Content Block document - [x] Preserve expression binding mode through the public HTTP client and document the MCP authoring contract - [x] Limit frontmatter value write-back to Content mode so Design mode retains normal binding replacement/reset behavior - [x] Keep bindings inside Templates and across nested Content Block ownership boundaries read-only - [x] Upgrade compatible legacy bindings even when the Content Block is disconnected during migration - [x] Run affected tests, typechecks, formatting, lint, package boundaries, fixture checks, and `git diff --check` Verification: full SDK (567), Project Build (2,277), and Builder (2,695) suites pass, along with affected Expression, Migration, Template, HTTP Client, and MCP suites; typechecks, lint, formatting, package boundaries, and diff checks pass. Generated contracts are refreshed. Fixture synchronization remains blocked before generation because the development API rejects this local CLI version as incompatible. The checked-in bundles pass the current Protocol suite and every fixture build with the current bundle version. |
||
|
|
7e7c14868a |
fix: Preserve read-only guides and publish targets (#6266)
## Summary - Route explicit read-only `meta.guide` requests to focused discovery tools and exclude mutations, side-effecting session tools, broad design context, and visual verification. - Require explicit task scope, specialized workflow, authored-fragment routing, and design-system reuse instead of inferring behavior from brief prose. - Persist the requested staging or production target in new SaaS deployment records. - Return the same target from publish list and job status, with backward-compatible inference for historical records. ## Todo - [x] Reproduce the read-only custom-code audit misrouting from #6262. - [x] Add failing regressions and implement strict read-only routing. - [x] Remove behavior-affecting prose inference from CLI/MCP guide routing. - [x] Reproduce the single-domain production target mismatch from #6263. - [x] Add create-to-list/status regressions and persist the explicit target. - [x] Cover historical deployment records that predate the stored target. - [x] Verify production create → list → get-job through the staging deployment. - [x] Regenerate and verify project fixtures against the changed bundle contract. - [x] Review documentation impact and update the generated MCP manual. - [x] Review the complete diff for correctness, compatibility, duplication, and unnecessary complexity. ## Verification - Real staging publish for #6263 — passed; create, list, and get-job consistently reported `production` for a one-domain publish. The supplied project has no custom domains, so the custom-domain variant was not available. The job remained `pending` during this check. - Real local CLI/MCP verification for #6262 — passed; no mutation or side-effecting tools leaked. - `pnpm --filter @webstudio-is/protocol test -- src/fixtures.test.ts` — 17 passed - `pnpm -r fixtures:build` — passed for all eight fixtures - `pnpm --filter @webstudio-is/project-build test` — 2,134 passed - `pnpm --filter webstudio test` — 1,037 passed; the one payload-size regression was fixed and its targeted test passed - `pnpm --filter @webstudio-is/domain test` — 24 passed - `pnpm --filter @webstudio-is/sdk test` — 519 passed - Builder API router test — 30 passed - Relevant package typechecks — passed - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` - Regression tests were demonstrated failing against the previous behavior and passing with the fixes. - Agent evaluations were not run because they require separate explicit approval. Closes #6262 Closes #6263 |
||
|
|
cbe4950cd0 |
fix: Use available package manager for previews (#6251)
## Summary - Use the npm or pnpm launcher that started Webstudio for preview dependency installation, builds, and server startup. - Use pnpm-compatible isolated-install flags and report the selected package-manager path on failure. - Preserve the existing installed-dependency reuse path before package-manager resolution. ## Technical choices - Read the standard `npm_execpath` metadata already supplied by npm and pnpm; users do not need to configure another environment variable. - Run JavaScript launchers such as `pnpm.cjs` with the selected Node runtime, supporting bundled Node distributions without adjacent npm. - Keep the existing npx-to-npm mapping and fallback behavior unchanged. - Distinguish numeric package-manager exit codes from process-launch errors such as `ENOENT`. ## Todo - [x] Reproduce the bundled Node + pnpm + missing adjacent npm failure. - [x] Add fail-before/pass-after coverage for dependency installation, production build, and preview startup. - [x] Reuse the detected pnpm launcher. - [x] Preserve installed-dependency reuse. - [x] Include the selected launcher path in installation failures. - [x] Report package-manager exits and process-launch errors accurately. - [x] Review documentation impact and update the CLI manual plus generated MCP documentation. - [x] Review fixture impact; no fixture inputs or outputs are affected. ## Verification - Focused install diagnostic regression suite — 28 tests passed. - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm --filter webstudio test` — 1,029 of 1,030 tests passed; an existing process-supervisor cleanup test hit a transient `ENOENT`, then passed 4/4 when rerun in isolation. - Generated documentation checks passed. - Real pnpm JavaScript launcher invocation with isolated preview install flags. - Agent evaluations were not run because they require separate approval. Closes #6250 |
||
|
|
130d371759 |
perf: Skip resources in statically hidden subtrees (#6233)
## Summary - Skip read-time resources scoped to an instance with literal `show=false` or any descendant of that instance. - Use the same static reachability rule in the Builder client preloader and CLI-generated published resource map. - Keep dynamic `show` expressions on the existing loading path because their result may depend on resource data. ## Data path and performance In the Builder, the client-side resource request set now excludes statically hidden subtrees before requests enter the preloader. For generated sites, the CLI still scans project instances and props during build, but removes statically hidden subtrees from the page build data. Their read resources therefore never enter the generated server-side resource map and no corresponding resource network request runs during page rendering. This removes request and server/network cost for literal-`false` subtrees. It does not remove build-time project scanning, and resources under dynamic conditions still load. ## Compatibility - No project schema or persisted data changes. - No migrations. - Action-bound resources retain their existing explicit-trigger behavior. - Dynamic `show` expressions retain current behavior. ## Checklist - [x] Add shared static-subtree reachability logic. - [x] Apply it to Builder preview resource preloading. - [x] Apply it to generated/published resource collection. - [x] Add Builder and generated-output regressions for direct, descendant, visible, and dynamic cases. - [x] Demonstrate the new regressions fail against the previous behavior and pass with the implementation. - [x] Review authoritative `docs/` content; no documentation update is required because the UI and authoring workflow are unchanged. - [x] Review fixture inputs and outputs; no fixture contains this resource/show combination, so fixture regeneration is not required. ## Verification - `pnpm --filter @webstudio-is/sdk test` - `pnpm --filter @webstudio-is/react-sdk test` - `pnpm --filter @webstudio-is/builder exec vitest run app/shared/nano-states/props.test.tsx` - `pnpm --filter webstudio build:content-runtime` - `pnpm --filter webstudio exec vitest run src/prebuild.test.ts` - Typechecks for SDK, React SDK, Builder, and CLI - Targeted `oxlint --deny-warnings` - `git diff --check` Agent evaluations were not run because they require separate explicit approval. Closes #6232 |
||
|
|
9e504037fb |
fix: improve MCP reliability across project workflows (#6222)
## Summary Fixes the reproducible MCP, preview, redirect, audit, mutation, and asset-upload failures from the latest issue batch. Historical and non-reproducible reports were investigated without speculative fixes. Visual verification is now opt-in unless the user explicitly requests it. ## Issue checklist - [x] #6207 — report tested recovery when an explicitly selected browser fails to start. - [x] #6208 — accept generic and registered buttons as valid label targets without requiring a separate form label. - [x] #6209 — reject unknown style coordinates such as `breakpointId` and document the supported `breakpoint` field. - [x] #6210 — traced Node 18 access to CLI 0.293.0 predating the launcher guard; closed as already fixed by #6201. - [x] #6211 — verified the supported launcher blocks the reported Node 18 crypto path; closed as already fixed by #6201. - [x] #6212 — give sequential responsive captures the sum of their per-capture timeout budgets. - [x] #6213 — keep preview install, build, and server subprocesses on the parent CLI Node runtime. - [x] #6214 — add safe confirmation and diagnostics for ambiguous mutation responses; this does not claim to remove upstream latency. - [x] #6215 — confirmed as the same historical Node 18 release path as #6210; closed as already fixed by #6201. - [x] #6216 — verified malformed input returns structured errors on current main; closed as not reproducible and improved future failure diagnostics. - [x] #6217 — add transaction-id confirmation for large fragment mutations after ambiguous 5xx responses; this does not make the operation asynchronous. - [x] #6218 — verified the existing DevTools reconnect fix from #6205; closed as already fixed. - [x] #6219 — preserve the incoming pathname and query when a redirect target supplies only a hash. - [x] #6220 — return ordered `uploaded`, `failed`, and `ambiguous` results so partial asset successes are not lost or retried unsafely. - [x] #6221 — verified parser recovery without a Node crash; closed as not reproducible and improved future JSX failure diagnostics. - [x] #6223 — verified browser-session reuse, reconnect, and cleanup; closed as already fixed by #6205 after the reported CLI version. - [x] #6224 — expose both text-asset sources and encode the exactly-one requirement in the standard MCP schema. - [x] #6225 — could not reproduce the project-specific upstream timeout; closed with safe confirmation coverage and improved structured diagnostics, without claiming a latency fix. - [x] #6226 — could not reproduce the project-specific upstream timeout; closed with safe confirmation coverage for insert-fragment, without adding a speculative fragment-specific fix. - [x] #6229 — reproduced the reported two-process sequence with the current local CLI and a real browser; both captures passed, so the 0.293.0 report was closed without a speculative fix. - [x] Require explicit user consent before preview, screenshots, diffs, OCR, or rendered visual audits unless visual verification was requested. ## Technical notes - Ambiguous mutation responses are confirmed only with the same idempotent transaction id. If confirmation is also ambiguous, the session reports `AMBIGUOUS_COMMIT`, refreshes state, and never replays a fresh mutation. - CLI error mapping retains the original remote error as a non-enumerable cause, so JSON gateway status reaches the ambiguity classifier without exposing raw remote context in serialized diagnostics. - Forced asset uploads are not automatically retried after an unknown/network/5xx outcome. Batch results retain the original input index, including duplicate filenames. - Stable issue codes and constraints are retained for diagnostics. Arbitrary validation paths, messages, argument values, project content, and raw contextual data are excluded. - The MCP handshake remains the source of tool input schemas; goal-specific guides avoid duplicating those contracts and reduce model-context cost. - `update-asset-content` now exposes `path` and `content` with a machine-readable `oneOf` constraint, matching the runtime rule that exactly one source is required. - Redirect targets with their own pathname or query still replace those request components. - Generated runtime contracts, CLI documentation, product documentation, and deployment fixtures were regenerated from their sources. ## Verification - [x] Three independent review/test agents exercised visual consent and preview behavior; mutation, asset, and privacy behavior; and accessibility, styles, and redirects. - [x] `pnpm checks` passed after the final transport follow-up: all workspace tests and typechecks, lint with warnings denied, package boundaries, generated API contracts, generated docs and documentation checks, and the complete fixture link/sync/build pipeline. - [x] Changed-package suites passed, including Project Build (2,125 tests), HTTP client (42 tests), CLI, Protocol, and Builder. - [x] Complete `pnpm evaluations` run on the preceding implementation commit: all five real-world fixtures and every behavioral check passed. Four baseline comparisons passed; one font-assets sample exceeded only its model-output token allowance, and its isolated rerun passed. Evaluations were not rerun after the final transport and schema follow-ups because fresh approval is required. - [x] Design evaluation MCP response bytes improved from the 39.8 KB baseline to 37.6 KB after removing duplicated guide contracts. - [x] Documentation impact reviewed; generated MCP docs and multi-file upload guidance are updated. ## Related issues Closes #6207 Closes #6208 Closes #6209 Ref #6210 Ref #6211 Closes #6212 Closes #6213 Ref #6214 Ref #6215 Ref #6216 Ref #6217 Ref #6218 Closes #6219 Closes #6220 Ref #6221 Ref #6223 Closes #6224 Ref #6225 Ref #6226 Ref #6229 |
||
|
|
626b5e741b |
fix: Reduce discovery for authored fragments (#6203)
Ref #6177 Ref #6154 ## Outcome Bounded authored-fragment requests no longer receive broad design/authentication context bundles, registry discovery, or design-token operations through generic keyword matching. The initial ProjectSession synchronization is unchanged. Focused target reads, missing nested schemas, and expression guidance can still add calls when the requested fragment requires them. ## Root cause `meta.guide` treated the generic word `design` as visual intent and allowed workflow-specific context bundle tools to enter ordinary keyword-ranked recommendations. An authored component insertion could therefore be classified as visual work and receive `inspect-design-context` even without a supplied visual reference or a request to reuse the project design system. ## Implementation - Give specialized goal guides stable IDs and return structured routing metadata with the matched workflow and broad context tools. - Keep `inspect-auth-context` and `inspect-design-context` exclusive to their specialized workflows. - Treat Figma, screenshots, supplied designs, and explicit design-system references as visual intent without treating every use of `design` as visual work. - Suppress component/template registry discovery for explicit `insert-fragment` or authored-fragment requests. - Suppress design-token operations for those requests unless the brief explicitly asks for design-system or token reuse. - Preserve the existing design-input workflow for Figma, screenshots, and supplied designs. ## Todo - [x] Add a regression test for the reported authored timer/component workflow. - [x] Demonstrate that the regression test fails before the routing fix and passes afterward. - [x] Preserve explicit design-input discovery and verification behavior. - [x] Add machine-readable workflow routing metadata. - [x] Review documentation impact and update the authoritative MCP manual plus generated GitBook output. - [x] Review fixture impact; no fixture inputs or generated fixture bundles are affected. - [ ] Run the complete local agent evaluation suite. It was not run because repository policy requires separate explicit approval and approval was not provided. ## Verification - Project-session MCP tests: 117 passed. - Project-build and CLI typechecks passed. - Targeted oxlint passed. - Documentation generator tests and documentation typecheck passed. - MCP documentation and CLI generated docs were regenerated twice with stable hashes. - `git diff --check` passed. ## Tradeoffs and limitations - Brief classification remains deterministic intent matching; clients still decide which recommended tools they actually call. - The change prevents broad context tools from being recommended generically but does not enforce a universal discovery-call limit. - A fragment that genuinely needs existing tokens, unfamiliar expressions, or unknown target structure can still require focused discovery. - No schema migration, project-data migration, or fixture regeneration is required. |
||
|
|
df3601c26a |
fix: Capture preview failure diagnostics (#6206)
## Summary - Give invalid project bundles a stable `PROJECT_BUNDLE_INVALID` error code and structured validation issues. - Remember the latest failed MCP tool call and attach sanitized diagnostics to automatic issue reports. - Render the tool, error code, bundle contract, and invalid schema paths in a dedicated issue section. ## Scope and issue assessment This PR improves diagnostics; it does not change which asset shapes `preview.start` accepts. Issue #6198 came from CLI 0.290.0 and did not include the rejected field, value, or bundle contract, so its exact root cause cannot be established. Node 22 is not implicated by the available evidence. Canonical video assets were added separately in #6189, which may explain an old-CLI schema mismatch, but that relationship is an inference rather than a confirmed reproduction. Per project triage policy, this PR closes #6198 despite being diagnostics-only. If the failure still exists on a current CLI, the enriched report will provide enough evidence to reopen or file a new actionable issue. ## Implementation Bundle validation exposes structured paths such as `assets.0.type`. The MCP host records the latest failure and injects it into CLI-owned runtime metadata when `report-issue` is called. The MCP registry supplies either a canonical known tool name or `unknown`. Stable error codes are validated once by the CLI error-code boundary. Detailed paths are included only for `PROJECT_BUNDLE_INVALID`, capped at 30 issues, and omit received values, error messages, examples, filenames, IDs, details, and stack traces. The bundle-contract field remains optional so reports from older CLI versions still validate. CLI-owned runtime metadata is not advertised as model-authored MCP input, keeping the handshake compact and making ownership explicit. ## Checklist - [x] Add structured bundle validation diagnostics. - [x] Capture the latest MCP failure in issue-report runtime metadata. - [x] Render deterministic diagnostics in GitHub issue bodies. - [x] Add fail/pass regression coverage and privacy constraints. - [x] Keep CLI-owned runtime fields out of the model-facing MCP schema. - [x] Regenerate the server-only API contract. - [x] Review documentation impact — no product documentation changes are required; this only enriches internal anonymous issue reports. - [ ] Run agent evaluations — not run because repository policy requires explicit approval. ## Verification - Real Node 22.22.1 stdio MCP run with an isolated malformed local bundle returned `PROJECT_BUNDLE_INVALID`, path `assets.0.type`, code `invalid_value`, and constraint `one_of:["image"]`. - The following real `report-issue` call was accepted by the server and deduplicated to existing issue #6198; it created no duplicate issue and changed no linked project. - Project-build: 2,115 tests passed. - CLI: all 1,005 unaffected tests passed; one unrelated process-supervisor timing test failed once and its exact two owner-disconnect cases passed on immediate rerun. - Project-build and CLI typechecks passed. - Formatter and diff checks passed. - All latest GitHub workflows passed, including both test/typecheck matrices, visual regression, size and generated checks, packaged SSG, and all six Builder E2E shards. Closes #6198 |
||
|
|
f2cece41ee |
fix: Reconnect responsive screenshots after preview restart (#6205)
## Summary Reconnect the reusable browser capture session and retry once when a managed screenshot reports that its Browser DevTools connection closed. The active generated-site preview remains running, so the retry recreates only the failed browser session and replays the requested single or multi-viewport capture. ## Root cause Vision already performs a bounded recovery inside its browser runtime. If that recovery still surfaced a DevTools session closure, the MCP preview handler reset the failed session during error cleanup but returned the failure to the caller. The next manual screenshot call could succeed, but the first screenshot after a preview restart still failed. ## Technical choices - Give browser-session closure errors a stable typed code at the Vision boundary. - Detect that typed failure in the MCP preview handler. - Close and recreate only the reusable browser capture session. - Retry the complete capture once against the existing active preview. - Apply the same recovery to one-viewport and responsive batch captures. - Report the reconnect as a screenshot lifecycle progress checkpoint. ## Impact A one-viewport responsive screenshot after preview restart now recovers automatically from a closed DevTools connection. Other screenshot errors retain their existing behavior, and repeated connection failure remains bounded. ## Checklist - [x] Add a fail-first regression for preview restart followed by a one-viewport responsive capture - [x] Recreate the failed browser session without restarting the active preview - [x] Retry the complete screenshot request once - [x] Preserve existing behavior for non-session errors - [x] Verify the recovery through a real preview server, Chrome, CDP, rendering, and PNG output - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected - [x] Review documentation impact: no update is required because this restores documented automatic screenshot behavior - [ ] Run agent evaluations (requires separate explicit approval) ## Verification - Regression failed before the implementation with `Browser DevTools connection closed.` and passed after it - Real-browser harness with Google Chrome: - restarted a real local HTTP preview and captured a full-page `1440×900` PNG successfully on the first call - forcibly closed the real CDP socket during `Page.captureScreenshot` twice and confirmed the lower browser retry surfaced the typed session-closed failure - confirmed the MCP handler created a new browser session, replayed the full capture successfully, and emitted `tool screenshot reconnecting browser session` - confirmed browser recovery did not restart the active preview - closed all Chrome processes, preview resources, temporary profiles, and screenshot artifacts - `pnpm --filter webstudio exec vitest run src/commands/mcp-preview.test.ts` — 44 tests passed - `pnpm --filter @webstudio-is/vision test` — 13 files, 81 tests passed - `pnpm --filter webstudio typecheck` - `pnpm --filter @webstudio-is/vision typecheck` - `pnpm exec oxlint --deny-warnings packages/vision/src/screenshot-browser-cdp.ts packages/cli/src/commands/mcp-preview.ts packages/cli/src/commands/mcp-preview.test.ts` - `pnpm exec oxfmt packages/vision/src/screenshot-browser-cdp.ts packages/cli/src/commands/mcp-preview.ts packages/cli/src/commands/mcp-preview.test.ts` - `git diff --check` The DevTools failures were injected deterministically at the screenshot command. The ordinary post-restart capture used the same real preview and Chrome path without fault injection. Agent evaluations were not run because repository policy requires separate explicit approval. Closes #6200 |
||
|
|
b1d23f69c0 |
fix: Report unsupported Node versions at CLI startup (#6201)
## Summary - Reject unsupported Node.js versions before loading the CLI bundle. - Report the declared engine range and detected version with an install-and-retry instruction. - Keep the runtime check aligned with `package.json#engines.node`. ## Root cause The CLI declares Node.js 22.12+ but did not enforce that requirement at startup. Package managers can warn and continue, allowing unsupported runtimes to reach preview code. Execa 10 then initializes `Set.prototype.union()`, which is unavailable in Node 20 and causes the delayed `screenshot.responsive` failure. ## Technical choices - Validate the runtime directly at the published executable boundary. - Parse the declared engine range with `semver`. - Dynamically import the CLI only after the runtime passes validation. - Report the exact engine range rather than assuming every valid range means “or newer.” - Test the published `bin.js` in a subprocess with an injected unsupported runtime version. - Write the actionable startup failure to stderr and exit nonzero. - No migrations or public API changes. ## Checklist - [x] Add the startup runtime guard. - [x] Add executable-level regression coverage for unsupported Node.js. - [x] Verify the supported runtime still loads the CLI. - [x] Review fixture impact; no fixture inputs or outputs are affected. - [x] Review authoritative documentation; `docs/university/cli.md` already requires Node.js 22.12+, so no update is needed. - [ ] Run agent evaluations — not run because the requester declined them. ## Verification - Published and local launcher tests: 4 passed. - CLI typecheck: passed. - Targeted lint and formatting: passed. - CLI production build: passed. - Node.js 18.16.1 and 20.12.2 executable checks: exited 1 before loading the CLI, reported the `>=22.12.0` requirement, and wrote no stdout. - Node.js 22 executable check: CLI loaded successfully. - Package dry run: includes the guarded `bin.js` and no separate runtime helper. - `git diff --check`: passed. - The executable-level regression test was confirmed to fail against the previous message/implementation and pass after the direct guard was applied. ## Known limitation An MCP client may wrap a subprocess startup failure in its own UI, but the CLI now provides the actionable requirement and installation instruction on stderr before any tool runs. Closes #6190 |
||
|
|
a2e01a8ebe |
fix: Export configured Webhook Form methods (#6192)
## Summary
- Add an optional metadata contract for copying allowlisted resource
fields into generated component props.
- Pass action resources into page component generation.
- Configure Webhook Form's resource-bound `action` prop to generate the
form's `method` prop.
- Preserve explicitly authored props over generated resource props.
- Add generic generator, schema safety, rendered static-export
regression coverage, and updated generated fixture output.
## Root cause
Builder stores a Webhook Form's selected method on its action resource,
not as an ordinary instance prop. Component generation serialized the
resource-bound action identifier but had no generic contract for copying
safe resource fields into component props. The generated component
therefore received `action={"action"}` without the configured method,
and plain HTML rendering omitted the `method` attribute.
## Implementation
Resource prop metadata can now declare same-named fields using
`generatedProps`:
```ts
generatedProps: ["method"]
```
The component generator resolves those declarations generically; it
contains no Webhook Form component checks. The schema currently
allowlists only `method`, so resource URLs, headers, bodies, and other
potentially sensitive configuration cannot be generated as component
props. An explicit instance prop with the same name takes precedence.
Dynamic routed Webhook Forms retain their existing browser-to-server
POST behavior. This change preserves configured resource metadata in
generated component output and does not add static Webhook submission
support.
## Todo
- [x] Reproduce the missing method from an existing resource-bound
Webhook Form.
- [x] Demonstrate the generator regression test fails against the
previous output.
- [x] Define a typed, allowlisted generated-props contract for
resources.
- [x] Apply generated props generically without component-name checks.
- [x] Preserve explicit instance props.
- [x] Verify a real SSG prerender contains `method="post"`.
- [x] Verify unsafe resource fields such as `url` cannot be generated.
- [x] Give the build/prerender regression test the established 30-second
timeout.
- [x] Regenerate and verify the affected Webstudio Features fixture.
- [x] Run affected lint, typechecks, unit suites, builds, and CLI
prebuild tests.
- [x] Review documentation impact; no update is needed because
configuration and static-site support constraints are unchanged.
## Verification
- Regression test before implementation: failed because resource-bound
forms contained `action` but no generated `method`.
- `@webstudio-is/sdk`: 517 tests passed; focused schema test passed
after the rename.
- `@webstudio-is/sdk-components-react`: 126 passed, 1 skipped.
- `@webstudio-is/react-sdk`: 140 tests passed; focused generator test
passed after the rename.
- CLI prebuild: 59 tests passed; focused rendered static HTML test
passed in 2.7 seconds with a 30-second test timeout.
- Webstudio Features fixture: regeneration is idempotent; typecheck and
production build passed.
- Typechecks: SDK, SDK components, React SDK, and CLI.
- Targeted formatting and `oxlint --deny-warnings`.
- React SDK and CLI builds.
- `git diff --check origin/main...HEAD`.
- Agent evaluations were not run because approval was not requested.
Closes #6191
|
||
|
|
2df130171f |
feat: Resolve asset references as structured metadata (#6184)
## Summary - add exact `$ref` asset values that resolve to Asset Manager metadata - keep plain local asset paths returning URL strings for backward compatibility - derive reference metadata from the canonical asset object so newly added asset fields flow through automatically - let Assets query output fields select only the metadata returned, including nested arrays - carry the same resolved shape through preview, generated preview, published runtime, and static export - document the syntax and accessible image binding in Content Engine and MCP docs ## Design The source document declares only the relationship: ```yaml featureImage: $ref: ./assets/hero.png ``` The Assets query controls projection with fields such as `properties.featureImage.src` and `properties.featureImage.description`. Selecting `properties.featureImage` returns the canonical Asset Manager asset metadata together with the resolved `src`. The Content Engine runtime contract accepts the canonical asset object instead of maintaining a second metadata field list; `url` becomes `src`, and internal `contentRef` is not exposed. Plain strings retain their existing URL-string result. Existing document `$ref` behavior is preserved by resolving structured asset metadata only when the target is a known non-document asset. ## Verification - [x] Content Engine full test suite: 298 tests - [x] SDK full test suite: 517 tests - [x] Asset repository tests: 39 tests - [x] CLI prebuild tests: 58 tests - [x] Content Engine, SDK, Asset Uploader, CLI, and Project Build typechecks - [x] Repository lint - [x] Content Engine and MCP documentation generation and tests - [x] Generated API check - [x] Local fixture build and generated fixture update - [x] New behavior tests demonstrated fail before/pass after the implementation - [ ] Complete fixture sync (development API currently rejects this branch's newer CLI protocol; local fixture build passes) - [ ] Agent evaluations (not run; require explicit approval) ## Checklist - [x] Local structured references return field-selected metadata - [x] Newly added canonical asset fields flow through without a Content Engine whitelist change - [x] Plain-path queries remain backward compatible - [x] Nested object and array projection - [x] External URL strings remain usable - [x] Missing or null descriptions allow `??` fallback to the title - [x] Expanded metadata counts toward query result-size limits - [x] Documentation impact reviewed and Content Engine and MCP docs updated - [ ] Missing asset targets return a non-failing unresolved value and dedicated diagnostic - [ ] Apply the resource and Image binding changes to the separate Webstudio blog project ## Known limitation A `$ref` whose asset target no longer exists is not yet converted into an unresolved asset value with a dedicated diagnostic. This PR intentionally does not claim that acceptance criterion yet. Ref #6179 |
||
|
|
d4a876bc35 |
fix: Report terminated MCP single-op calls (#6187)
## Summary - return structured `MCP_CALL_TERMINATED` output when a one-shot MCP call receives SIGHUP, SIGINT, or SIGTERM, or reaches `beforeExit` without a result - reuse the existing bounded host-cleanup and signal-preservation path from `mcp run` - cover the reported anchor → inline SVG → `pointer-events: none` fragment through the real MCP normalization path ## Evidence and scope The reported fragment itself does not hang: it normalizes in about 20–30 ms on both CLI 0.290.0 and current main, including Node 26.0.0. The reproducible gap is in the surrounding process lifecycle: `mcp run` reports interrupted calls, while `mcp single-op-call` had no termination handlers. An external caller timeout could therefore end a one-shot call without a structured result. The original long-running project-session condition could not be reproduced with the available credentials. This PR fixes the missing termination diagnostic; it does not claim that nested SVG parsing caused the stall. ## Technical choices - Install termination handling before input parsing and project-session startup so every active phase is covered. - Re-check termination after every asynchronous preflight phase so refreshes and mutations cannot start during cleanup. - Stop reporting the call as active once success or failure output is ready, preventing duplicate JSON during cleanup. - Preserve the original terminating signal after bounded cleanup instead of converting it to an ordinary exit. - Do not add an arbitrary operation timeout: a timed-out committed mutation can still finish remotely and would make retry safety ambiguous. ## Todo - [x] Reproduce the reported fragment on CLI 0.290.0, current main, and Node 26.0.0 - [x] Add structured termination reporting to `mcp single-op-call` - [x] Cover the nested SVG style input and termination payload - [x] Exercise the installed one-shot `beforeExit` lifecycle, not only the payload formatter - [x] Stop execution after asynchronous checkpoint preflight resumes from termination - [x] Review documentation impact — existing CLI docs already promise structured JSON for failed one-shot calls; no content update is required ## Verification - Nested-SVG reporter regression demonstrated fail-before (`reportMcpSingleOpCallTermination is not a function`) and pass-after - Installed-lifecycle regression demonstrated fail-before when the active-call hook was disabled and pass-after when restored - `pnpm --filter webstudio exec vitest run src/commands/mcp.test.ts` — 43 passed - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint --deny-warnings packages/cli/src/commands/mcp.ts packages/cli/src/commands/mcp.test.ts` - `pnpm --filter webstudio exec vitest run src/bin.test.ts` — 3 passed - `pnpm --filter webstudio test` — 998 passed; two unrelated concurrent-suite timeouts (`src/bin.test.ts` and `evaluations/high-impact/fixture-api.test.ts`). The launcher test passed in isolation. The evaluation fixture was not rerun because evaluations require separate approval. ## Known limitations - SIGKILL cannot be intercepted, so no process can emit a final diagnostic in that case. - This change does not impose an internal operation deadline or cancel in-flight mutations. - A real authenticated reproduction is still needed to identify why the original project-session call remained active. Ref #6132 |
||
|
|
0760d6cfec |
fix: upload videos from Builder and MCP (#6189)
## Summary Video uploads failed because file detection returned `video` while the canonical Asset schema accepted only `font | image | file`. The mismatch was introduced when video detection was added in #5539; the recent JSON work only exposed the adjacent contract gap and did not cause it. This makes `video` a first-class `Asset["type"]` across Builder, SDK, storage formatting, project bundles, HTTP uploads, and MCP. There is no separate upload-only type and no conversion from `video` to `file`. ## Implementation - Add the canonical `video` Asset variant with width/height metadata. - Make Builder UI reservations and optimistic assets preserve `video`. - Make MCP and HTTP upload schemas derive their enum from the canonical SDK `assetType`. - Preserve video metadata through S3 and filesystem upload paths. - Include canonical video assets in project/canvas bundles. - Keep legacy video records without dimension metadata readable as generic `file` assets. - Fall back to a labeled file preview when the browser cannot decode a video format such as AVI; browser-supported formats continue to render video thumbnails. - Regenerate runtime operation contracts and sync fixtures from the PR deployment. ## Contract protection - Assert every detected upload category parses as a canonical Asset type. - Exercise Builder reservations for every value in `assetType.options`. - Assert MCP's upload enum exactly equals `assetType.options`. - Exercise direct HTTP video upload metadata and URL construction. - Cover canonical video formatting, legacy fallback, preview assets, and canvas serialization. - Verify a video decode error replaces the blank media element with a visible format-labeled fallback. - Store canonical WebM and MP4 records with dimensions in the `webstudio-features` fixture and verify generated runtime metadata. ## Checklist - [x] Make video a canonical Asset type - [x] Verify Builder UI upload flow - [x] Verify MCP and direct HTTP upload contracts - [x] Add fail/pass regression coverage for the broken paths - [x] Add an Assets panel fallback for browser-unsupported video formats - [x] Regenerate runtime contracts - [x] Sync and build fixtures against the PR deployment - [x] Run affected package tests, typechecks, lint, package-boundary, generated API, and generated docs checks - [x] Review documentation impact — existing Assets documentation already lists supported video formats and upload behavior; no user-facing documentation change is required ## Verification - Builder: 2,543 tests passed - Builder asset thumbnail regression: 14 tests passed - Project build/MCP runtime: 2,111 tests passed - CLI: 999 tests passed - SDK: 516 tests passed - Asset uploader: 199 tests passed - Protocol: 92 tests passed - HTTP client: 38 tests passed - Typechecks passed for Builder, SDK, asset uploader, project build, protocol, HTTP client, and CLI - Lint and package-boundary checks passed - Generated API and documentation checks passed - Fixture sync completed against `fix-video-up-be4d8a0.development.webstudio.is` - All fixture builds passed after synchronization Closes #6186 |
||
|
|
5a57234c75 |
revert: Store Content Block content in MDX assets
Revert the accidental merge of #6125 so the implementation can continue in draft PR #6181. |
||
|
|
5ec3547d36 |
fix: Support JSON content files in Builder (#6168)
## Summary - make the complete asset filename editable in Asset settings - convert existing editable text assets when their extension changes while preserving the asset ID - accept every JSON root type and normalize JSON-compatible syntax into formatted strict JSON - expose the same optional extension change through MCP/API `update-asset-content` - initialize new JSON files and empty text-to-JSON conversions with a valid empty object - distinguish browser URL imports from JSON file uploads so JSON objects with a root `url` field remain file content - update the Assets and Content Engine documentation ## Root cause Asset settings rendered the extension as a fixed suffix outside the name input. The metadata rename mutation could only change the display basename, while content revisions always inherited the current storage extension. As a result, changing `.md` to `.json` was impossible in the UI and unavailable through the shared MCP/API revision command. Asset settings now edits the complete filename. Ordinary renames keep using the metadata mutation. A text-extension change loads the current content, validates it for the target format, and writes a new immutable revision through the existing conflict-safe content endpoint. The existing Acorn-backed `parseJsonExpression` utility accepts JSON-compatible syntax without evaluating code and serializes it as strict JSON. Objects, arrays, strings, numbers, booleans, and `null` are all accepted. ## Checklist - [x] Create JSON files by entering a `.json` filename - [x] Edit the complete filename in Asset settings - [x] Convert editable text-file extensions while preserving the asset ID - [x] Expose extension conversion through `update-asset-content` - [x] Create JSON files and convert empty text files with a valid empty object - [x] Normalize safe JSON-compatible syntax to strict JSON - [x] Accept objects, arrays, and scalar JSON roots - [x] Reject executable or incomplete content - [x] Preserve browser-uploaded JSON object shapes - [x] Review and update authoritative Builder documentation - [x] Add focused UI, revision, HTTP-client, CLI/MCP, protocol, and upload regression tests - [x] Run affected typechecks, lint, documentation checks, and the Builder production build - [ ] Manually verify create, edit, rename `.md` to `.json`, reload persistence, and Content Engine query in a browser - [ ] Run the complete local agent evaluation suite if approved ## Verification - 217 focused tests passed across Builder, asset revisions, HTTP client, CLI/MCP, and protocol - Builder, asset-uploader, HTTP-client, protocol, CLI, and project-build typechecks passed - Builder production build passed - MCP and Content Engine documentation checks passed - `oxlint` on changed TypeScript files passed - `git diff --check` passed - Regression tests were demonstrated failing before the implementation and passing afterward A disposable E2E database and PostgREST stack bootstrapped successfully in the earlier real-path test, but UI automation remained blocked because no controllable browser was available. Fixture inputs and generated fixture outputs are not affected. Agent evaluations were not run because approval is required and was not requested. Closes #6167 |
||
|
|
81d5148046 |
fix: canonicalize trailing-slash page URLs (#6173)
## Outcome Canonical page URLs now omit a trailing slash in Webstudio Cloud sites and exported JavaScript applications. A request such as `/about/?campaign=launch` receives a permanent `301` redirect to `/about?campaign=launch`, preventing both URL variants from serving identical page content. The behavior is implemented once in the generated root redirect handler, so it covers fixed and dynamic application routes without generating an extra route per page. Exact project redirects remain authoritative. Protocol-relative-looking paths such as `//example.com/` are left untouched so canonicalization cannot become an external redirect. Static exports cannot redirect requests themselves. Their URL behavior remains host-specific and is documented for Cloudflare Pages, Netlify, Vercel, and other static hosts. ## Implementation - Add one shared pathname normalizer in the SDK. - Apply canonicalization after exact authored redirect matching in both generated application runtimes. - Ignore repeated leading slashes before constructing a redirect location. - Extend redirect-loop detection to model the implicit canonical redirect. - Regenerate the affected fixture applications from their templates. - Document application canonicalization and host-specific static export behavior. ## Todo 1. [x] Add central trailing-slash canonicalization. 2. [x] Preserve query strings, encoded path segments, and the root path. 3. [x] Cover concrete dynamic URLs without per-route generation. 4. [x] Preserve explicit project redirect precedence. 5. [x] Detect redirect loops that pass through canonicalization. 6. [x] Prevent protocol-relative external redirects. 7. [x] Regenerate and review fixture output. 8. [x] Review documentation impact; document application and SSG behavior. 9. [x] Run targeted and repository-level verification. ## Verification - SDK tests: 548 passed - SDK typecheck: passed - Project Build tests: 2,379 passed - Project Build typecheck: passed - CLI tests: 997 passed; two tests timed out only while three package suites ran concurrently, then both affected files passed in isolation (6/6) - Redirect regression suite after security follow-up: 302 passed - CLI typecheck: passed - `pnpm lint`: passed - `pnpm check:package-boundaries`: passed - `pnpm fixtures`: passed - Documentation internal anchors and Markdown whitespace: checked - New regression tests were confirmed failing before their implementations and passing afterward - Agent evaluations were not run because they require separate explicit approval Closes #6172 Closes https://github.com/webstudio-is/webstudio/issues/4327 |
||
|
|
86b6310fff | feat: Store Content Block content in MDX assets | ||
|
|
af11ec211f |
feat: Search all local project data from MCP (#6165)
Ref #6154 ## What - Add standalone search across all 13 synchronized Builder namespaces. - Search in the CLI ProjectSession and send only paged matches to the model; initial synchronization is unchanged. - Return stable match ids, exact paths, entities, references, and affected routes. - Preserve deprecated `scopes` output, redact recognized credential fields, and document the command. ## Objectives - [x] O1 — Universal Builder namespace search - [x] O2 — Stable identity and actionable location - [x] O3 — Filters, pagination, route impact, and references - [x] O4 — Honest synchronization → local search → model-input boundary - [x] O5 — Standalone command and workflow documentation - [x] O6 — Safety, compatibility, typed contracts, and regression tests Verified by Atlas (implementation), Scribe (docs/workflow), and Sentinel (adversarial review). ## Remaining #6154 work - [ ] Atomic semantic multi-record updates - [ ] Targeted route rendering and assertions - [ ] General slow-operation consent and time budgets - [ ] Full agent evaluation suite after approval ## Verification - Project search + MCP: 129 tests passed - Protocol docs: 8 tests passed - CLI schema/docs: 23 tests passed - Compact MCP handshake budget test passed - Project-build, protocol, and CLI typechecks passed - Generated docs and API checks passed - Agent evaluations not run; approval is required ## Limitation Asset metadata is searchable. Asset binaries and document contents are not Builder namespace data and are not searched. |
||
|
|
4ca695cf46 |
fix: Improve MCP screenshot and session compatibility (#6163)
## Summary Allow responsive MCP screenshots to use local project data and remove the CLI session storage dependency on the Web Crypto global. ## Root causes - Responsive capture rejected every `source: "local"` request before preview preparation, even though the generated preview and reusable browser session support local data. - Local screenshot inputs skipped collision-free port resolution. - Project session revisions and restore-point IDs called `crypto.randomUUID()` through the ambient global. Environments without the Web Crypto global failed after otherwise successful mutations. - The production/session route-generation failure from #6161 is no longer reproducible on current `main`; the exact reported flow succeeds, so this PR does not add a speculative change for it. ## Technical choices - Resolve an available preview port for local generated screenshots using the existing screenshot port path. - Permit local and session sources through the same responsive generated-preview capture path. - Keep mixed preview targets and mixed browser configurations rejected. - Import `randomUUID` from `node:crypto` for session revisions and restore points. - Preserve explicit URL and `baseUrl` capture behavior. ## Impact A single `screenshot.responsive` call can prepare a local project once, reuse the configured browser, and capture desktop, tablet, and mobile viewports. Native MCP mutations can persist their session state without requiring the Web Crypto global. ## Checklist - [x] Add fail-first coverage for local responsive preview preparation and port allocation - [x] Add fail-first coverage for session persistence without the Web Crypto global - [x] Verify a real local CLI capture at 1440×900, 768×1024, and 390×844 - [x] Verify the production/session scenario from #6161 on current `main` - [x] Run the complete CLI test suite - [x] Run CLI typecheck and lint - [x] Review documentation impact: no user documentation changes are required because this restores the documented MCP behavior - [ ] Run agent evaluations (requires explicit approval) ## Verification - `pnpm --filter webstudio test` — 62 files, 983 tests passed - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint --deny-warnings packages/cli/src/commands/mcp-preview.ts packages/cli/src/commands/mcp-preview.test.ts packages/cli/src/project-session.ts packages/cli/src/project-session.test.ts` - `git diff --check` - Real local-source production capture returned HTTP 200 at all three viewports using one generated preview and the requested Chrome executable Closes #6156 Closes #6160 Ref #6161 |
||
|
|
baa48232fc |
fix: Keep Assets routes out of the static sitemap (#6158)
## Summary - keep Assets-backed dynamic path discovery and SSG prerendering unchanged - stop merging Assets-derived paths into `$resources.sitemap.xml` - keep eligible static pages in the generated sitemap - update the existing Assets prerender integration test to cover static sitemap behavior ## Why The CLI used one Assets query result for both route generation and sitemap indexing. Renderability and indexability are separate concerns, and automatic insertion could duplicate entries from a custom `/sitemap.xml` page. The Builder already exposes only static sitemap data, so generated production output should match it. ## Compatibility and release note Assets-backed dynamic routes are no longer added automatically to the static sitemap. Existing projects that relied on that behavior need to add those routes explicitly to a custom `/sitemap.xml` page with an Assets resource and Collection. This `fix:` PR is included in the repository's generated release notes under **Fixes**. ## Technical choices - Removed only the Assets-derived sitemap collection and merge. - Left `getAssetResourcePrerenderPaths()`, query evaluation, route generation, prerendering, and draft filtering unchanged. - Continued using `getStaticSiteMapXml()` as the sole source of generated sitemap entries. ## Verification - Regression demonstration before the implementation change: the updated targeted test failed because `/blog/hello-world` was present in `$resources.sitemap.xml.ts`. - After the implementation change, the targeted integration test passed and successfully built/prerendered `/blog/hello-world`. - `pnpm --filter webstudio test -- src/prebuild.test.ts` — 58 tests passed. - `pnpm --filter webstudio typecheck` — passed. - `pnpm exec oxfmt --check packages/cli/src/prebuild.ts packages/cli/src/prebuild.test.ts` — passed. - `pnpm exec oxlint --deny-warnings packages/cli/src/prebuild.ts packages/cli/src/prebuild.test.ts` — passed. - Agent evaluations were not run, per request. - Fixture regeneration was not needed because no fixture inputs or outputs changed. ## Todo - [x] Invert the existing Assets prerender sitemap assertion. - [x] Demonstrate that the regression test fails with the old behavior. - [x] Remove Assets-derived sitemap collection and merging. - [x] Confirm dynamic Assets routes still build and prerender. - [x] Confirm drafts stay excluded and eligible static pages stay included. - [x] Review documentation impact. - [x] Review the authoritative `docs/` content: the Content Engine guide already directs users to build and draft-filter a custom sitemap for dynamic Assets entries, and the XML Node guide documents combining it with the static Sitemap resource; no docs change is required. - [x] Document the compatibility change for generated release notes. Closes #6157 |
||
|
|
dbfb0a9849 |
fix: Preserve variable font styles (#6153)
## Summary Preserve font style metadata for variable fonts so upright and italic files from the same family produce distinct `@font-face` rules. Variable fonts with an `ital` or `slnt` axis are also registered for the matching CSS styles. ## Technical choices - Detect `normal`, `italic`, and `oblique` from the font binary, preferring OS/2 `fsSelection`, then `post.italicAngle`, then the existing subfamily parser. - Add `style` to variable-font metadata while defaulting legacy stored records to `normal`. - Keep update metadata partial and strict, but accept and persist `style` and `variationAxes` together so a `get-asset` result can be written back. - Group generated font faces by family, style, and browser-selectable variable descriptors so separate upright and italic files cannot overwrite each other. - Regenerate the runtime operation contracts from the updated schema. ## Checklist - [x] Add regressions using real upright and italic Inter variable-font binaries. - [x] Cover style detection, metadata compatibility, updates, and generated font-face selection. - [x] Verify the final stylesheet contains distinct upright and italic `@font-face` rules. - [x] Verify the public asset update contract accepts a complete variable-font metadata object. - [x] Review documentation impact and update the custom-font guide. - [x] Regenerate and verify runtime API contracts. ## Verification - `@webstudio-is/fonts`: 14 tests and typecheck passed. - `@webstudio-is/asset-uploader`: 198 tests and typecheck passed. - `@webstudio-is/sdk`: 514 tests and typecheck passed. - `@webstudio-is/project-build`: 2,094 tests and typecheck passed. - CLI: 980 tests and typecheck passed. - Builder typecheck passed. - `pnpm lint`, `pnpm check:package-boundaries`, `pnpm check:generated-api`, and `pnpm check:generated-docs` passed. - Regression tests were demonstrated failing against the previous behavior and passing with the fix. - Fixture builds regenerated successfully with no diff. Full remote fixture sync was attempted, but the deployed API rejected the source CLI contract as incompatible. - Agent evaluations were not run because they require separate explicit approval. Closes #6150 |
||
|
|
05118e0f22 |
fix: recover from browser startup failures (#6135)
## Summary Recover screenshot and rendered-audit capture when a discovered Chromium executable fails before its DevTools endpoint becomes ready. The CLI now tries the next compatible installed browser for standalone screenshots, reusable captures, and multi-viewport capture batches. When no candidate starts, the error identifies every attempted executable and its startup failure. ## Root cause Browser discovery stopped after selecting the first executable that existed on disk. If that executable aborted, failed to spawn, or never exposed its DevTools endpoint, capture failed even when another supported browser was installed. Startup failures also crossed the Vision/CLI package boundary through an untyped string code, and concurrent captures could duplicate failure diagnostics. ## Technical choices - Define the typed `BrowserStartupError` contract in Vision. - Keep executable discovery and fallback ownership in CLI, where all browser candidates are known. - Share one fallback loop across standalone capture, reusable capture, and viewport batches. - Treat an explicit `browserPath` as strict and never launch a different executable. - Reuse the first successful browser session and deduplicate concurrent startup failures by executable path. - Preserve original startup causes while adding aggregate executable diagnostics. ## Checklist - [x] Classify browser exits, synchronous spawn failures, and DevTools startup timeouts. - [x] Fall back across compatible installed browsers. - [x] Cover standalone, reusable, and multi-viewport capture paths. - [x] Preserve strict explicit-browser behavior. - [x] Aggregate all failed executable paths and causes. - [x] Deduplicate concurrent failure diagnostics. - [x] Demonstrate each regression failing before and passing after the fix. - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected. - [x] Review documentation impact: no user-facing documentation changes are required. ## Verification - `pnpm --filter webstudio test` — 62 files, 978 tests passed - `pnpm --filter @webstudio-is/vision test` — 13 files, 79 tests passed - `pnpm --filter webstudio typecheck` - `pnpm --filter @webstudio-is/vision typecheck` - `git diff --check` - Independent subagent reproduction and post-fix harness verification passed for standalone capture, reusable capture, viewport batches, explicit paths, aggregate failures, session reuse, and concurrent failures. The full agent evaluation command was not run because it requires separate approval. ## Known limitation The exact nested SVG fragment from #6132 completes on current main and the reported CLI release, so this PR does not claim to fix or close that issue. Closes #6133 Closes #6134 Ref #6132 |
||
|
|
42f5291168 |
fix: Reconcile MCP commits and Cloudflare scaffold types (#6131)
## Summary - confirm ambiguous project commits by retrying the exact transaction ID before treating a version conflict as a rejection - share the confirmation path between normal mutations and restore-point commits - emit an explicit sitemap entry type so an empty sitemap remains type-safe - generate and publish TypeScript declarations for `@webstudio-is/wsauth` - regenerate affected CLI fixtures ## Root cause The project API already treats the latest transaction ID as idempotent, but ProjectSession interpreted the first `CONFLICT` response as a rejected write. If the original transaction had committed, the subsequent refresh exposed the requested values while the tool still reported failure. The Cloudflare scaffold had two independent type-contract gaps: an empty generated sitemap inferred `never[]`, and the wsauth declaration build inherited a shared output directory, leaving its published package without the declaration files referenced by its exports. ## Technical choices - Retry only a version conflict, once, with the same base version and transaction ID. A confirmed retry returns the committed server version; persistent conflicts continue through the existing refresh/retry-safe flow. - Use the same confirmation helper for regular patch and restore-point transports. - Keep the generated sitemap module standalone by emitting its concrete entry type inline. - Make the wsauth declaration config extend its package config and publish nested `lib/types` output. - Preserve existing API payloads and server idempotency behavior; no migration is required. ## Todo - [x] Reproduce and cover ambiguous committed mutations - [x] Reuse conflict confirmation for restore-point commits - [x] Cover empty sitemap typechecking - [x] Generate and inspect the wsauth package declarations - [x] Regenerate affected fixtures - [x] Verify the Cloudflare fixture typecheck and production build - [x] Review documentation impact — no user-facing documentation changes are required ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,092 tests passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter webstudio test` — 972 tests passed - `pnpm --filter webstudio typecheck` - `pnpm --filter @webstudio-is/wsauth test` - `pnpm --filter @webstudio-is/wsauth typecheck` - `pnpm --filter @webstudio-is/wsauth build && pnpm --filter @webstudio-is/wsauth dts` - `npm pack --dry-run --json` in `packages/wsauth` — both public declaration entrypoints included - `pnpm -r fixtures:build` - `pnpm --filter webstudio-cloudflare-template typecheck` - `pnpm --filter webstudio-cloudflare-template build` - focused formatting, lint, and `git diff --check` Agent evaluations were not run because they require separate explicit approval. Closes #6129 Closes #6130 |
||
|
|
146e65fe0d |
fix: Forward fragment token conflict resolution (#6122)
## Summary - expose `conflictResolution` on both JSX fragment MCP tools - derive the JSX-facing fragment contract from the Builder runtime contract instead of maintaining a second handwritten field list - preserve `conflictResolution`, `contentMode`, insertion mode, and insertion index through JSX normalization - verify all 151 MCP-exposed public APIs stay aligned with the generated public API catalog - keep the normal MCP handshake below its size budget while retaining the complete schema in focused discovery - cover direct and verified fragment insertion, shared-contract parity, and reuse of the existing token id ## Implementation The runtime remains the canonical semantic contract for fragment insertion. The MCP adapter now inherits its fields and validation from `insertFragmentInput`, overriding only the transport-specific differences: MCP accepts `fragment` as a Webstudio JSX string and requires `parentInstanceId`. After converting JSX to structured Webstudio data, the adapter validates the result with the same runtime schema used by Builder operations. This removes the duplicated conflict-resolution, content-mode, insertion-mode, and insertion-index definitions. It also restores `contentMode` to the MCP schema, where the previous handwritten contract had omitted it. Builder performance is unchanged because JSX parsing exists only on the MCP boundary; Builder continues to pass structured fragments directly to the runtime. A catalog-wide audit confirmed that the other public API tools already derive their schemas from the generated protocol catalog. There are 152 public APIs: 151 are exposed through MCP and `copy-page` is intentionally hidden because its hydrated `Map` input is not serializable. The only schema adapters are `insert-fragment` and `insert-collection`, where MCP accepts JSX instead of structured fragment data. A permanent test now compares complete semantic field schemas and required fields for every exposed API, including types, enums, constraints, descriptions, branched schemas, and focused schemas that were compacted during the handshake. The collection adapter test also covers all optional insertion controls. The runtime already resolves colliding token names and reuses the target token id when `conflictResolution` is supplied. The complete `insert-fragment` input remains available through focused schema discovery, while its normal handshake representation is compacted to keep the complete tool handshake below the existing 200 KB limit. No migrations or persistence-format changes are required. Existing calls that omit the optional fields keep their current behavior. ## Checklist - [x] Add `conflictResolution` to `insert-fragment` - [x] Inherit the option in `insert-fragment-verified` - [x] Derive shared MCP fields and validation from the runtime fragment contract - [x] Keep JSX parsing and required-parent validation at the MCP boundary - [x] Validate converted JSX with the runtime schema - [x] Restore `contentMode` to the MCP contract - [x] Audit all 152 public APIs for duplicate MCP contracts - [x] Add catalog-wide complete-schema parity coverage for all 151 MCP-exposed APIs - [x] Cover all `insert-collection` insertion controls through the JSX adapter - [x] Demonstrate the new contract and forwarding tests fail when behavior is disabled and pass when restored - [x] Keep the MCP handshake within its existing size budget - [x] Verify `ours` attaches the existing token id without adding a duplicate token - [x] Regenerate and verify runtime API contracts - [x] Run the full fixture sync/build; no fixture changes were produced - [x] Review generated MCP documentation; no documentation output changed - [x] Review documentation impact; no user-facing documentation update is required - [ ] Run agent evaluations (not run because they require separate explicit approval) ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,089 tests passed - `pnpm --filter webstudio test` — 971 tests passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint packages/cli/src/commands/mcp.test.ts packages/project-build/src/mcp.test.ts` - `pnpm exec oxfmt --check packages/cli/src/commands/mcp.test.ts packages/project-build/src/mcp.test.ts` - `pnpm check:generated-api` - `pnpm check:generated-docs` - `pnpm fixtures` Closes #6121 Ref #5928 |
||
|
|
58eaf8c7c9 |
fix: Publish docs independently of release smoke (#6120)
## Summary - finish the `publish` job after npm publication and exact registry-artifact verification - run packaged CLI verification in a separate `release-smoke` job - keep `publish-docs` dependent on successful release creation and package publication, but independent of post-publish smoke results - verify the Codex registration command through `webstudio connect codex --print` in CI instead of requiring an installed Codex client ## Root cause The release workflow ran post-publish CLI smoke verification inside the `publish` job. GitHub therefore marked package publication as failed whenever the smoke failed, even though npm publication had already completed. Because `publish-docs` declared `needs: [release, publish]`, GitHub skipped documentation publication. The recurring failure was the smoke invoking `webstudio connect codex` on a runner without the `codex` executable. ## Technical choices and tradeoffs Package publication remains strict: npm publication and exact registry visibility must both succeed before downstream jobs run. Post-publish smoke verification remains a red, visible release job and still uploads its diagnostic artifact, but it no longer changes the truthful outcome of publication or blocks docs. The Codex package smoke now validates the generated registration command without mutating a real Codex installation. The command subprocess boundary remains covered by the existing focused connect-command tests. No migrations or compatibility changes are involved. ## Todo - [x] Separate post-publish CLI smoke from package publication. - [x] Keep docs gated on successful release and registry publication. - [x] Make Codex connection verification deterministic in CI. - [x] Manually advance the `docs` branch to release 0.290.0. - [x] Review documentation impact: no product documentation update is required because this changes release automation only. - [x] Verify formatting, workflow syntax and topology, CLI tests, lint, and typechecking. - [x] Run the non-model release smoke and record the remaining unrelated failure. ## Verification - `pnpm exec oxfmt --check .github/workflows/release.yml packages/cli/scripts/release-smoke.ts` - parsed `.github/workflows/release.yml` with Ruby Psych - asserted the parsed workflow job graph with the repository's `yaml` dependency - `pnpm --filter webstudio exec vitest run scripts/release-smoke-registry.test.ts src/commands/connect.test.ts` — 22 tests passed - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint packages/cli/scripts/release-smoke.ts` - `pnpm --filter webstudio test:release-smoke` — the corrected Codex path passed; the smoke later reached `preview.start` and failed on an unrelated current-main fixture error: `Project session is missing preview data: assetFolders` Fixture review: this change does not modify fixture inputs or generated fixture outputs. Closes #6119 |
||
|
|
21ca567686 |
fix: Stop owned preview process trees (#6111)
## Summary Supervise generated preview processes so the CLI terminates the complete owned process tree when an MCP session disconnects, a command finishes, or the owner receives a termination signal. Record owned PIDs and report actionable locked-path recovery when cleanup still fails. Closes #6019 ## Technical choices - Start generated previews through a dedicated supervisor process connected to its CLI/MCP owner over IPC. - Disconnect the supervisor to stop a preview; the supervisor owns all descendant cleanup. - Use Execa `killDescendants` for cross-platform process-tree termination instead of maintaining separate Windows and POSIX kill implementations. - Force-stop the owned tree so a descendant that ignores SIGTERM cannot survive its launcher. - Record supervisor and preview PIDs beside the generated preview directory. - Include the supervisor in the CLI build output. ## Implementation checklist - [x] Add owned preview process-tree supervision. - [x] Dispose previews on MCP completion, failure, disconnect, and signals. - [x] Add scoped locked-path diagnostics and recovery instructions. - [x] Add lifecycle and command regression coverage. - [x] Run the CLI typecheck and broader test suite. - [x] Review authoritative `docs/` content; no user-facing documentation changes are needed. - [ ] Run the complete agent evaluation suite after explicit approval. ## Verification - Preview server and supervisor tests: 42 passed. - Full CLI test suite: passed. - CLI typecheck: passed. - CLI production build: passed. - Package-boundary check: passed. - Targeted lint and formatting: passed. - `git diff --check`: passed. - The supervisor-disconnect regression was verified to fail without the new behavior and pass with it restored. - Agent evaluations were not run because repository policy requires separate explicit approval. |
||
|
|
87968f40ff |
fix: Improve MCP authoring and preview reliability (#6105)
## Summary
Fix MCP reliability failures reported in ten issues against CLI 0.288.0
and 0.289.0:
- keep every advertised array input schema client-valid, including
compact and tuple schemas
- report a text asset update as successful when its persisted revision
and bytes confirm that the server committed despite a failed response
- preserve standard package import resolution in generated React Router
previews
- upload variable WOFF2 fonts when callers provide the documented static
font metadata shape
- explain unmatched JSX as a stateless fragment syntax error
- distinguish the `animation` component namespace from value helpers and
reject unsupported CSS at-rules with an actionable validation error
- forward optional session tools such as `download-asset` through
top-level CLI shortcuts
- isolate published generated-preview dependencies from parent
workspaces
- return structured screenshot failures when React Router production
builds fail
Sensitive visual regression checks also run automatically for
organization-authored fork PRs. External fork PRs remain gated by
`safe-to-deploy`.
## Root causes and implementation
The MCP handshake compactor retained an array's type but discarded its
`items` schema. Unconstrained and tuple arrays could also be advertised
without `items`. Schema normalization now adds `items: {}` whenever an
array omits it, while focused discovery retains complete constraints.
Catalog coverage rejects every missing array item, including tuple
schemas, and the handshake remains below its 200 KB budget.
Asset content updates previously treated any failed response as a failed
mutation, even when the server had already swapped the revision.
Recovery now reads the current revision, compares the persisted bytes,
and confirms the revision remains stable across the read. It returns the
updated asset only when all evidence agrees. Otherwise it returns
`ASSET_UPDATE_COMMIT_UNCERTAIN` with guidance not to retry blindly.
Definitive 4xx responses retain their original errors.
The generated React Router Vite config replaced the client and SSR
resolver condition lists without explicitly retaining the standard
`import` condition. Both lists now preserve `import`. The regression
test generates a dynamic route, stages the built React Router SDK as a
published dependency without the local `webstudio` source condition, and
runs the generated build.
Variable fonts are detected with `variationAxes`. Merging the documented
static `style` and `weight` upload metadata into that detected variable
shape made validation fail after the binary was read. Font override
validation and shape-aware merging now live in `@webstudio-is/fonts`.
The SDK delegates to that domain function, which validates the complete
override before applying compatible fields, retains the detected
static-or-variable shape, and keeps the detected format.
Fragment parsing is stateless. Unmatched opening and closing tags now
explain that every opening element must use the same closing tag or be
self-closing, and that refreshing the session cannot repair malformed
JSX.
The `animation` binding is a component namespace, not a callable helper.
Tool schema text, evaluation errors, and the MCP manual now separate
component namespaces from value helpers. The MCP JSX `css` binding
parses the final interpolated CSS with CSS-tree and recursively rejects
selectors and unsupported at-rules such as `@keyframes`, while
preserving supported declarations and case-insensitive `@media` rules.
Keeping this validation at the external binding avoids changing internal
component templates.
CLI shortcut discovery previously omitted optional session tools even
though the runtime registered their handlers. Shortcut discovery now
includes the same optional tool categories as the CLI MCP host, while
real top-level CLI commands keep precedence.
Published generated previews could reuse a stale `node_modules` symlink
into a parent source workspace. Only development manifests containing
the local placeholder version may now reuse the CLI dependency tree.
Published manifests replace symlinks with a local install and disable
npm workspace discovery.
React Router could report a bundler failure while its build command
exited successfully outside CI, allowing screenshot startup to terminate
without a structured result. Managed production builds now set `CI=1`,
so the existing MCP error boundary receives the nonzero build failure
and prints structured JSON.
Visual regression authorization now distinguishes repository members
from external contributors. Organization members' fork PRs run on open,
synchronize, and reopen events; external fork code runs only from a
`safe-to-deploy` label event, and a later commit does not reuse that
approval.
## Implementation checklist
- [x] Preserve valid array item schemas in compact MCP discovery
- [x] Normalize tuple input schemas with an `items` fallback
- [x] Keep the MCP handshake below its 200 KB size budget
- [x] Cover the real `update-props` schema and oversized array
compaction
- [x] Reconcile failed asset-update responses against stable persisted
content
- [x] Reject recovery when a concurrent asset revision is detected
- [x] Preserve `import` resolution in generated React Router client and
SSR builds
- [x] Build a generated dynamic route against a staged published SDK
package
- [x] Regenerate and verify affected React Router fixtures
- [x] Preserve detected variable-font axes with documented upload
metadata
- [x] Add actionable unmatched-tag and unsupported-CSS validation
- [x] Correct animation namespace guidance in tool discovery and errors
- [x] Forward optional session tools through top-level CLI shortcuts
- [x] Replace parent-workspace dependency links for published previews
- [x] Disable npm workspace discovery for isolated preview installs
- [x] Make React Router build failures return nonzero in managed
previews
- [x] Run visual regression automatically for organization-authored PRs
- [x] Verify each regression test fails without its corresponding fix
- [x] Review documentation impact and update the authoritative MCP
manual plus generated outputs
- [x] Confirm no database migration or compatibility migration is
required
- [ ] Run `pnpm evaluations` after explicit approval; not run because
repository policy requires approval before agent evaluations
## Verification
- `packages/cli/src/prebuild.test.ts`: 57 tests passed
- `packages/cli/src/commands/schema.test.ts` and `mcp.test.ts`: 51 tests
passed
- `packages/project-build/src/runtime/components.test.ts` and
`mcp.test.ts`: 194 tests passed
- `packages/asset-uploader`: 196 tests passed
- focused font schema, SDK asset schema, CSS parser, and template CSS
tests passed
- `packages/http-client/src/index.test.ts`: 38 tests passed
- relevant CLI, project-build, asset-uploader, fonts, SDK, CSS data,
template, HTTP client, and React Router SDK typechecks passed
- MCP documentation tests, typecheck, generation, and Markdown source
tests passed
- React Router SDK package build passed
- full fixture link, sync, and generation pipeline passed
- affected Docker and Vercel fixture typechecks and locally bootstrapped
production builds passed
- complete CLI suite: 61 test files and 966 tests passed
- CLI typecheck passed
- preserved nested-workspace dynamic preview installed local `0.289.0`
dependencies and completed its production build
- visual-regression workflow YAML parsing and authorization truth table
passed
- repository lint passed with warnings denied
- formatting and `git diff --check` passed
## Tradeoffs and limitations
Deferred array schemas advertise unconstrained `items` in the compact
handshake to remain client-valid without duplicating detailed
constraints. Agents can retrieve the complete item schema through
focused `meta.get-more-tools` discovery.
Asset reconciliation performs three read requests only after an
uncertain 5xx, malformed response, or transport failure. This keeps the
normal successful path unchanged and avoids claiming success if the
revision changes during recovery.
For variable fonts, detected axes define the metadata shape. Static
`style` and `weight` hints are ignored because they cannot be
represented alongside `variationAxes`; compatible fields such as
`family` still override detection.
Native CSS keyframe authoring remains unsupported in fragment `css`
templates. The tool now rejects it before rendering and directs callers
to editable Webstudio Animation components instead of advertising a
nonexistent callable helper.
Published previews perform one isolated npm install when no valid local
dependency tree is cached. Local source development keeps the fast
workspace symlink path for placeholder-version manifests.
Closes #6104
Closes #6099
Closes #6098
Closes #6106
Closes #6107
Closes #6108
Closes #6114
Closes #6115
Closes #6116
Closes #6117
|
||
|
|
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. |
||
|
|
5c6ffd3148 |
docs: document Content Engine workflows (#6097)
## Summary - add a step-by-step Content Engine guide for building a Markdown article overview and dynamic article page - clarify that the example folder structure is optional and link to the Markdown Blog marketplace template - explain that an AI agent can complete the entire workflow through Webstudio MCP and include a ready-to-use prompt - document frontmatter, JSON files, relative and published asset paths, document references, draft filtering, and single-result resources - document Markdown-to-Markdown, Markdown-to-JSON, JSON-to-Markdown, and JSON-to-JSON document references, including fragments and JSON Pointer escaping - add a schema-aware `webstudio man content-engine` reference for fields, operators, saved and preview inputs, result/output/content modes, diagnostics, limits, and reference syntax - generate the GitBook Content Engine reference and the matching MCP manual section from that shared CLI source - fail documentation generation when result modes, output modes, content modes, diagnostic fields, or Content Engine limits drift from the implementation - add four focused visual-editor screenshots - keep the Assets page focused on asset management and link it to the dedicated Content Engine guide - update MCP Assets examples and the Markdown blog recipe to use Markdown files, `result: "one"`, direct detail bindings, page metadata, and visual verification ## Impact Users get one workflow for treating files as the source of truth while designing article listings and detail pages in Webstudio. The generated reference documents the complete Assets query contract and document-reference system. Agents receive the same reference through the MCP manual, so the product and agent documentation no longer need separate factual copies. This does not change product runtime behavior. ## Checklist - [x] Documentation impact reviewed - [x] Added the Content Engine guide and generated reference to `docs/SUMMARY.md` - [x] Updated related Assets, Data variables, and MCP documentation - [x] Verified internal documentation and image targets - [x] Verified the Markdown Blog marketplace URL returns HTTP 200 - [x] Confirmed the MCP recipe test failed before the recipe correction and passed afterward - [x] Confirmed the schema-coverage test fails when an implemented result mode is omitted and passes after restoration - [x] Confirmed both Content Engine generator tests fail without their corresponding generator behavior and pass after restoration - [x] Ran `pnpm --filter @webstudio-is/project-build test -- src/mcp.test.ts` - [x] Ran `pnpm --filter webstudio test -- src/commands/api-command-docs.test.ts` - [x] Ran the Content Engine and MCP generator tests - [x] Ran project-build and CLI typechecks - [x] Ran `pnpm check:package-boundaries` - [x] Ran targeted lint and formatting checks - [x] Ran `pnpm check:generated-docs` - [x] Verified the final diff and working tree - [ ] Agent evaluation suite: not run because it requires explicit approval Ref #5973 |
||
|
|
93fa799cb8 |
fix: Preserve SSG exports with Assets queries (#6102)
## What changed - Preserve the SSG asset-resource template as a package-relative file URL in the bundled CLI. - Ignore Assets queries that do not bind any parameters from the current dynamic SSG route, while retaining the error for partial or split multi-parameter bindings. - Recognize the persisted `$ws$system.params.*` expression form when enumerating dynamic SSG paths. - Add a required package smoke test that deploys the release-shaped SSG package, runs the packaged CLI, runs Vite and Vike, and verifies rendered Assets data. ## Why Two gaps caused the staging export failures: 1. Vite inlined the template URL as a `data:` URL, which Node could not pass to `readFile`. 2. Dynamic-route validation treated an unrelated Assets query as an incomplete route enumerator. The initial smoke test only checked that an HTML file existed and could pass while resource loading logged a `400`. The replacement test verifies the rendered query result and fails on resource-loading errors. ## Technical choices - The package smoke uses `createPublishedProjectBundleFixture`, so fixture data stays checked against the published bundle contract. - Persisted expressions use `encodeDataSourceVariable`; the generated query now receives the real route parameter instead of compiling to `undefined`. - Temporary deployment, cleanup, subprocess execution, and assertions live in `test:ssg-package`. The workflow invokes one repository command. - Asset downloads are disabled to keep the smoke deterministic. It still covers CLI packaging, the embedded Assets index, dynamic path enumeration, generated resource execution, Vite compilation, and Vike prerender. - The test asserts the queried title in `/posts/hello-world`, rejects any resource-load error, and verifies that an unrelated query does not invent a dynamic path. ## Todo - [x] Reproduce the invalid URL scheme through a bundled template reader. - [x] Preserve the package-relative template URL in the production CLI bundle. - [x] Ignore Assets queries unrelated to the current dynamic route. - [x] Preserve rejection of incomplete multi-parameter route queries. - [x] Support persisted system-variable expressions during route enumeration. - [x] Add a production-shaped packaged CLI and Vike smoke test. - [x] Make the packaged SSG smoke test required on `main`. - [x] Run CLI tests, typecheck, lint, build, and the packaged smoke test. - [x] Rerun the previously failing `WEBSTUDIO-LANDING` SaaS SSG workflow. - [x] Review documentation impact; no user-facing documentation changes are needed. - [x] Review fixture impact; synced fixture inputs and generated outputs are unaffected because smoke data exists only in a temporary deployment. ## Verification - `pnpm --filter webstudio test` — 61 files, 977 tests passed before the final test addition - `pnpm --filter webstudio test -- prebuild.test.ts ssg-asset-resource-fetch-template.test.ts` — 57 tests passed - `pnpm --filter webstudio test:ssg-package` - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm --filter webstudio build` - Package regression proof: the smoke failed on the original unrelated-query implementation with `Dynamic SSG route parameters must be completely enumerated by one Assets query`, then passed with the fix restored. - Persisted-expression regression proof: the focused test returned no prerender path before encoded-system support, then passed with the support restored. - Template regression proof: the focused bundle test failed with `ERR_INVALID_URL_SCHEME` before the fix and passed after it. - Exact SaaS E2E rerun passed: project sync, CLI build, Vike build, archive upload, and database update ([run 31519515809](https://github.com/webstudio-is/webstudio-saas/actions/runs/31519515809)). Closes #6100 Supersedes #6101 after moving the change to the staging branch. |
||
|
|
eb46abf4e5 |
fix: Recover missing preview assets (#6091)
## Summary Fix session-based generated preview startup when the local `.webstudio/assets` directory has not been created yet. - materialize the current session's asset files before compiling the Assets resource index - reuse the existing safe asset downloader so missing parent directories are created and downloads retain retry and temporary-file cleanup behavior - return the stable `PREVIEW_ASSET_DOWNLOAD_FAILED` code with a concrete recovery action when asset access cannot be restored automatically - document the automatic recovery and regenerate the authoritative MCP manual ## Root cause `preview.start` materialized current ProjectSession data and compiled reachable Assets resources before generated-app prebuild. That compilation called `realpath` on the local assets directory, but the session path had never downloaded assets the way `webstudio sync` does. A newly linked project without `.webstudio/assets` therefore failed with `ENOENT` before preview generation. ## Technical choices - Download only after confirming that the project has a reachable Assets resource compilation plan. - Keep canonical path and symlink validation in the filesystem content source after materialization. - Wrap download failures at the preview boundary without exposing local paths or raw remote diagnostics. - Preserve the existing generated-doc source/generator workflow rather than editing generated guidance alone. ## Todo - [x] Reproduce startup from a missing local assets directory - [x] Materialize required session assets before index compilation - [x] Add actionable failure recovery - [x] Add fail/pass regression coverage - [x] Review documentation impact and update the MCP vision guidance - [x] Regenerate the CLI and GitBook MCP manuals - [x] Review fixture impact — no fixture inputs or generated fixture outputs are affected - [x] Run the focused low-reasoning Markdown fixture, including the cold assets-directory scenario - [ ] Deferred: run the remaining agent evaluation fixtures ## Verification - Regression demonstrated failing before the fix with `ENOENT` for the missing assets directory, then passing after the fix. - Recovery regression demonstrated failing with raw `ENOENT`, then passing with `PREVIEW_ASSET_DOWNLOAD_FAILED` and the retry action. - `pnpm --filter webstudio test` — 60 files, 976 tests passed. - `pnpm --filter webstudio exec vitest run src/project-session.test.ts src/mcp-guidance.test.ts` — 25 tests passed after final fixture cleanup. - `pnpm --filter webstudio typecheck` — passed. - Targeted `oxlint --deny-warnings` — passed. - Documentation generation, docs tests, and docs typecheck — passed. The aggregate generated-doc clean-tree guard reports the intentionally changed generated CLI/GitBook outputs included in this PR. - `git diff --check` — passed. - Focused real-world evaluation: `gpt-5.4-mini` with `model_reasoning_effort="low"`, `markdown-blog-v1`, 12/12 MCP calls succeeded, 0 failures, 0 retries, 2 rendered verifications, and all fixture checks passed. - Cold-directory variant: removed `.webstudio/assets` immediately before the first rendered verification; preview restored the required assets, and both verification calls plus content-database checks passed. - Remaining high-impact fixtures were not run; this was the targeted real-world scenario requested for #6090. ## Known limitations Preview startup still requires network and project asset access when required files are not already local. It now reports a stable error and tells the caller to restore access and retry instead of leaking an `ENOENT`. Closes #6090 |
||
|
|
63fcc9c5a6 |
fix: Improve MCP preview verification reliability (#6084)
## Summary Fix the third MCP reliability batch across generated catch-all routes, rendered screenshot evidence, and preview startup diagnostics. ## Root causes - Incremental prebuild rewrote an authored `/*` route with the redirect-only fallback at `routes/$.tsx`. - Screenshot capture trusted the browser writer result without verifying that the output artifact was readable and non-empty. - Generated preview dependency installation had no timeout, and preparation exposed only one broad progress phase. ## Implementation - [x] Preserve authored catch-all HTML routes during full and incremental React Router generation while retaining the redirect fallback when no catch-all page exists. - [x] Probe every single and responsive screenshot artifact before returning success; reject missing, unreadable, or zero-byte output with stable error codes. - [x] Bound generated preview dependency installation to two minutes. - [x] Report session materialization, route generation, dependency preparation, and completion phases through MCP progress output. - [x] Deduplicate preview dependency preparation and MCP progress wiring, flatten generation control flow, and consolidate overlapping test setup. - [x] Add regression coverage and demonstrate each new test failing before its implementation and passing afterward. - [x] Review documentation impact: no documentation update is required because the existing preview and audit workflow is unchanged; this PR makes its generated output and failure behavior reliable. - [x] Review fixture impact and run the full fixture pipeline; no fixture diff was produced. - [ ] Agent evaluations — not run because repository policy requires separate explicit approval. ## Verification - `pnpm --filter webstudio test` — 60 files, 974 tests passed. - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` - `pnpm fixtures` Closes #6081 Closes #6080 Closes #6078 |
||
|
|
dd316c53cc |
fix: Complete interrupted preview workflows (#6076)
## Summary `webstudio mcp run` now emits a terminal structured error when the process is interrupted while an MCP call such as `preview.start` is still active. It preserves completed call results, identifies the unfinished call and terminating signal, attempts preview cleanup, and then propagates the original signal. The MCP runner owns process termination for this workflow so the preview controller cannot race it or propagate the same signal twice. Cleanup is bounded to five seconds so a stalled preview startup cannot prevent termination. ## Todo - [x] Reproduce the missing terminal result for an interrupted `preview.start` call - [x] Report the active call and original signal in structured output - [x] Preserve completed results from the shared MCP session - [x] Clean up preview resources before propagating the signal - [x] Prevent competing MCP-run and preview-controller signal handlers - [x] Add regression coverage and verify it fails before the fix and passes after it - [x] Review for DRY violations and unnecessary abstractions - [x] Review documentation impact; existing CLI documentation already describes the restored terminal JSON behavior - [x] Review fixture impact; no fixture inputs or generated fixture bundles are affected - [x] Run CLI tests, typecheck, lint, package-boundary checks, generated API checks, and generated docs checks - [x] Verify CI; all checks pass or are intentionally skipped except the requested Lost Pixel exemption - [ ] Run the complete local agent evaluation suite (requires explicit user approval) ## Verification - `pnpm --filter webstudio test` — 60 files, 972 tests passed - `pnpm --filter webstudio typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` - `pnpm exec oxfmt --check packages/cli/src/commands/mcp.ts packages/cli/src/commands/mcp.test.ts packages/cli/src/preview-server.ts packages/cli/src/preview-server.test.ts` - `git diff --check` - GitHub CI — all checks passed or skipped except Lost Pixel, which is explicitly excluded Closes #6075 |
||
|
|
e4983b0d1d |
fix: Report unsupported Node versions (#6058)
Closes #6057 ## Outcome Generated projects now reject Node.js versions older than 22.12 before React Router, Remix, or Vite evaluates SDK components. Users see the package-manager engine error with the current and required versions instead of the indirect `sanitize-html` / `htmlparser2` `ERR_REQUIRE_ESM` stack trace. ## Root cause `sanitize-html@2.17.6` synchronously loads the ESM-only `htmlparser2@12`. That dependency combination relies on synchronous `require(ESM)` support, which Node.js enabled by default in 22.12. Generated projects incorrectly declared the broader `>=22` range, allowing an unsupported runtime to reach SSR evaluation. ## Implementation - Set the CLI and all generated base templates to `engines.node: >=22.12.0`. - Add npm `devEngines.runtime` with `onFail: error`, which runs before install, CI, and run commands. - Enable `engine-strict` in generated npm configuration so pnpm also rejects an unsupported runtime. - Regenerate every tracked CLI fixture package manifest. - Update CLI documentation and the release-smoke manifest contract. - Remove the earlier sanitizer-bundling workaround from the branch; sanitizer code and packaging are unchanged from `main`. ## Checklist - [x] Declare the exact Node.js compatibility floor - [x] Fail before generated development, build, and start commands - [x] Cover the generated engine contract with a fail/pass regression - [x] Regenerate and inspect all affected fixtures - [x] Review documentation impact and update the CLI guide - [x] Keep sanitizer behavior and SDK packaging unchanged ## Verification - Regression demonstrated failing before the template metadata change and passing afterward - `pnpm --filter webstudio test` — 946 passed - `pnpm --filter webstudio typecheck` - `pnpm --filter webstudio build` - `pnpm fixtures` - `pnpm lint` - `pnpm exec oxfmt --check` on changed source, template, fixture, and documentation files - `git diff --check` Agent evaluations were not run because they require separate approval. |
||
|
|
1fe087ed26 |
fix: Improve MCP preview and mutation reliability (#6073)
## Summary Fix the second MCP reliability batch across tool discovery, runtime mutations, preview/screenshot setup, Windows process launching, and stdio recovery. ## Implementation - [x] #6071 Accept canonical dotted/kebab tool names and MCP underscore names in `mcp run`; return near matches and `meta.index` guidance for unknown tools. - [x] #6067 Parse JSON-stringified `tools` arrays in `meta.get-more-tools`. - [x] #6069 Preserve resource-backed variables when renaming without a replacement value. - [x] #6068 Parse CSS declaration strings consistently in design-token style updates. - [x] #6065 Fail immediately for occupied explicit screenshot ports and discover Chromium from the Playwright browser cache. - [x] #6066 Recover the stdio MCP transport after an abandoned partial newline-delimited frame. - [x] #6072 Launch managed Windows previews through Node plus `npm-cli.js`, avoiding `spawn EINVAL`. - [x] #6061 Reuse `npm-cli.js` when launched through `npx`, fall back to the Node-adjacent npm CLI on Windows, forward `npm_config_cache`, and include sanitized package-manager diagnostics. - [x] Address review findings: preserve rebinding on resource scope changes and discover default Playwright caches on Linux, macOS, and Windows. - [x] Complete the DRY pass: remove the dead npm command selector, centralize accepted MCP tool-name lookup, simplify stdio frame recovery, and share Levenshtein distance across MCP suggestions and screenshot text matching. - [x] Complete the follow-up review: centralize preview URL port resolution, use `get-port` instead of custom TCP probing, use named resolver dependencies, and correctly reuse owned previews on default HTTP/HTTPS ports. - [x] Complete the final review: use non-reserving `detect-port` checks for explicit ports and repair the generated-app guidance regression coverage. - [x] Audit new utility code against maintained libraries: use `fastest-levenshtein` for edit distance; retain custom stdio recovery, Playwright cache discovery, and npm launching where no supported library API preserves the required behavior. - [x] Audit Windows/macOS/Linux compatibility helpers: use `path-key` for environment PATH casing and `which` for executable discovery; retain explicit Playwright layouts, browser application paths, npm CLI resolution, symlink types, and process-tree shutdown where behavior is platform- or product-specific. - [x] Add fail/pass regression coverage for every fix. - [x] Review documentation impact and update the CLI MCP sources plus generated GitBook output. - [x] Review fixture impact: no fixture inputs or generated fixture bundles are affected. - [x] Run targeted tests, package type checks, lint, package-boundary checks, generated API checks, and generated documentation checks. - [ ] Agent evaluations — not run because repository policy requires separate explicit approval. ## Verification - Complete CLI suite: 60 files, 968 tests passed. - Project-build affected tests: 4 files, 382 tests passed. - `pnpm --filter webstudio typecheck` - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` - `pnpm check:generated-docs` Each new regression test was run against the unfixed behavior to confirm the expected failure, then rerun after its fix. ## Compatibility note The stdio recovery layer discards only an unterminated frame that remains idle for five seconds. Complete newline-delimited JSON-RPC frames continue through the SDK transport unchanged. Closes #6072 Closes #6071 Closes #6069 Closes #6065 Closes #6066 Closes #6067 Closes #6068 Closes #6061 |
||
|
|
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 |
||
|
|
b6d4d645f5 |
fix: Include runtime metadata in CLI issue reports (#6026)
## Summary Automatically attach anonymous CLI runtime metadata when the resolved public API command is `report-issue`. The transport previously compared the route operation ID (`reports.issue`) with the command name (`report-issue`), so enrichment was skipped. The change keeps enrichment owned by the CLI transport and preserves the existing server contract for Builder UI and other clients. ## Technical choices - Resolve the public operation by route ID as before. - Pass its typed command to runtime enrichment, removing ambiguity between route IDs and commands. - Exercise the real `reports.issue` transport path and inspect the serialized request body. - Keep runtime fields limited to CLI version, Node.js version, OS family/version, architecture, execution mode, and API contract version. ## Todo - [x] Attach runtime metadata using the resolved report command. - [x] Add transport-level regression coverage for the outgoing request. - [x] Confirm non-report operations preserve existing behavior. - [x] Review documentation impact; no documentation changes are required because the public report schema and workflow are unchanged. - [x] Confirm fixture inputs and generated fixture outputs are unaffected. - [ ] Run `pnpm evaluations` after explicit approval for agent evaluations. ## Verification - Regression test demonstrated failure before the implementation and passed afterward. - `pnpm --filter webstudio test -- project-session.test.ts` — 20 passed. - `pnpm --filter webstudio test` — 943 passed. - `pnpm --filter webstudio typecheck` — passed. - `pnpm exec oxlint --deny-warnings packages/cli/src/project-session.ts packages/cli/src/project-session.test.ts` — passed. - `git diff --check` — passed. ## Known limitations The complete agent evaluation suite has not been run because repository policy requires separate explicit approval before invoking it. Closes #6025 |
||
|
|
6d2389ee54 |
fix: Stop managed preview process groups (#6037)
## Summary - start managed POSIX preview servers in their own process group - terminate the complete preview process group from `preview.stop` - clean up the owned preview group before propagating `SIGHUP`, `SIGINT`, or `SIGTERM` - preserve the existing child-process fallback on Windows - keep standalone `webstudio preview` signal behavior unchanged ## Root cause The managed preview controller spawned an npm wrapper and stopped only that direct child with `ChildProcess.kill()`. React Router runs below that wrapper, so the dev server could survive as an orphan. Its inherited stdout/stderr pipes could also keep `webstudio mcp run` alive after the manifest had completed. ## Impact `preview.stop` now terminates the npm wrapper and all descendants. If the CLI is terminated while it owns a managed preview, it kills that process group before re-propagating the original signal to itself. ## Todo - [x] Reproduce the missing process-group cleanup in regression tests - [x] Isolate managed POSIX previews in their own process group - [x] Stop the full group on `preview.stop` - [x] Stop the full group on CLI termination signals - [x] Preserve standalone preview behavior - [x] Run an independent real subprocess test with an npm wrapper and long-lived grandchild - [x] Review documentation impact — existing MCP documentation already describes `preview.stop` as ending the owned preview, so no docs change is required - [x] Verify fixture impact — no fixture inputs or generated outputs are affected ## Verification - `pnpm --filter webstudio test` — 58 files, 945 tests passed - `pnpm --filter webstudio typecheck` — passed - targeted `oxlint`, `oxfmt`, and `git diff --check` — passed - regression tests were demonstrated failing without the process-group and signal cleanup, then passing with it - independent real-process test on macOS / Node 22.22.1: - `preview.stop` removed the npm wrapper, server, and long-lived grandchild in 458 ms; harness exited in 0.93 s - parent `SIGTERM` removed the complete process group in 0.01 s; harness exited with expected status 143 - all observed PIDs were absent afterward - agent evaluations were not run because they require separate explicit approval Closes #5958 |
||
|
|
b8cbd09020 |
fix: Preserve MCP run results on termination (#6033)
## Summary - emit a structured terminal result when an active `mcp run` reaches Node `beforeExit` - preserve completed call results and identify the unfinished call - add regression coverage for a four-call run that terminates during `preview-asset-query` ## Root cause `mcp run` only wrote its final JSON after the awaited tool call settled. An unresolved tool promise does not keep Node's event loop alive by itself, so a read-only preview call could reach `beforeExit` after its start lifecycle event without producing either a terminal call event or the run result. ## Implementation The CLI tracks only the currently active call while a run is executing and installs one scoped `beforeExit` handler. If Node would exit while that call is unresolved, the handler reuses the existing MCP run error envelope to return `MCP_RUN_TERMINATED` with completed results, total call count, the unfinished call number and tool, elapsed time, and the original exit code. Existing success, tool-failure, and checkpoint control flow remains unchanged. OS-level termination that cannot be intercepted, such as `SIGKILL`, remains outside the process's ability to report. ## Checklist - [x] Preserve completed MCP call results on unexpected termination - [x] Identify the unfinished call in the terminal payload - [x] Emit a nonzero exit status - [x] Add fail-then-pass regression coverage for asset query preview termination - [x] Review implementation for correctness, unnecessary work, and duplication - [x] Review documentation impact: no update needed because this restores the existing documented stdout JSON contract - [x] Verify fixture impact: no fixture inputs or generated fixture outputs are affected ## Verification - `pnpm --filter webstudio typecheck` - `pnpm exec oxlint --deny-warnings packages/cli/src/commands/mcp.ts packages/cli/src/commands/mcp.test.ts` - `pnpm --filter webstudio test` — 943 tests passed - `git diff --check` The separate `pnpm evaluations` agent evaluation suite was not run because it requires explicit approval. Closes #6032 |
||
|
|
928867a08b |
fix: Improve MCP CSS variable safety and state feedback (#6018)
Closes #6017 Ref #6019 ## Summary Improve agent-facing CLI/MCP feedback for CSS variables, mutation durability, batch operations, and preview freshness. ## Implementation - Validate structured hex colors as normalized channels and recommend CSS strings for ordinary 0–255 hex input. - Return exact CSS variable values while retaining `valueLength` in compact output for compatibility. - Preserve optional boolean inputs generically in compact MCP SDK schemas, including `withUsage`, `verbose`, `overwrite`, and `force`. - Add multi-variable define/delete examples and document safe batching. - Derive `meta.session.commitStatus` from the session envelope so reads, plans, failed/no-op mutations, and durable mutations are unambiguous. - Retain `committed` on read results for compatibility while reporting `commitStatus: "not-applicable"`. - Report preview `stale` state and `renderedProjectVersion`, and avoid marking a preview fresh when the project changes during regeneration. - Track WSL2/9P cleanup hardening separately in #6019. ## Todo - [x] Reject out-of-range structured hex color channels and alpha. - [x] Add fail-before/pass-after CSS color regression coverage. - [x] Return exact compact CSS variable values without removing `valueLength`. - [x] Clarify mutation durability with `commitStatus`. - [x] Distinguish failed, unchanged, planned, committed, and read-only results. - [x] Distinguish server-backed reads from committed mutations at the session boundary. - [x] Preserve optional boolean schemas without a per-field allowlist. - [x] Add multi-variable define and delete examples. - [x] Report preview freshness and rendered project version. - [x] Investigate WSL cleanup behavior and create follow-up #6019. - [x] Review and update authoritative CLI/MCP documentation. - [x] Verify fixture impact; no fixture inputs or outputs changed. - [x] Run affected tests, typechecks, lint, and generated-file checks. - [ ] Run the complete local agent evaluation suite after explicit approval. ## Verification - [x] Regression tests demonstrated failing before their implementation and passing afterward. - [x] `pnpm --filter @webstudio-is/project-build test` — 82 files, 2,085 tests passed. - [x] `pnpm --filter webstudio test` — 57 files, 939 tests passed. - [x] Project-build and CLI typechecks passed. - [x] `pnpm lint` passed. - [x] `pnpm oxfmt --check` passed. - [x] `pnpm check:generated-api` passed. - [x] `pnpm check:generated-docs` passed. - [ ] `pnpm evaluations` — awaiting explicit approval per repository policy. ## Compatibility and limitations - `committed` remains available on every session result. For reads it is `false` and durability does not apply; use `commitStatus: "not-applicable"`. - Compact CSS-variable records include both exact `value` and `valueLength`. - Structured hex color channels remain normalized `0..1`; CSS color strings such as `"#2d3748"` are the recommended 0–255 representation. - WSL2/9P process cleanup is not changed in this PR and is scoped in #6019. |
||
|
|
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. |
||
|
|
57d9ad14cd |
fix: Retry published CLI registry lookup (#6013)
## What changed - Retry npm version and integrity resolution inside the CLI registry smoke test. - Keep retry timing injectable so the propagation race is covered by a fast unit test. - Preserve the final npm error when all registry attempts are exhausted. ## Why CLI 0.286.0 was published successfully, but npm briefly exposed integrity metadata while the exact version lookup still returned 404. The post-publish smoke failed and the dependent docs publication job was skipped. The 0.286.0 documentation snapshot has been recovered directly on the `docs` branch. Ref #6007 ## Verification - [x] Regression test demonstrated failing before the implementation and passing afterward - [x] CLI registry/versioning tests: 3 passed - [x] CLI typecheck - [x] Formatting and diff checks - [x] Documentation impact reviewed: no product-doc source change is needed in this PR; the missed 0.286.0 snapshot was published separately to `docs` |
||
|
|
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 |
||
|
|
1ca01e96a3 |
docs: Guide MCP agents to build dynamic JSON-LD (#5998)
## Summary Clarify how MCP agents should author JSON-LD without serializing dynamic values prematurely. Static structured data remains a validated compact JSON string, while runtime-backed structured data uses an expression that evaluates directly to an object or array. The focused guide now provides machine-readable input recipes for both paths. ## Implementation - [x] Update the focused `components.get` JSON-LD guidance. - [x] Update the JSON-LD `meta.guide` workflow and include `bind-props`. - [x] Add structured `fixedCodeUpdate` and `dynamicCodeBinding` recipes. - [x] Document that expression source is stored as text while its evaluated value must be an object or array. - [x] Warn agents not to call `JSON.stringify` or assemble JSON with string concatenation. - [x] Update CLI use-case documentation and generated docs. - [x] Parse the fixed JSON and dynamic expression AST in regression coverage, including the `post.title` runtime binding. - [x] Demonstrate that the semantic regression test fails when the structured recipe is absent. ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,066 tests passed - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter webstudio typecheck` - Focused MCP semantic regression tests - `pnpm oxfmt --check ...` - `pnpm oxlint packages/project-build/src/mcp.ts packages/project-build/src/mcp.test.ts` - `pnpm check:generated-docs` - Fixtures not run: documentation and MCP guidance do not affect fixture inputs or generated fixture bundles. - Agent evaluations not run: explicit approval was not provided. Closes #5997 |