44 Commits

Author SHA1 Message Date
kokisanai
54de349c47 fix: replace expired Discord invite (#4849)
Co-authored-by: koki yanlai xu <koki@kokideMacBook-Air.local>
2026-06-29 15:00:45 +00:00
elifive555555
1319bcef2e chore: prune curated official example plugins (#4815)
Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-26 10:01:44 +00:00
Tom Huang
29b138f7a3 feat(brands): turn any brand into a reusable design system (#4691)
* Implement brand management routes and CLI support

- Added `brand-routes.ts` to handle HTTP endpoints for brand operations: listing, extracting, retrieving details, deleting, and serving logos.
- Introduced `brands-cli-help.ts` for CLI commands related to brand management, including usage instructions for listing, creating, retrieving, and deleting brands.
- Updated `cli.ts` to integrate brand commands into the existing CLI structure, allowing headless management of brands via the command line.
- Created supporting files for brand metadata handling, including `design-md.ts` for rendering brand information in markdown format and `index.ts` for the brand engine API.
- Implemented `prefetch.ts` to fetch and process brand material from specified URLs, ensuring a streamlined extraction process.
- Enhanced server setup in `server.ts` to register brand routes and manage brand-related data effectively.

This commit establishes a comprehensive framework for managing brands within the application, facilitating both HTTP and CLI interactions.

* Enhance memory management and onboarding experience

- Introduced canonical profile labels to ensure consistent handling of user input in profile forms, preventing duplicate entries.
- Updated the `parseProfileBody` and `captureProfileFromForm` functions to utilize the new canonical label matching.
- Added a memory callout section in the onboarding view to highlight the benefits of memory usage, including personalized responses and reduced setup questions.
- Implemented new UI elements in the onboarding view to improve user engagement with memory features.
- Expanded i18n support for new onboarding messages related to memory benefits across multiple languages.

* Refactor onboarding flow and enhance design system integration

- Updated the onboarding process to include a new brand extraction step, replacing the previous newsletter step.
- Adjusted the tracking logic to reflect the new onboarding steps, ensuring accurate analytics for user progress.
- Improved the UI for the onboarding view, including new input fields for email collection during the brand extraction phase.
- Refined the EntryShell component to remove outdated comments and clarify the onboarding renderer's purpose.
- Enhanced CSS styles for the onboarding steps to improve layout and user experience.
- Updated internationalization strings across multiple languages to reflect changes in the onboarding flow and brand extraction messaging.

* Add brand management features and enhance font handling

- Introduced new modules for managing brand assets, including `chrome.ts` for headless Chrome operations and `fonts.ts` for self-hosting web fonts.
- Implemented `prefetch.ts` to streamline the brand material extraction process, allowing for efficient harvesting of colors, fonts, and logos.
- Enhanced the brand system with new schema definitions in `schema.ts` to support brand color and font management.
- Developed the `engine` module to integrate brand building and rendering processes, including token derivation and artifact generation.
- Improved the overall structure and organization of brand-related files for better maintainability and scalability.

* Enhance brand extraction and project management features

- Updated `brand-routes.ts` to include new dependencies for project management, allowing for the registration of brand-related projects.
- Modified the `extractBrand` function to support project ID and system files, improving the brand extraction process.
- Enhanced the CLI commands in `cli.ts` to handle project IDs during brand creation, enabling better tracking of brand projects.
- Updated the server setup in `server.ts` to register new project-related routes.
- Improved the UI components to display project information associated with brands, including buttons for opening projects in the `BrandDetailView` and `BrandsTab`.
- Added new metadata fields in the contracts to support project tracking and management for brands.

This commit establishes a more robust framework for managing brand projects, enhancing both backend and frontend functionalities.

* Enhance onboarding profile management and memory persistence

- Added new canonical profile labels for 'Organization size', 'Use cases', and 'Discovery source' to improve user input consistency.
- Introduced `OnboardingProfileState` type to manage onboarding profile data more effectively.
- Implemented functions to build and persist the onboarding profile body to memory, ensuring user selections are saved accurately.
- Updated the `OnboardingView` component to handle profile persistence during navigation and submission steps.
- Enhanced tests to verify that user selections are correctly persisted to the memory profile.

This commit improves the onboarding experience by ensuring that user inputs are consistently captured and stored, enhancing overall user engagement with the application.

* Reflow brand extraction into an agent-driven, live flow

Replace the deterministic SSE prefetch/preview/system pipeline with an
agent-driven extraction: POST /api/brands now reserves the brand and stands
up a backing project with the target site open in an in-app browser tab plus
a seeded prompt, so the agent measures, synthesizes brand.json incrementally,
and the user can clear anti-bot walls by hand. New /preview and /finalize
routes let the agent render the kit page live and register the resulting
user:<id> design system, so extracted brand facts persist as a structured,
reusable brand kit instead of a one-shot deterministic guess.

Adds the brand-extract skill (SKILL.md + brand-kit.html template), kit-render
engine, brand-extraction-engine tests, brand project covers in the Designs
tab, onboarding extract handoff, and the matching od brand extract/preview/
finalize CLI subcommands and contract updates.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Sediment finalized brands into structured memory

Reflow a finalized brand into the memory store (brandToMemoryEntries +
reflowBrandToMemory) so future chats can ground vague requests in the
brand's palette, type, voice and rules. finalizeBrand now wires through
the runtime dataDir and best-effort persists the brand, MemoryChangeEvent
gains a 'brand' source, and the brand kit render hardens its inline JSON
escaping. Adds brand.previewEmpty / brand.viewDetails across all locales.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Implement logo fallback and imagery support in brand extraction

- Introduced a deterministic logo fallback mechanism to ensure that brand extraction processes can retrieve and save site logos, even when the agent fails to do so.
- Enhanced the `startBrandExtraction` and `finalizeBrand` functions to utilize the new logo fallback, allowing for better handling of logo assets.
- Added support for imagery samples in brand validation, enabling the inclusion of representative images in the brand kit.
- Updated the brand kit rendering to include self-hosted fonts and imagery, improving the overall presentation of brand assets.

This commit strengthens the brand extraction workflow by ensuring that logos and imagery are reliably captured and displayed, enhancing the user experience in brand management.

* Enhance memory management with rule proposal and verification features

- Introduced new functionality for distilling annotations into rule proposals, allowing users to suggest rules based on in-canvas annotations through the `od memory rule suggest` command.
- Implemented a verification system that programmatically enforces compliance with active rules during artifact generation, ensuring that all active rules are covered in the self-verify scorecard.
- Added endpoints for managing verification outcomes, including listing, removing, and clearing verification records, enhancing the transparency of the verification process.
- Updated the memory management system to support the retrieval of active rule entries, ensuring that only linked rules are considered during verification.
- Enhanced tests for both rule proposal generation and verification processes to ensure reliability and correctness.

This commit strengthens the memory management capabilities by integrating rule proposals and verification, improving the overall user experience in managing design rules and ensuring compliance.

* Distill review annotations into memory and enforce self-verify scorecard

Add distillAnnotationsToMemory to mine inline preview comments/highlights/
marks into durable feedback + rule memory via a dedicated distiller prompt,
threaded through the existing extract pipeline with an 'annotation' change
source. Tighten the self-verify prompt (daemon + contracts) to state the
daemon programmatically checks the scorecard, so a missing or uncovered
scorecard on an artifact turn is an enforcement failure. Cover the rule
suggest and verification-history routes with tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Apply brand design system through web config on "Use in new chat"

Thread onApplyDesignSystem from the entry shell into BrandsTab so the brand's
registered design system is applied via the web config channel instead of a
bare daemon PATCH that left the Home composer stale. Add a transient
home-intent latch + event so the Brands tab can request the Prototype chip on
the already-mounted HomeView, which consumes it once the plugin catalog loads.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Wire annotation distillation into background memory extraction

Add a background distill pass that mines inline review annotations
(comments / highlights / drawn marks) from a turn into durable memory
alongside the general LLM extraction, surface an `annotation` memory
toast source in the web UI, and cover the flow with a unit test.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix brand design system not applying to composer on "Use in new chat"

Selecting a brand's "Use in new chat" applies the brand's design system as
the default and fires the Prototype chip intent in the same synchronous click
handler. HomeView consumed that intent inside the event listener, so `pickChip`
ran before React committed the config change and seeded the composer's
design-system field from the stale (empty) default — the composer showed
"No design system" instead of the brand until a reload.

Split the intent handling: the listener now only bumps a tick, and a separate
effect consumes the chip after the re-render lands, so the seeded design system
reflects the freshly-applied brand. Add the previously-untracked home-intent
latch test coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(web): rework Brands into Brand Kit and add Home create entry

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(brands): harvest real cover/hero images for the Images module

The brand kit's Images gallery only populated when the extraction agent
remembered to save imagery — so a forgetful or bot-blocked agent (and the
pre-imagery "Open Design" brand) left it empty. Add a deterministic,
server-side imagery fallback (imagery-fallback.ts), mirroring the logo
fallback: it parses og:image/twitter:image, large <img> (highest-res
srcset/<picture>), <link rel=preload as=image>, and CSS background-image
hero blocks, fetches candidates with browser-shaped headers, decodes
PNG/GIF/JPEG/WebP dimensions to keep only big representative images
(dropping icons/sprites/logos/tracking pixels), dedupes by content hash,
and saves up to 8 of the largest into imagery/ with labeled samples.

finalizeBrand runs it as a timeout-bounded, failure-tolerant safety net
(injectable so tests stay offline) when the agent captured too few
samples, first adopting any on-disk images. The extraction prompt and
brand-extract SKILL now explicitly direct the agent to harvest the site's
large/cover/hero images, filtered by rendered size.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(qa): implement deck layout validation and safety checks

Add a new QA module for validating the layout of generated brand decks to ensure robustness against clipping and truncation issues. The `analyseDeckLayout` function checks for critical layout invariants, including the presence of `.slide` sections, correct container types, and necessary runtime layers. Introduce `assertDeckLayoutSafe` to enforce these checks during brand system rebuilds, preventing the deployment of decks that fail validation. Additionally, create comprehensive tests to verify the functionality of the new layout validation features.

* fix(brands): apply deck shrink-to-fit synchronously so slides never clip

The no-clip runtime scheduled its fit pass through requestAnimationFrame,
whose callbacks are throttled while the deck is offscreen or occluded. A
slide could therefore stay unscaled — and clip its content — until first
paint. Fit synchronously on resize/load/fonts-ready with a trailing
setTimeout settle pass for late reflow, removing the rAF dependency.

Verified at the previously-broken 1024x620 viewport: container-type:size,
zero truncations, runtime auto-applies scale (Problem 0.71, ASK 0.87,
Product 0.97, Competition 0.97) and frame clip count drops to 0.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(web): let New Brand modal embed scrollable brand reference picker

Add a fillHeight mode to BrandReferencePicker so the heading, quick-pick
row and controls stay pinned while only the gallery scrolls inside a
bounded-height parent. Wire it into NewBrandModal with a stable, spacious
dialog and refresh the related newBrand/brandPicker copy across all 18
locales.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(brands): enhance brand extraction with deterministic seed harvesting

Introduce a new `seed-fallback` module to provide a server-side deterministic palette and typography seed during brand extraction. This ensures that the brand kit's initial display includes a harvested logo, an approximate color palette, and font families, improving the user experience by reducing the all-skeleton appearance during the first paint. Update the `startBrandExtraction` function to utilize this new module, allowing for a more seamless and visually appealing brand extraction process.

Additionally, enhance the `BrandReferencePicker` component to reflect loading states and errors during brand extraction, ensuring users receive immediate feedback on their actions. Update related tests to verify the idempotency of the `finalizeBrand` function, ensuring that re-finalizing a brand correctly reuses the existing design system without duplication.

* feat(brand-extract): enhance BrandReferencePicker and localization updates

Updated the BrandReferencePicker component to reflect loading states and errors during brand extraction, improving user feedback. Added a new localization key for the brand extraction process and updated existing translations in English, Simplified Chinese, and Traditional Chinese to enhance clarity and user experience. Additionally, introduced new styles for better interaction with brand assets in the brand kit template.

* feat(brands): wire in-page lightbox/masonry/asset preview + refine seed

Brand-kit preview improvements for the live extraction kit:
- brand-kit.html: add in-page overlay system (sandboxed iframe has no
  top-nav) — clickable image lightbox with prev/next, a "view all"
  masonry modal, and a full-page asset preview modal that loads
  system/artifacts/<kind>.html in an iframe. Defer auto-reload while an
  overlay is open so it never yanks the modal out mid-interaction.
- seed-fallback.ts: prefer vivid mid-luminance hues for the seeded
  accent/accent-secondary, and drop icon/symbol faces (Remix Icon etc.)
  from the typography seed so specimens never render glyph soup.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(brands): wire in-page lightbox/masonry/asset preview + refine seed

Brand-kit preview improvements for the live extraction kit:
- brand-kit.html: add in-page overlay system (sandboxed iframe has no
  top-nav) — clickable image lightbox with prev/next, a "view all"
  masonry modal, and a full-page asset preview modal that loads
  system/artifacts/<kind>.html in an iframe. Defer auto-reload while an
  overlay is open so it never yanks the modal out mid-interaction.
- seed-fallback.ts: prefer vivid mid-luminance hues for the seeded
  accent/accent-secondary, and drop icon/symbol faces (Remix Icon etc.)
  from the typography seed so specimens never render glyph soup.

Co-authored-by: Cursor <cursoragent@cursor.com>

* i18n(web): add brandPicker.opening across remaining locales + picker test

Completes the brand-reference picker i18n key that was committed only for
en/zh-CN/zh-TW, so every locale satisfies the typed Dict, and lands the
BrandReferencePicker extraction-feedback test left untracked by the
concurrent worker.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(EntryShell): enhance AMR cloud card visibility post-detection

Updated the EntryShell component to ensure the AMR cloud card remains visible after detection settles, even when the AMR runtime is unavailable. This change prevents the card from disappearing and allows it to degrade gracefully to fallback content and sign-in flow. Additionally, added tests to verify the new behavior, ensuring a better user experience during onboarding.

* feat(library): OD Library asset registry + OD Clipper extension

Add a global, cross-project asset registry (OD Library) and a Chrome MV3
capture extension (OD Clipper), wiring the full HTTP + CLI + Web UI three-track
loop per specs/od-clipper.md.

- contracts: LibraryAsset/Source/Kind, ingest, search, pairing, task DTOs
- daemon: 6 additive SQLite tables, content-addressed owned storage, the
  idempotent registerLibraryAsset hook (hash dedup + append-source),
  programmatic enrichment (mime/size/image dims/domain/tags), pairing tokens
  with a persisted extension-origin allowlist, /api/library/* routes, and
  /api/tools/library/{search,apply} for in-task agent reuse
- cli: `od library list|get|rm|search|import|pair`
- web: Library tab (grid, source badges, filters, search, live SSE updates,
  extension pairing affordance)
- clipper/: standalone MV3 extension (background SW, content toolbar, popup)
- skills/library-curator: utility skill for agent-driven asset reuse

Origin middleware now honors paired chrome-extension:// origins (seeded from
SQLite on boot) and exempts the pairing-confirm handshake. Enrichment AI stages
(caption/OCR/embedding) are recorded as skipped pending a configured model.

* feat(brands): programmatic-first design system extraction + rename

Make brand extraction two-phase so a usable design system is ready the
moment the user enters a URL — the instant "aha" — instead of waiting on
the AI agent:

1. PROGRAMMATIC-FIRST (synchronous): startBrandExtraction now harvests the
   site deterministically (logo, palette, typography, one-line description,
   cover imagery, source URL) via prefetchBrand, synthesizes a valid design
   system with brandFromMaterial (no LLM), and finalizes + registers it
   before returning. finalizeBrand is refactored into a reusable
   finalizeBrandCore shared by both the programmatic path and the agent path.
2. ASYNC AI ENRICHMENT: the seeded agent prompt is reframed to enrich the
   already-usable design system and re-finalize in place (same user:<id>),
   updating every artifact/template.

Bounded + best-effort: a blocked/unreachable origin skips phase 1 and stays
`extracting` for the agent to drive. Gated on userDesignSystemsRoot so the
legacy agent-only path stays intact for tests.

Also rename the user-facing "Brand Kit" surface to "Design System" across
en + zh-CN strings, project names, and the enrichment prompt.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(library): enhance asset import and management features

- Updated the `import` command to allow multiple local files and remote URLs, with restrictions on supported formats.
- Added new commands: `apply` for copying assets into project design files, `edit-as-page` for converting HTML assets into editable projects, and `figma` for exporting Figma captures.
- Introduced sidecar functionality for storing derived data alongside owned assets, including Figma capture IR and element HTML.
- Enhanced server configuration to support larger ingest payloads for asset captures.
- Improved error handling and user feedback during asset import and application processes.

* feat(asset-management): enhance asset dropzone and introduce chat-to-design feature

- Updated the DesignSystemAssetDropzone component to improve file preview handling with new functions for creating and revoking object URLs.
- Adjusted CSS for better layout and spacing in the asset dropzone.
- Added a new "Chat to design" button in the LibrarySection component, allowing users to send selected assets to the Home chat composer for project creation.
- Updated localization strings across multiple languages to reflect changes in asset import terminology.
- Enhanced the HomeView component to handle asset staging from the chat composer.

* feat(library): enhance asset application with element markup support

- Updated the `applyLibraryAsset` function to include an `includeElement` option, allowing the capture of element markup alongside assets.
- Modified related components (e.g., `ChatComposer`, `LibrarySection`, `FileWorkspace`) to handle the new element markup feature, ensuring both asset paths and optional element paths are returned and processed.
- Introduced a new function, `fetchLibraryAssetElementHtml`, to retrieve the captured HTML for element-pick assets.
- Enhanced the UI to display element markup inline within the chat composer, improving user interaction with captured elements.
- Updated API contracts to reflect changes in asset application responses, including optional element markup paths.

* feat(library): enhance asset filtering and preview handling

- Updated the LibraryPicker and LibrarySection components to implement a badge-aware kind filter, allowing for more precise asset filtering based on badge kind.
- Introduced a new `matchesKindFilter` function to streamline the filtering logic across components.
- Enhanced the DesignSystemAssetDropzone to ensure proper handling of image previews, addressing issues with broken thumbnails under React StrictMode.
- Added CSS styles for kind badges to improve asset representation in the UI.
- Implemented tests for the DesignSystemAssetDropzone to ensure correct preview lifecycle management.

* feat(library): hydrate single asset on SSE ingest

Add fetchLibraryAsset(id) so the Library grid can merge just the one
asset an `ingest` SSE event references instead of refetching the whole
list on every capture. Returns null on miss/error.

* feat(clipper): richer in-page image picker

Collect CSS background-image url()s in addition to <img> (so hero/section
art painted as backgrounds is no longer silently missed), defer thumbnail
decode to visible cells via IntersectionObserver, draw downscaled canvas
thumbnails instead of second full-res decodes, and add locate-on-page
highlighting so a picked image can be traced back to its DOM source.

* feat(library): implement lazy loading for thumbnails and enhance asset filtering

- Introduced a `LibraryThumb` component to lazily load heavy content (images, videos, iframes) only when they are near the viewport, improving performance.
- Added a debounced search feature to optimize asset filtering, reducing unnecessary network requests during rapid input.
- Enhanced the asset filtering logic to track active filters using a ref, ensuring efficient updates during live events.
- Updated the `snapshotCardRects` and `cardIdsInBand` functions to support improved hit-testing for drag-and-drop interactions.

* feat(library): lazy picker thumbnails + debounced search

Extend the Library grid's lazy-thumbnail + 250ms debounced-search pattern
to the composer LibraryPicker so opening it no longer fires one full-bytes
request per asset, and tidy the clipper content-script image collection.

* feat(clipper): compress and budget capture inlining

Re-encode large raster images to downscaled WebP and inline smallest-first
within a fixed budget, dropping only the secondary Figma IR past a safe body
size, so an image-heavy page (e.g. a news front page) always saves as an
editable HTML capture instead of 413-failing the ingest.

* test(library): LibraryPicker debounce + lazy-thumbnail coverage

Cover the composer picker's 250ms debounced search and its lazy <img>
mount (deferred until the card is in view), matching the grid's perf test.

* feat(design-system): enhance asset handling and UI for design systems

- Updated the CLI to support additional asset kinds, including 'design-system'.
- Enhanced the DesignSystemProvenance type to include source URLs, improving provenance tracking.
- Modified the design system generation jobs to correctly summarize source links and GitHub repositories.
- Updated UI components to reflect changes in asset handling, including new source link management in the DesignSystemFlow.
- Improved tests to cover new functionality for adding source links and ensuring proper handling of design system assets.

* refactor(library): rename 'design-system' to 'brand kit' and enhance thumbnail loading

- Updated labels and filters in Library components to replace 'design-system' with 'brand kit'.
- Introduced a shimmer skeleton for lazy-loaded thumbnails in the LibraryPicker to improve user experience during asset loading.
- Enhanced the PickerCard component for better performance by memoizing individual asset cards.
- Updated tests to ensure proper handling of brand kit assets and their visibility in the LibraryPicker.

* feat(clipper): implement internationalization for toolbar and popup

- Added i18n support to the clipper, enabling localization of UI elements and tooltips.
- Introduced a new i18n.js file to manage translations for various languages.
- Updated content.js and popup.js to utilize the i18n functions for dynamic text rendering.
- Enhanced accessibility by ensuring aria-labels and tooltips are also localized.
- Improved user experience by providing localized messages for actions and statuses.

* feat(clipper): enhance brand kit extraction and localization support

- Updated the brand kit extraction process to include improved handling of assets and localization for various UI elements.
- Added internationalization support for the brand kit feature, allowing for dynamic text rendering based on user locale.
- Enhanced the user experience by ensuring that all relevant messages and tooltips are localized.
- Updated tests to cover new localization features and ensure proper functionality of the brand kit extraction process.

* feat(clipper): enhance brand color derivation and update localization

- Introduced new functions for color manipulation, including linear interpolation and clamping, to improve brand color derivation.
- Updated the deriveBrandColors function to better map observed palettes to semantic roles, ensuring consistent brand representation.
- Revised localization strings in i18n.js to reflect changes from 'brand kit' to 'design system', enhancing clarity and user experience.
- Improved overall code organization and readability by refactoring existing functions and adding new utility methods.

* refactor(clipper): update terminology from 'brand kit' to 'design system'

- Replaced all instances of 'brand kit' with 'design system' across various components and localization files for consistency.
- Updated UI elements, tooltips, and documentation to reflect the new terminology.
- Enhanced user experience by ensuring clarity in the design system extraction process and related functionalities.
- Adjusted localization strings in multiple languages to align with the updated terminology.

* feat(clipper): enhance image fill handling and normalization

- Introduced functions to normalize image fills by converting non-PNG/JPEG formats (SVG, WebP, GIF, AVIF) to PNG before import, ensuring all images are properly rendered in Figma.
- Updated the UI to report the number of images converted and dropped during the import process, improving user feedback.
- Enhanced the overall image processing workflow to prevent silent failures when unsupported formats are encountered.
- Revised documentation to reflect the new image handling capabilities and supported formats.

* feat(clipper): enhance UI kit and busy state feedback

- Updated the UI kit to include new components such as inputs, selection, and overlays, improving the overall design system representation.
- Enhanced the busy state feedback during capture processes with localized messages and a step-by-step progress indicator, providing users with clearer status updates.
- Revised localization strings to support new UI elements and improve user experience across multiple languages.
- Improved documentation to reflect changes in the UI kit and busy state handling.

* fix(brands): restore design-systems nav entry + reconcile BrandsTab on re-activation

Address review feedback on PR #4260:

1. EntryNavRail dropped the only control that reached view==='design-systems'
   when Brands replaced it in the rail, leaving the still-rendered/routed
   design-system manager deep-link only (the entry-nav-design-systems e2e
   specs assert this). Restore a reachable rail entry (blocks icon, existing
   navDesignSystems key) alongside Brands.

2. BrandsTab only fetched once on mount, but EntryShell keeps sub-views
   mounted and toggles visibility, so a brand finishing extraction in its
   backing project never reconciled until a full reload. Refresh whenever the
   Brands view becomes active again, and poll while any brand is extracting
   (torn down once settled / when hidden).

Red spec: tests/components/BrandsTab.refresh.test.tsx (fails pre-fix:
fetchBrands called once, not twice).

* Update clipper/brand-capture.js

* fix(clipper): improve busy state handling and UI feedback

- Adjusted the spinner CSS to use flex properties for better layout control.
- Enhanced the reclampIfMoved function to preserve user position during busy state transitions.
- Added loading toast notifications for popup-launched captures to ensure progress visibility even when the on-page bar is hidden.

* feat(daemon): add kiwi-schema dependency and enhance Figma API integration

- Added kiwi-schema package to the daemon for improved schema handling.
- Updated FigmaApiNode interface and related functions to support shared functionality with the offline decoder, ensuring consistency in node processing.
- Refactored capture functions in clipper to maintain UI visibility during DOM/IR snapshots, enhancing user experience during capture operations.

* fix(web): surface missing backing projects

* fix(web): re-enable brand actions after use

* fix(daemon): serve brand logos from data roots

* fix(brands): reconcile failed extractions

* feat(daemon): implement offline Figma import and decoding functionality

- Added support for importing `.fig` files directly into the daemon, enabling offline processing without requiring a Figma account.
- Introduced a new `fig-decode.ts` module for decoding `.fig` files, handling both ZIP-wrapped and raw formats.
- Created `figma-import.ts` to orchestrate the import process, generating a canonical snapshot and associated metadata.
- Enhanced the server to handle Figma file uploads and integrate with the new decoding logic.
- Updated package dependencies to include `kiwi-schema`, `html2canvas`, and `jspdf` for improved functionality.
- Added tests for the new Figma import features to ensure reliability and correctness.

* feat(clipper): reload-proof capture progress badge on the extension icon

The on-page progress strip dies if a page reloads itself mid-capture
(aggressive paywall sites like economist.com do this), leaving no
loading signal. Add a per-tab '•••' badge on the extension icon for the
lifetime of any capture message — it lives on the action icon, so a page
navigation can't take it down. Verified end-to-end via a real loaded
extension.

* feat(daemon): add export functionality for Figma and enhance PDF export process

- Introduced `runFigma` command for importing Figma designs, supporting both local `.fig` files and Figma URLs.
- Added detailed usage instructions for the `od figma import` command.
- Implemented `runExport` command for programmatic export of HTML/deck artifacts to PDF, PPTX, or image formats.
- Enhanced error handling and user feedback during export processes.
- Removed obsolete `build-pptx-export-prompt` module and related tests to streamline the codebase.

* feat(daemon): enhance library synchronization and export capabilities

- Implemented `reconcileLibrary` to mirror design systems and agent-produced project deliverables into the Library as referenced assets.
- Added support for programmatic export of artifacts via the `od export` command, including detailed usage instructions.
- Introduced new functions for handling Figma imports and exports, improving integration with design workflows.
- Enhanced error handling and user feedback during synchronization and export processes.
- Added tests for new features to ensure reliability and correctness.

* feat(web): PPTX export for any shareable artifact + Library toolbar tooltips

* chore(nix): refresh pnpm deps hash

* refactor(web): enhance onboarding view and file export progress indicators

- Updated the onboarding view layout for improved accessibility and visual hierarchy, including adjustments to spacing, typography, and button styles.
- Introduced a loading toast for file export progress, displaying elapsed time and estimated time remaining for slide exports.
- Added new translation keys for export progress messages in multiple languages.
- Refactored the export progress handling to provide real-time updates during the export process, improving user feedback and experience.

* refactor(web): streamline export capture bridge and update connector styles

- Removed unused loading logic for html2canvas in the export capture bridge, simplifying the code.
- Updated CSS for the onboarding view connector to improve visual clarity and ensure it does not overlap with node numbers.

* refactor(web): remove html2canvas dependency and enhance Figma URL handling

- Removed the html2canvas package from the project, including its references in the lock file and related components.
- Added functionality to manage Figma URLs within the Design System flow, allowing users to add, remove, and validate Figma file links.
- Improved drag-and-drop handling to prevent unintended file navigation when dropping files outside designated areas.
- Updated UI components to accommodate new Figma URL features, enhancing user experience and accessibility.

* refactor(web): unify brand and design system flows

- Merged the brand extraction process into the design system creation workflow, allowing users to start from a brand directly within the design system wizard.
- Updated routing to redirect legacy brand links to the unified design systems tab.
- Enhanced the onboarding experience by removing the separate Brand Kit tab and integrating brand selection into the design system creation process.
- Improved UI components to reflect these changes, ensuring a seamless user experience across the application.

* feat(web): introduce brand enrichment banner and picker modal

- Added a new BrandEnrichmentBanner component to allow users to refine programmatically-extracted design systems with AI by selecting design-system skills.
- Implemented a BrandPickerModal for selecting brands from a searchable gallery, enhancing the design system creation flow.
- Updated ChatPane to conditionally display the enrichment banner for eligible brand projects, improving user engagement.
- Enhanced the design system flow to support the new brand enrichment features, ensuring a seamless experience for users.

* feat(web): enhance BrandPickerModal and DesignSystemAssetDropzone

- Updated the BrandPickerModal to allow scrolling of the entire picker area, improving user experience by creating a unified scrolling surface.
- Added new props to the BrandReferencePicker for action labels and scroll root reference, enhancing flexibility in brand selection.
- Introduced a new DesignKitView component for rendering design kits consistently across different surfaces.
- Enhanced the DesignSystemAssetDropzone to support a wider variety of file types with appropriate previews, improving asset management during design system creation.
- Updated styles for better visual clarity and responsiveness across components.

* feat(web): update Design Systems tab actions and enhance localization

- Changed the button label in the DesignSystemsTab from "Edit" to "Open" for better clarity in user actions.
- Added a new translation key for 'dsManager.openSystem' across multiple languages to support the updated button label.
- Enhanced the FileWorkspace component to ensure the Design Files tab aligns correctly with the Design System tab, improving UI consistency.
- Implemented a new design system editing feature that allows users to fetch and save design system content from DESIGN.md, enhancing the design workflow.

* fix(merge): repair post-merge regressions after origin/main integration

Follow-up fixes on top of the origin/main merge (886f925cd) addressing
regressions the conflict resolution introduced. main's web suite is the
oracle (100% green); resolution principle was main's engine/backend +
HEAD's UI, unioned.

daemon:
- library-sync.ts: correct design-systems import to ./design-systems/index.js
  (design-systems became a directory module on main).
- tests/server-bootstrap-regression: add LIBRARY_DIR to the PathDeps fixture
  (main-added test x HEAD-added LIBRARY_DIR field).

web:
- WorkspaceTabsBar: union — restore main's onboarding Search-popover close
  behaviour + guards, keep HEAD's library/brands nav entries.
- HomeView: restore main's composer sending-state (await onSubmit, widen its
  return type to Promise<boolean>|boolean|void, pass submitting to HomeHero).
- MemorySection.test: take main's version to match main's two-loop memory
  component.
- i18n: restore dropped settings.onboardingRoleMarketing key across types.ts
  and all locales.
- App/BrandsTab/EntryNavRail/router/home-intent: union fixes restoring main
  features dropped during conflict resolution (needs_input handling, etc.).

Validation: pnpm guard + full pnpm typecheck (all 23 packages) green.
Known-red: EntryShell onboarding step 3 intentionally retains HEAD's "build"
step rather than main's brand-extract step; 8 EntryShell.onboarding /
App.onboarding-amr-e2e tests stay red pending that onboarding decision.

* fix(merge): keep HEAD's unified brand flow (revert main's separate Brands tab)

Follow-up to 688544ff7. Per the chosen product direction (brand creation
unified into the design-system create wizard, not a standalone Brands tab),
revert the brand-flow routing/nav that the post-merge repair had restored
from main:

- router.ts: keep HEAD's brand routing (brands folded into design-systems),
  drop main's standalone /brands and /brands/:id view routing.
- EntryNavRail.tsx: drop main's standalone "Brands" nav button.
- runtime/home-intent.ts: drop main's brand "Use in new chat" confirmation
  notice plumbing (tied to the separate Brands flow).

Kept from the repair commit (additive, non-conflicting): App.tsx
loadedActiveProject correctness, composer Sending… state, WorkspaceTabsBar
onboarding popover behaviour, two-loop memory test, restored i18n keys,
brand needs_input STATUS handling, server.ts plugin-route infrastructure.

* feat(library-ui): implement conditional rendering based on LIBRARY_UI_VISIBLE

- Updated router.ts to conditionally render the library view based on the LIBRARY_UI_VISIBLE flag.
- Modified ComposerPlusMenu.tsx, DesignFilesPanel.tsx, and DesignSystemAssetDropzone.tsx to show the "Select from library" button only when LIBRARY_UI_VISIBLE is true.
- Adjusted EntryNavRail.tsx and EntryShell.tsx to include the library navigation button and section conditionally based on the LIBRARY_UI_VISIBLE state.
- Enhanced HomeHero.tsx to allow starting a blank project directly, improving user experience by providing more options for project creation.

This commit introduces a feature toggle for the library UI, allowing for better control over its visibility during development and testing.

* feat(home-hero): implement edge auto-scroll for horizontal overflow

- Introduced `useEdgeAutoScroll` hook to manage auto-scrolling behavior for horizontally overflowing components in HomeHero.
- Updated `PluginPromptPresets` and `RailGroup` components to utilize the new auto-scroll functionality, enhancing accessibility for users without trackpads.
- Added `EdgeScrollZones` component to provide interactive edge zones for scrolling.
- Enhanced CSS styles to support the new scrolling layout and ensure proper positioning of elements.

This commit improves user experience by making overflow content more accessible and easier to navigate.

* feat(design-systems): add project creation from design system and enhance UI components

- Implemented `handleCreateProjectFromDesignSystem` function in `AppInner` to facilitate project creation directly from a selected design system.
- Updated `DesignKitView` to wrap the iframe in a span for better layout control.
- Refactored CSS for `BrandPreviewCard` and `DesignSystemsTab` to improve styling and responsiveness.
- Introduced a new `TemplatePicker` component in `HomeHero` for selecting project-type templates, enhancing user experience.
- Updated various components to support asynchronous handlers for design system actions, improving overall functionality.

This commit enhances the design system integration and user interface, making project creation more intuitive and accessible.

* feat(brand-routes): enhance brand reservation API and add DESIGN.md support

- Updated the POST /api/brands endpoint to accept optional fields: description and designMd, allowing for more flexible brand reservations.
- Modified validation to require either a URL or designMd for brand extraction.
- Introduced a new design-md-input module to handle parsing and validation of DESIGN.md content.
- Enhanced startBrandExtraction function to support processing of DESIGN.md, improving integration with design systems.
- Added utility functions for managing DESIGN.md input and output, streamlining the brand creation process.

This commit improves the brand extraction workflow by integrating DESIGN.md support, making it easier for users to create and manage brands.

* feat(chat-pane, design-kit-view): enhance chat functionality and design preview features

- Added `handleNextStepPromptAction` to `ChatPane` for setting draft prompts, improving user interaction.
- Introduced `nextStepVariant` to differentiate design system projects in `ChatPane`.
- Updated `DesignKitView` to include a button for previewing design kit covers, enhancing user experience.
- Implemented a modal for displaying design kit previews, allowing users to view content in a dedicated space.

These changes improve the chat interface and design kit interactions, making the application more intuitive and user-friendly.

* feat(brand-extraction): enhance DESIGN.md support and testing

- Added a new test case to validate brand extraction from DESIGN.md input without requiring a website.
- Implemented functionality to register brands directly from DESIGN.md, improving the brand creation workflow.
- Updated the `ChatPane` and `NextStepActions` components to handle design system-specific actions for projects, enhancing user experience.
- Enhanced localization files with new carousel hints and project brief options across multiple languages.

These changes streamline the brand extraction process and improve the overall functionality of the design system integration.

* feat(wireframe-examples): add annotated and greybox wireframe examples

- Introduced new wireframe examples for annotated and greybox styles, enhancing design system capabilities.
- Added HTML and JSON files for both wireframe types, providing templates for low-fidelity design mockups.
- Implemented SKILL.md documentation for each wireframe example, detailing usage and design specifications.

These additions improve the design toolkit, offering users more options for creating wireframes in various styles.

* feat(brand-extraction): refine Chrome fallback and enhance error handling

- Updated the Chrome fallback logic in the prefetch pipeline to clarify its purpose and usage as a diagnostic tool.
- Introduced environment variable checks to enable or disable system Chrome usage, improving control over the extraction process.
- Enhanced error messages in the DesignSystemCreationFlow component to provide clearer guidance on required inputs for creating a design system.
- Added regression tests to ensure that prompts do not instruct the agent to invoke a non-existent `brand-extract` skill, preventing potential failures during brand extraction.

These changes improve the robustness of the brand extraction process and enhance user experience by providing clearer instructions and error handling.

* feat(brand-extraction): enhance DESIGN.md input handling and introduce brand ready prompt

- Updated the BrandFromDesignMdInput interface to explicitly define the description property as optional with undefined.
- Enhanced the brand extraction prompts to clarify the inline brand-extract workflow, preventing confusion during the extraction process.
- Added a new BrandReadyPrompt component to notify users when a design system is ready for preview, improving user experience.
- Introduced CSS styles for the BrandReadyPrompt to ensure a visually appealing and user-friendly interface.
- Updated localization files to support new strings related to the brand ready prompt across multiple languages.

These changes improve the clarity and usability of the brand extraction process, providing users with timely feedback and a more intuitive interface.

* feat(brand-extraction): improve design system focus handling and localization updates

- Refactored the handling of browser tabs in the brand extraction tests to ensure proper validation of tab states.
- Enhanced the AppInner component to refresh design systems alongside templates, ensuring users see the latest updates without page reloads.
- Introduced a pending focus state in the DesignSystemsTab to manage design system selection more effectively after brand extraction.
- Added a BrandReadyPrompt in the ProjectView to notify users when a design system is ready for preview, improving user engagement.
- Updated localization files for Chinese (Simplified and Traditional) to reflect changes in terminology related to design systems.

These changes enhance the user experience by providing timely feedback and ensuring that the design system selection process is seamless and intuitive.

* fix(styles): adjust letter-spacing and enhance plus-menu trigger styles

- Set letter-spacing to 0 in design-system-flow.css for improved text clarity.
- Added styles for plus-menu trigger in plus-menu.css, including background, border, and hover effects to enhance user interaction and visual consistency.

These changes refine the design aesthetics and improve the usability of the plus-menu component.

* feat(tests): add design-system focus handoff tests

- Introduced a new test suite for validating the design-system focus handoff functionality.
- Implemented tests to ensure that the focus ID is correctly set, read, and cleared from session storage, preventing user selection hijacking.
- Added checks for scenarios where no focus ID is pending, enhancing test coverage for the design system's behavior.

These tests ensure the reliability of the design-system focus handling, contributing to a more robust user experience.

* feat(export): restrict image format options to PNG and JPEG

- Updated the image format options in the export functionality to only allow PNG and JPEG, removing WebP to prevent silent downgrades.
- Enhanced error handling to provide clear feedback when an unsupported image format is specified.
- Adjusted related documentation and comments to reflect the changes in supported formats across the application.

These changes ensure consistency in image export behavior and improve user experience by providing immediate validation errors for unsupported formats.

* feat(origin-validation): implement zero-config OD Clipper bypass for library requests

- Added a new function `isZeroConfigClipperLibraryRequest` to validate requests from locally-installed browser extensions targeting the `/library/` path.
- Updated the origin validation middleware to utilize this function, allowing unpaired browser extensions to access the `/api/library/ingest` endpoint while blocking other cross-origin requests.
- Enhanced tests to cover the new bypass functionality, ensuring correct behavior for both valid and invalid origins.

These changes improve the integration of browser extensions with the local daemon, enhancing user experience while maintaining security.

* feat(design-systems): add download functionality for design systems

- Implemented a new command `od design-systems download <id>` to allow users to download design systems as a .zip file, including all system files and a generated SKILLS.md usage guide.
- Updated the CLI help documentation to include usage instructions for the new download command.
- Enhanced the design systems API to support the download feature, ensuring only user design systems are accessible while handling errors for non-existent presets.
- Added localization strings for the new download functionality across multiple languages.

These changes enhance the usability of design systems by providing a straightforward method for users to obtain and share their design assets.

* feat(design-systems): enhance design system management and localization

- Introduced new UI components and styles for managing design systems, including buttons for downloading, refreshing, and resetting edits.
- Updated the DesignKitView to support direct actions for DESIGN.md editing, improving user interaction with design systems.
- Enhanced the DesignSystemDetail component to include download functionality and improved state management for design system edits.
- Added localization strings for new features, ensuring consistent user experience across multiple languages.
- Improved error handling and user feedback for design system operations, including download failures.

These changes streamline the design system management process, making it more intuitive and user-friendly while ensuring robust localization support.

* feat(tests): add comprehensive tests for design system archive functionality

- Introduced a new test suite for validating the `buildUserDesignSystemArchive` and `buildDesignSystemSkillsMarkdown` functions.
- Implemented tests to ensure correct packing of design system files, including the generation of a `SKILLS.md` guide and exclusion of internal metadata.
- Added checks for handling non-user IDs and scenarios where a design system already includes its own `SKILLS.md`.
- Enhanced the overall test coverage for design system functionalities, ensuring reliability and correctness in the design system archive process.

These changes improve the robustness of the design system features by ensuring thorough testing of critical functionalities.

* feat(figma-import): enhance CLI output and add Figma import endpoint

- Updated the CLI to conditionally log detailed import information based on the `--json` flag, improving usability for users who prefer JSON output.
- Introduced a new API endpoint for importing Figma files, handling file uploads and validating project existence, with appropriate error responses for missing files or invalid URLs.
- Added a dedicated route for the Figma import functionality, ensuring seamless integration with existing project workflows.

These changes improve the Figma import experience by providing clearer output options and robust error handling, enhancing overall user interaction with the CLI and API.

* feat(design-files): enhance DesignFilesPanel with new actions and styles

- Added new action buttons for opening a browser and creating a design system in the DesignFilesPanel, improving user interaction in the empty state.
- Updated styles for action buttons to enhance visual distinction and usability.
- Enhanced tests to verify the functionality of new actions in the DesignFilesPanel, ensuring they trigger correctly.

These changes improve the user experience by providing additional functionality and clearer visual cues in the design files interface.

* fix(ci): restore new project modal flow

* fix(ci): align design kit and onboarding checks

* fix(ci): sync bake preview workflow action

* fix(ci): include plugin preview helper scripts

* fix(review): harden brand source and preview flows

* fix(ci): stabilize web workspace tests

* fix(review): address latest blocking feedback

* chore(ci): retrigger validation after label update

* chore: re-trigger CI on updated main — needs-validation gate moved to merge_group (#4714)

* refactor(lightbox): implement portal for overlays to resolve z-index issues

- Updated the lightbox component to use React's createPortal for rendering overlays directly to the <body>, ensuring proper z-index stacking.
- Removed session mode toggle from HomeHero and adjusted related styles and tests accordingly.
- Cleaned up CSS by removing unused styles related to session mode toggle.
- Updated tests to reflect changes in the HomeHero component and its interaction with the design router.

* style(home-hero): remove focus halo from template search input

- Updated CSS to eliminate the global input focus outline and box-shadow for the template search field in the HomeHero component.
- Added a test to verify that the template picker search field maintains a clean appearance when focused.

* feat(design-system): add create design CTA and enhance design kit functionality

- Introduced a new `DesignSystemCreateCta` component to facilitate creating new designs from an active design system, enhancing user experience in the chat interface.
- Updated `ChatPane` to include the new CTA, allowing users to create designs directly from the chat.
- Enhanced `DesignKitView` with sticky header functionality for better accessibility while scrolling.
- Added new CSS styles for the `DesignSystemCreateCta` component to ensure a visually appealing and consistent design.
- Updated internationalization files to include new strings for the design system creation feature.

* feat(upload): enhance file upload handling and error recovery

- Introduced `sanitizePath` to preserve directory structures during file uploads, preventing issues with subdirectory paths.
- Updated `DesignKitView` and related components to utilize the new `sanitizePath` function for improved file name resolution.
- Added `KitErrorBoundary` component to gracefully handle rendering errors in the design kit, providing a user-friendly fallback.
- Implemented internationalization updates for new error messages and action confirmations related to uploads and error handling.
- Enhanced CSS styles for better visual feedback during error states and improved user experience.

* feat(design-kit): add keyboard shortcuts hint and enhance key handling

- Introduced a new keyboard shortcuts hint in the DesignKitView, providing users with quick access to essential actions (E edit, C copy, U upload, R refresh, ⌫ delete logo).
- Implemented a keydown event handler to manage keyboard shortcuts contextually within the design kit, improving user interaction and accessibility.
- Updated CSS for the shortcuts hint to ensure it remains low-contrast until hovered, enhancing the UI experience.
- Added internationalization support for new shortcut labels and hints across multiple languages.
- Adjusted DesignSystemsTab to prefer user logos for their systems, improving visual consistency.

* feat(design-system): introduce DesignSystemExtractionPanel and enhance design system interactions

- Added the `DesignSystemExtractionPanel` component to facilitate user interactions during design system extraction, providing a synthesized conversation view and next steps.
- Updated `ChatPane` to render the new extraction panel when a design system is active, enhancing user guidance.
- Introduced a new utility function `designSystemExtractionSource` to derive human-readable labels for design system sources.
- Enhanced internationalization support with new strings for extraction-related actions and prompts across multiple languages.
- Updated various components and tests to reflect changes in terminology and functionality, improving overall user experience.

* feat(project): add project deletion functionality and enhance design system interactions

- Introduced `onDeleteProject` prop in `ProjectView` to handle project deletion, improving project management capabilities.
- Updated `AppInner` to include the new delete project handler, enhancing user experience in project interactions.
- Enhanced `DesignKitView` and `DesignSystemsTab` with loading states and improved visual feedback during design system resolution.
- Removed deprecated `DesignSystemCreateCta` component and associated styles, streamlining the codebase.
- Updated internationalization files to reflect changes in project management terminology and actions.

* feat(design-kit): enhance internationalization and user feedback in DesignKitView

- Updated various labels and error messages in the DesignKitView to utilize internationalization functions, improving accessibility and user experience.
- Enhanced color input validation messages and added confirmation prompts for design system deletions in DesignSystemsTab and FileWorkspace.
- Introduced new props for handling design system project deletions, streamlining project management.
- Updated internationalization files to reflect new strings and translations for improved user guidance across multiple languages.

* refactor(design-kit): remove keyboard shortcuts hint and streamline header menu

- Eliminated the keyboard shortcuts hint from the DesignKitView, simplifying the header menu.
- Updated the sticky-header overflow menu to exclude upload, full-system preview, and shortcut help actions, focusing on essential project operations.
- Adjusted related tests to reflect the removal of the shortcuts hint and ensure accurate menu item visibility.

* feat(brand-routes): add extract-from-html endpoint for brand extraction

- Introduced a new POST endpoint `/api/brands/:id/extract-from-html` to re-run brand extraction using HTML rendered from the in-app browser after clearing anti-bot walls.
- Implemented error handling for missing HTML and brand not found scenarios.
- Enhanced the `extractBrandFromHtml` function to process the provided HTML and optional CSS, integrating it into the existing brand extraction workflow.
- Updated `prefetch` functionality to support extraction from pre-rendered HTML, improving the overall brand data retrieval process.

* chore(nix): refresh pnpm deps hash

* feat(brand-cli): add extract-from-html command for brand extraction

- Introduced a new CLI command `od brand extract-from-html` to facilitate brand extraction from pre-captured rendered HTML, allowing users to bypass anti-bot walls.
- Enhanced the command to accept optional CSS and base URL parameters, improving flexibility in extraction scenarios.
- Implemented error handling for missing HTML input and invalid brand IDs, ensuring robust user feedback.
- Updated the `BRAND_USAGE` documentation to reflect the new command and its usage details.
- Adjusted server configuration to accommodate larger payloads for the new extraction endpoint.

* feat(design-system): enhance design system extraction and browser tools

- Added a new script to collect CSS styles from rendered pages, improving brand extraction capabilities by capturing computed styles from cross-origin stylesheets.
- Removed the `DesignSystemExtractionPanel` component and its associated styles, streamlining the codebase.
- Updated `ProjectView` and `FileWorkspace` components to enhance design system interactions and improve user experience.
- Introduced new internationalization strings for design system phases and actions, ensuring better user guidance across multiple languages.

* feat(brand-assist): implement browser assist for brand extraction

- Added support for a client-side confirmation mechanism for the brand-browser-assist od-card, allowing users to extract brand information from the unblocked browser DOM.
- Enhanced the `ProjectView`, `ChatPane`, and `AssistantMessage` components to handle the new assist functionality, improving user interaction during brand extraction.
- Introduced new internationalization strings for browser assist prompts and messages, ensuring clarity and guidance across multiple languages.
- Updated the `useBrandReadyPrompt` hook to manage the state of the browser assist, providing a seamless user experience when dealing with anti-bot walls.

* feat(brand-prompt): enhance BrandReadyPrompt with refinement options

- Updated the BrandReadyPrompt component to include options for AI optimization and manual editing, allowing users to refine extracted brand systems.
- Added a new refinement nudge to inform users that automatic extraction may miss details, improving user guidance.
- Adjusted styles for the prompt and dismiss button for better alignment and visual consistency.
- Introduced new internationalization strings for the refinement features, ensuring clarity across multiple languages.
- Removed deprecated PPTX export functionality from the FileViewer component, streamlining the export options.

* refactor(export): remove PPTX export functionality and streamline export options

- Eliminated PPTX export support across various components, including CLI, desktop, and web, to simplify export formats.
- Updated documentation and help messages to reflect the removal of PPTX, ensuring clarity for users.
- Adjusted export-related types and constants to focus on PDF and image formats only, enhancing code maintainability.
- Improved user experience by refining export options and related UI elements.

* refactor(export): remove PPTX references and update export functionality

- Removed all instances of PPTX export functionality from the codebase, including related dependencies and comments.
- Updated export options to focus solely on PDF and image formats, enhancing clarity and maintainability.
- Adjusted UI components and tests to reflect the removal of PPTX, ensuring a streamlined user experience.
- Improved internationalization strings and documentation to align with the new export capabilities.

* chore(nix): refresh pnpm deps hash

* fix(onboarding): preserve selected runtime

* fix(brand): localize generated kit copy

* fix(onboarding): align first-run flow with main

* fix(nav): use palette icon for design systems

* fix(analytics): use design system onboarding step

* fix(ui): remove design system guide toggle

* fix(ui): position design system ready prompt

* fix(ui): space plugin task notice

* fix(web): restore home ask mode and design kit preview

* test(e2e): align onboarding visual capture

* test(e2e): align amr onboarding checks

* fix(brand): remove blocked reference brands

* feat(onboarding): show profile choices as chips

* fix(home): prefer design system cover art in recents

* test(e2e): select onboarding profile chips

* feat(brand-extraction): implement programmatic extraction transcript and UI enhancements for design systems

* feat(brand-extraction): enhance programmatic extraction with transcript agent support and UI improvements

* feat(brand-extraction): add transcript agent resolution and improve message handling in brand extraction

* fix(design-systems): stabilize loading state coverage

* test(e2e): align design system detail visual

* fix(brand-extraction): backfill programmatic transcripts

* fix(web): refresh ready brand design systems

* fix(brands): stabilize extraction handoff and seed colors

* fix(brands): return extraction transcript immediately

* fix(web): open new project modal from entry rail

* fix(editing): expose content edits for plain targets

* feat(file-viewer): implement manual edit draft dirty state tracking and reset logic

* feat(design-system): enhance project creation flow with conversation ID handling

* feat(brands): implement light theme handling for color extraction and seed generation

* feat(brands): add finalizeBrandProject function for brand project completion

* feat(file-workspace): add designSystemBrandId prop and update DesignSystemProjectPanel to use it

* Fix manual editing for brand kits

* fix(design-system): wait for project refreshes

* fix(web): open new project modal from rail

* fix(web): restore home ask mode toggle

* fix(web): sync brand color edits with seeds

* fix(web): stabilize design system workspace tests

* test(tools-pack): relax Windows resource cache timeout

* chore(pr): retrigger review after validation

* fix(web): surface design kit action progress

* fix(web): clarify brand next-step actions

* fix(web): cancel programmatic brand extraction

* fix(web): add design systems tab action feedback

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: xne998808-ai <xne998808@gmail.com>
Co-authored-by: PerishCode <perishcode@gmail.com>
Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
Co-authored-by: lefarcen <935902669@qq.com>
Co-authored-by: Siri-Ray <2667192167@qq.com>
2026-06-25 03:56:14 +00:00
PerishFire
0bf1b6d6b8 [codex] converge release workflows and stable dry-runs (#4390)
* fix(tools-pack): use junctions for Windows standalone peer deps

* fix(desktop): expose IPC during startup

* fix(tools-pack): preserve Windows inspect diagnostics

* fix(tools-pack): report Windows inspect status errors

* fix(packaged): use Electron net fetch for app protocol

* fix(packaged): load Windows renderer from web sidecar

* fix(desktop): show Windows packaged window during startup

* fix(packaged): disable Windows GPU startup

* fix(tools-pack): keep Windows core smoke observable

* fix(packaged): remove Windows startup probes

* fix(tools-pack): trace Windows desktop IPC status

* fix(tools-pack): add Windows IPC diagnose loop

* fix(release): default beta-s Windows updater feed

* chore: clean merged test eof

* refactor(release): unify prerelease channel model

* chore(release): close prerelease doc escape hatches

* refactor(release): converge release channel workflows

* fix(release): install toolchain in metadata jobs

* fix(release): build release package before contracts

* chore(release): bump development version to 0.10.1

* fix(e2e): seed windows packaged smoke runtime config

* fix(release): install toolchain for metadata publish

* fix(release): materialize betas metadata checkout

* chore(release): bump development version to 0.10.2

* fix(release): allow betas metadata cold start from s3

* fix(e2e): support betas packaged update scenarios

* fix(release): pass betas channel into packaged smoke

* fix(release): set betas channel during self-hosted builds

* fix(release): verify counted channel reservations

* fix(release): use pnpm cmd for betas windows publish

* fix(release): add betas manifest artifact fallback

* fix(release): skip beta-s public metadata fetch

* fix(release): read beta-s manifests from storage

* fix(release): cache beta windows tools-pack builds

* fix(release): inline beta mac tools-pack builds

* fix(pack): deep sign unsigned mac bundles

* docs(pack): document payload-first beta updater validation

* fix(release): align preview tools-pack cache flow

* fix(release): align prerelease tools-pack cache flow

* fix(release): pass github token to prerelease metadata

* fix(release): setup pnpm before feishu notify

* fix(release): add stable dry-run prepublish flow

* fix(release): accept completed prerelease metadata gate

* fix(release): require stable release branches

* fix(release): converge r2 access checks

* fix(updater): use release channel parser for defaults

* fix(updater): harden windows payload relaunch

* fix(release): converge updater smoke fixture contract

* test(e2e): require silent updater fixture output

* fix(release): align stable windows smoke build path

* fix(ci): include release workspace in validation

* fix(ci): repair release validation lanes

Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex)

* fix(ci): restore zero-install Feishu notification

Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex)

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-23 06:13:21 +00:00
kokisanai
b02d20e6b9 fix: unify Discord invite links (#4452)
Co-authored-by: koki yanlai xu <koki@kokideMacBook-Air.local>
2026-06-17 08:25:16 +00:00
PerishFire
915548b4bd [codex] Fix social template English metadata (#4427)
* Fix social media template English metadata

* Remove social template description hard wraps

Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex)

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-17 11:00:06 +08:00
lefarcen
f6cceb303d fix(plugins): unwrap cosmetic hard wraps in bundled manifest descriptions (#4406)
Picking a Home example-prompt card (or "Replicate this content" in the
plugin detail modal) seeds the composer with the plugin manifest's
`description`. Many descriptions were authored with cosmetic hard wraps
(a single newline mid-paragraph, ~75 cols, as if formatted for a
terminal/markdown source). The composer renders the seed with
`white-space: pre-wrap`, so those newlines survived as short ragged
lines that never filled the editor width — leaving a large blank gutter
on the right of the input box (e.g. the Trading Analysis Dashboard
template: 4 hard breaks, ~200px / 29% of the editor blank).

Reflow the offending `description` / `description_i18n` strings in the
56 affected bundled manifests into flowing text (wrapped lines joined,
real blank-line paragraph breaks preserved; CJK joins carry no space).
Surgical string edits only — manifest formatting/key order untouched
(146 lines changed across 56 files). The full build spec still reaches
the agent as plugin context (SKILL.md + example.html); only the
human-facing seed copy changed.

Add an e2e guard (plugin-description-hardwrap.test.ts) that fails if any
bundled manifest description carries an intra-paragraph hard wrap, so
the cleanup can't silently regress when new examples are added.
2026-06-16 22:39:55 +08:00
free666799
eb749841b4 fix(home): surface community slide decks on Home with letterbox-free 16:9 previews (#4350)
* fix(plugins): surface slides decks on Home instead of marketplace sources

The 23 community slides/deck plugins from #4127 were registered as a
restricted community marketplace source, so they showed up as installable
"available sources" cards (受限 + Install) instead of on Home. Relocate them
to plugins/_official/examples so they ship bundled — appearing in the Home
Community gallery and the deck example-prompt rail, exactly like the existing
zhangzara / swiss / guizang decks — and drop their community-registry entries.

- Move 23 plugins/community/<slug> → plugins/_official/examples/<slug>
  (upstream LICENSE / author / homepage / "Based on" attribution preserved)
- Rename manifest name community-<slug> → example-<slug> (bundled convention)
- Remove the 23 entries from plugins/registry/community/open-design-marketplace.json
  (the 3 pre-existing community entries stay)
- HomeHero: uncap the deck example-prompt rail (other chips keep the curated 18)
  so every bundled slide template is reachable straight from "All"
- curatedPriority: pin the 23 slides to the front of both the deck example rail
  and the Community Slides shelf

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(home): drop provenance tail from deck seeds & fix deck preview letterbox

Two polish fixes for the slide/deck plugins now surfaced on Home:

1. Example-prompt seed: strip a trailing source-attribution sentence
   ("…。移植自 foo/bar 的 baz 模板。" / "Based on …") from the composer seed so
   the prompt doesn't end on provenance boilerplate. Conservative — only fires
   when the final sentence opens with an attribution marker and real text
   precedes it; attribution woven mid-description (followed by a use-case
   sentence) and the gallery/detail descriptions are left intact. Latin '.'
   only ends a sentence at whitespace/EOL so "STYLE_PRESETS.md" / "github.com/…"
   don't mis-split.

2. Deck gallery preview: decks ship a fixed 16:9 stage that scales to its
   viewport, so the tall scroll-preview frame letterboxed it and showed a dark
   --stage-bg band above/below the slide. Tag deck cards with data-od-mode and
   give them a 16:9 frame the iframe fills natively (no transform, no pan), so
   the stage sits edge-to-edge with no band.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(home): deck preview frame to 16:9 so no white strip below the slide

The deck preview override targeted the inner html-frame while the gallery frame
kept its fixed 300px height, leaving a white strip under the 16:9 slide. Make
the gallery frame itself 16:9 for deck cards so the stage fills it exactly —
title bar + slide, nothing left over.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(decks): hide the page-counter chrome on all 23 community slide decks

The five upstream deck families each render a different page-counter ("1 / 10")
— a center pill (.deck-controls), an id="counter" badge, a fixed .deck-counter,
or a .count span inside a Shadow-DOM rail — so the home gallery thumbnails
showed it inconsistently. Per maintainer request, drop it everywhere rather
than unify: inject a display:none rule for the light-DOM counters and inline-
hide the Shadow-DOM .count span. Keyboard/touch navigation is untouched; only
the visual counter is removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(home): fix deck letterbox band in the example-prompt rail tiles too

The earlier 16:9 deck-preview fix only covered the Community gallery cards; the
hero example-prompt rail tiles render the deck in a 4:3 (1440×1080) preview and
still showed a dark --stage-bg band on top. Tag deck preset tiles with
data-od-mode and give them a 16:9 preview the iframe fills natively, matching
the gallery treatment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(home): remove the ↗ open-external button from community gallery cards

The ↗ only rendered when a tile's preview was an HTML source, so it
appeared on some cards (most decks, a few prototypes) and not others
(images, srcless tiles) — inconsistent chrome across the shelf. Drop it
and the whole onOpenExternal pass-through (PluginCard → PluginsHomeSection
→ HomeView) plus the now-dead .plugins-home__gallery-open styles.

* fix(home): make the community search clear (×) button visible

The clear button uses the shared <Button> component, whose CSS-module
class set padding 6/12 and crushed the 12px × glyph to zero width inside
the 26px button (a blank grey square). The .plugins-home__search-clear
reset only out-specified the global `button {}` element rule, not the
component class — scope it under .plugins-home__search so the padding:0 /
20x20 sizing actually wins.

* fix(home): align deck example-prompt tile title row with other tiles

Deck preset tiles used a 16:9 `auto` preview row, so their card was
shorter than the fixed-150px sibling tiles; the flex rail stretched them
back up and the slack leaked into the title row, making deck titles ~6px
taller. Keep deck tiles on the standard 150px preview cell and center the
native 16:9 stage inside it (neutral margin, no dark band), so card and
title-row heights match prototype/HyperFrames/image tiles.

* fix(deck-bridge): mirror the visible class so reveal animations fire on navigation

Reveal-animation decks (the frontend-slides family) gate staggered
entrances on a separate `.slide.visible` class that the deck's own show()
adds alongside `.active`. The host bridge's setActive() flipped only the
active class, so bridge-driven page turns showed slide chrome but left
every .reveal child at opacity:0 — the body rendered blank. Mirror
`.visible` in lock-step with the active slide (only for decks that use it,
a no-op elsewhere). Adds a red→green regression test.

* fix(home): unpin the bare Frontend Slides template from the slides shelf

example-frontend-slides is the family-root template with a generic cover;
pinned first it read as filler leading the Slides shelf and deck chip.
Drop it from PINNED_SLIDE_PLUGIN_IDS so it falls to the uncurated tail
while the styled variants (Creative Voltage, Electric Studio, …) keep the
lead.

---------

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:32:15 +00:00
free666799
c7e422d7a2 feat(plugins): unify all 56 official deck seeds with the Open Design product narrative (#4357)
* feat(plugins): unify all 56 official deck seeds with the Open Design product narrative

Apply the same canonical 10-section story used for the community slides
batch (sourced from the homepage structure doc + README) to every official
deck plugin seed that ships an example.html: cover, why, three claims,
numbers board (60K+ stars / 300+ contributors / 217+ plugins / 129 design
systems / 21 agents), 5-step workflow, multimodal outputs, capabilities,
agent ecosystem, testimonial, and CTA with GitHub/Discord/X links.

Scenario decks keep their framing with Open Design as the subject:
weekly-report/weekly-update become OD growth reports, course-module a
getting-started tutorial, testing-safety-alert the local-data-security
story, xhs-* decks OD-themed xiaohongshu notes, ib-pitch-book an investor
narrative, presenter-mode-reveal keeps its presenter-mode demo.
open-design-landing-deck only gets its numbers aligned to the canonical
figures. Skipped (no example.html seed): guizang-ppt, html-ppt, replit-deck.

Content-only edits: CSS tokens, layouts, decorations, animations, keyboard
nav, hash routing and functional JS untouched. zh 13 decks / en 43 decks
per existing typography. All 56 verified: script syntax, cover screenshot,
no fictional brand residue.

* fix(decks): wire dead Download/closing CTAs to real destinations

Review follow-up for #4145: primary Download CTAs now point to
https://open-design.ai/ (the canonical download landing), and the
remaining href="#" closing links (Star on GitHub / Discord / X /
See All Agents) point to the repo, Discord invite, and X profile.
Also split the landing-deck primary CTA off the repo-root URL so the
primary and secondary actions no longer share a destination.

* style(official-decks): anti-slop visual pass across the official deck seeds

Restyle/polish sweep over all 55 official example decks (taste-skill +
impeccable + gsap-skills guidelines):

- A-class seeds (AI-slop look: default Inter, purple-blue gradients,
  uniform rounded shadow cards) fully restyled with distinct typographic
  systems, locked single accents, and off-white/off-black grounds.
- B-class seeds (clear style family, e.g. the zhangzara-* craft set)
  kept their family signature and received polish only: spacing rhythm,
  contrast to WCAG AA, hairline discipline, reduced-motion guards.
- Motion limited to transform/opacity with prefers-reduced-motion
  guards; signature ease cubic-bezier(.16,1,.3,1).
- Content is unchanged: all copy, numbers (60K+ stars, 217+ plugins,
  129 design systems, 21 agents, -80% cost), links, slide counts and
  the deck engine scripts are byte-identical to the previous seeds.
- html-ppt-zhangzara-pin-and-paper already met every rule (craft fonts,
  single ink accent, static content) and is intentionally untouched.

* i18n(official-decks): translate all Chinese deck seeds to English

All official slide seeds are now English-only per template policy.
15 decks translated (~12,000 CJK chars): presenter-mode-reveal,
testing-safety-alert, xhs-pastel-card, tech-sharing,
obsidian-claude-gradient, knowledge-arch-blueprint, xhs-white-editorial,
hermes-cyber-terminal, xhs-post, dir-key-nav-minimal,
graphify-dark-graph, ppt-keynote, guizang-editorial,
swiss-international, open-slide-canvas.

- Layout, engine scripts, slide counts, stats (60K+/300+/217+/129/21/
  -80%) and links unchanged; only content language changed.
- CJK-specific Google Fonts (Noto Sans/Serif SC, ZCOOL KuaiLe, Songti)
  replaced with Latin families matching each deck's voice (Inter,
  IBM Plex Sans, Nunito, Patrick Hand, Georgia, Noto Serif).
- The xhs-* social decks keep their Xiaohongshu aesthetic with native
  English social copy.
- Overflow from longer English copy fixed with minor per-element type
  sizing; every deck screenshot-verified; zero CJK characters remain
  across all 56 official deck seeds.

* fix(xhs-pastel-card): restore absolute positioning of topbar/footer chrome

The content-layer rule '.slide > *:not(.xp-blob){position:relative}'
(specificity 0,3,0) overrode the absolutely-positioned .xp-topbar and
.xp-footer (0,2,0), dropping both into the flex flow: the chip overlapped
the headline, left:90px turned into a 90px rightward shift that pushed
the page number off-canvas, and bottom:40px lifted the footer into the
body copy on every slide. Excluding the two chrome elements from the
content-layer rule restores the intended layout; verified per-slide
screenshots across all 8 slides.

* feat(deck-seeds): expand the three sampler decks to full 10-page examples

deck-guizang-editorial, deck-swiss-international, and
deck-open-slide-canvas shipped as 1-2 page style samplers while every
other official seed carries a full 8-11 page example. Each is now a
10-page deck built from its own SKILL.md layout vocabulary:

- guizang-editorial: one page per L01-L10 layout, single Ink/Monocle
  palette per the 5-pick-1 rule, ink/paper reversal for rhythm.
- swiss-international: 10 of the 22 locked layouts (statement, cards,
  six-cell grid, timeline, duo compare, loop diagram, why-now, closing
  manifesto), Klein Blue as the single accent; SKILL.md example_desc
  updated from the stale two-page wording.
- open-slide-canvas: ten free-composition 1920x1080 canvases (asymmetric
  split, oversized numerals, positioned-block flow, editorial quote,
  comparison spread) with keyboard + hash navigation per its own
  convention.

Content follows the English-only OD narrative with canonical stats and
links; every page screenshot-verified; zero CJK; single-file with
Google Fonts as the only external resource.

* fix(decks): wire the two remaining dead closing-slide CTAs

Review follow-up for #4145 (nettee, looper reviewer):

- 8-bit-orbit: the closing 'Download Open Design' / 'Star on GitHub'
  pixel buttons were plain <button> elements with no click handling;
  converted to anchors targeting https://open-design.ai/ and the
  GitHub repo, keeping the .pixel-btn skin.
- retro-windows: the closing copy promised download/star actions but
  the action row was the old unwired Restart / Contact / End Session
  set; replaced with Download Open Design / Star on GitHub /
  Join Discord anchors in the same .btn-retro skin.

* fix(decks): wire remaining button-skinned dead CTAs across deck seeds

Review follow-up for #4145 (looper reviewer round 3). Converts every
remaining action-copy control that carried button/chip skin but no
href into a real anchor with the canonical targets, keeping each
deck's skin:

- zhangzara-long-table: closing .pill chips (GitHub / Download) and the
  cover 'Star on GitHub' pill
- zhangzara-raw-grid: closing .label arrow Download + the two
  .s10-rb-block tiles (macOS-Windows / Star on GitHub)
- zhangzara-peoples-platform: GET STARTED slide DOWNLOAD block
- obsidian-claude-gradient: all four .oc-pill chips on the CTA slide
- zhangzara-biennale-yellow / sakura-chroma / cobalt-grid colophon
  ftag labels, zhangzara-pink-script 'Star on GitHub' tile, and
  ib-pitch-book 'Download Open Design' stamp (same pattern, found by
  a repo-wide sweep for the regression class)

* fix(decks): wire zhangzara-coral closing-slide social icons to anchors

* feat(plugins): unify guizang-ppt (magazine-web-ppt) deck default with the Open Design product narrative in English

The deck-mode default seed (magazine-web-ppt, dir guizang-ppt) was the one
official deck the narrative+i18n pass missed, because its content lives in
assets/example-slides.html + assets/template.html rather than example.html.

- Rewrite the 9-slide example deck to the English Open Design product narrative
  (60K+ stars / 300+ contributors / 217+ plugins / 129 design systems / 21
  agents / -80% cost), preserving the magazine editorial layout vocabulary and
  hitting all 8 layout categories. English titles use the Playfair .h-hero-en
  family; copy follows anti-slop craft (no decorative em-dashes, real labelled
  metrics, tight hierarchy).
- Translate template.html (title, hint, all CSS/JS comments), SKILL.md,
  references/*.md, open-design.json, and the design-templates README to English.
- Keep magazine-web-ppt name, mode=deck, default_for=deck intact.
- Both synced copies (plugins/_official + design-templates) updated identically.

---------

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-16 08:41:04 +00:00
PerishFire
a0afc584bb [codex] centralize daemon data directory docs (#4222)
* docs: centralize daemon data directory contract

* fix(e2e): allow slower artifact consistency navigation

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* docs: localize daemon data directory pointers

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-15 02:52:05 +00:00
elihahah666
ec524986b5 chore(plugins): remove html-ppt-dir-key-nav-minimal and html-ppt-xhs-post (#4212)
* chore(plugins): remove html-ppt-dir-key-nav-minimal and html-ppt-xhs-post

Final cut list from the maintainer review of the slide-template gallery
(narrowed from the originally proposed nine html-ppt studio seeds to
these two; the other seven stay).

Removed across every surface:
- plugins/_official/examples/<slug>/ (2 plugin dirs)
- design-templates/<slug>/ (2 catalogue entries)
- plugins/registry/official/open-design-marketplace.json entries
- apps/web/src/i18n/content{,.ru,.fr}.ts slug keys

Landing-page solution showcases never referenced these two, so no
landing changes are needed. pnpm guard and pnpm typecheck pass;
repo-wide grep for both slugs returns zero hits.

* fix(registry): sync bundledPreinstallCount after removing two plugins

plugins-marketplaces.test.ts asserts metadata.bundledPreinstallCount
equals the registry plugins array length; update 414 -> 412 to match
the two removed entries.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-13 13:15:04 +00:00
elihahah666
b034609cde chore(plugins): remove the shamoni example plugin (duplicate preview imagery) (#4040)
* chore(plugins): remove the shamoni example plugin

The Shamoni scroll-driven gallery example ships a baked preview that
duplicates luxury-botanical's hero imagery, so the Community shelf
shows the same perfume tile twice. Curator call: drop the example
entirely — plugin folder, baked-preview manifest entry, and its slot
in the pinned curated ordering.

* fix(daemon): prune persisted bundled rows when their folder leaves the image

The bundled boot walker only upserted folders that still exist, so a
plugin removed from the daemon image (like the Shamoni example this PR
deletes) survived in upgraded installs' installed_plugins table — and
/api/plugins kept serving a record whose backing files were gone.

Make bundled rows mirror the bundled tree: after a successful walk,
delete source_kind='bundled' rows whose folder was not seen this boot.
Folders that still ship but fail to parse stay registered (warned, not
pruned), the ENOENT early-return never prunes (a missing bundledRoot is
a packaging bug, not a removal), and user-installed rows are untouched.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-10 08:07:12 +00:00
elihahah666
ec47346e94 feat(web): composer 插件菜单 & 设计百宝箱 hover 预览 (#4000)
* feat(web): hover-preview column in the composer plugins menu

Hovering (or arrow-defaulting to) a plugin in the composer "+" → Plugins
flyout now opens a second-level preview column: a live preview hero
(reusing the plugins-home PreviewSurface — media poster or sandboxed
example iframe) plus the localized title, trust badge, description, and
tags. The previewed row stays highlighted so the panel's subject is
clear before the cursor lands.

The Plugins flyout widens to fit the side column and reserves that width
in the placement math; on narrow (contained) surfaces the preview drops
below the list instead. Other submenus are unchanged.

* feat(web): design-toolbox hover preview + styled detail panel

Extends the plugin hover-preview to the project composer's design
toolbox. Hovering a plugin entry now renders the same rich preview
(ComposerPluginPreview — poster / sandboxed example iframe + title,
trust badge, description, tags); every other kind (skill, MCP,
connector, file, follow-up action) keeps a compact text card.

The shared hover-detail panel (.plus-menu__detail) previously shipped
with no CSS at all — it had no position/background/border, so the
inline left/top never applied. This adds the panel styling (fixed,
panelled, shadowed, viewport-clamped) plus the section-label and
detail text styles, and clamps the panel's top so the taller plugin
preview stays on screen. ComposerPluginPreview's column divider was
de-scoped to the plugins-flyout context so it renders cleanly inside
the toolbox panel too.

* fix(web): drop redundant divider above design-toolbox search

The toolbox head carried a border-bottom while the search box below it
has its own full border, so with the flyout gap the two hairlines read
as a doubled line. Drop the head border; the search box already bounds
the section.

* fix(web): localize plugin titles in the composer plugins list

The list rendered the raw `plugin.title` (often English) while the
hover preview used the localized `title_i18n`, so the same plugin showed
two different-language names side by side. Render the localized title in
the list too, and fold it into the search haystack so a localized-name
query still matches.

* feat(web): show plugin kind tag in the hover preview

Adds a localized kind pill (Prototype / Slides / Image / Video / Audio /
HyperFrames / Live artifact) to the plugin preview title row, reusing
extractCategories — the same taxonomy that powers the home Community
filter chips — so the preview names the plugin's type at a glance. Shows
in both the composer plugins menu and the design-toolbox preview.

* fix(web): localize the applied-plugin chip title

The composer's applied-plugin chip showed the raw `record.title` (English,
e.g. "Audio Jingle") while the same plugin's preset card / hover preview
used the localized `title_i18n` (e.g. "音频铃声"), so the two read in
different languages. Localize the chip in both surfaces:
- HomeView: activeBadgeTitle now uses localizePluginTitle(locale, record).
- PluginsSection: the ContextItem label (project ChatComposer chip) too.

Mirrors the already-correct PluginPromptPresetCard pattern.

* fix(web): localize trust badge, drop raw tag chips from preview

- TrustBadge now resolves its label via i18n (pluginsView.trust.*) so
  Official / Trusted / Restricted follow the active locale everywhere it
  renders; an explicit `label` prop still overrides.
- Drop the raw manifest tag chips from the plugin hover preview. Tags are
  author-defined English slugs with no controlled vocabulary, so they
  can't be reliably localized; the localized kind pill already conveys
  the category, so the card stays single-language.

* feat(web): tag design-system plugins in the hover preview

Design-system plugins aren't one of the home Community facets, so
extractCategories returns nothing and they had no kind pill. Detect them
by mode/tag (same heuristic as the preview classifier) and show the
localized 'Design systems' label (entry.navDesignSystems).

* i18n(plugins): backfill title/description translations for 22 example plugins

These 22 official example manifests shipped title_i18n / description_i18n
with only zh-CN + en, so in every other UI language (Korean, Japanese,
…) the plugin name and description fell back to English — visible now
that the composer surfaces them in the hover preview.

Fill all to the full 18-locale set (zh-CN, zh-TW, ja, ko, de, fr, ru,
es, pt-BR, it, vi, pl, id, nl, ar, tr, uk, en), matching the locale set
used by the already-complete manifests. Brand/product/proper names and
technical terms are kept verbatim; useCase.query stays English-authoritative.

* fix(web): clamp design-toolbox detail panel into the viewport

The left-side fallback (when the right side overflows) used
rect.left - gap - detailWidth without clamping, so a row near the left
edge or a pane narrower than detailWidth + gap*2 produced a negative
left and pushed the position:fixed panel off-screen. Clamp the chosen
left into [8, innerWidth - 8 - detailWidth] so it always degrades
gracefully. (review: nettee/looper)

* test(web): extract + unit-test toolbox detail panel positioning

Pull the detail-panel placement out of showToolboxDetail into a pure
computeToolboxDetailPosition helper and pin the narrow-pane clamp with a
focused vitest regression (row near left edge / viewport narrower than
the panel never yields a negative left; top clamps too). Addresses the
nettee/looper review ask for a regression check.

* fix(web): match plugins-flyout placement reserve to rendered width

PLUS_MENU_PLUGIN_FLYOUT_WIDTH was 560 while .plus-menu__flyout--plugins
renders at 466px, so getFlyoutPlacement over-reserved and medium-width
panes (~664-757px side room) wrongly fell back to the contained layout,
silently dropping the side-by-side preview column. Set it to 466 (with a
cross-reference comment to the CSS), extract the boundary arithmetic into
a pure resolveFlyoutSide helper, and pin the 466-vs-560 boundary with a
vitest regression. (review: nettee/looper)

* fix(web): localize trust badge tooltip + aria text

title and aria-label still came from the hard-coded English
meta.description, so on non-English locales the badge read as
mixed-language to tooltips and screen readers. Resolve all of label,
title, and aria-label from the localized tier key. (review: nettee/looper)

* fix(web): update TrustBadge test for localized a11y text

The existing TrustBadge spec asserted the old hard-coded English
descriptions ("Open Design official", aria "…: Action plugin"), which the
localization change replaced — that's why Web workspace tests went red.
Keep a localized tier prefix in the accessible text when a contextual
label is passed ("Official: Action plugin") and update the spec to pin
the localized behavior.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-09 17:04:11 +00:00
lefarcen
b8489c9874 fix(plugins): pin the Motion React UMD loader in motionsites plugins (follow-up to #3973) (#3992)
* fix(plugins): pin Motion React UMD loader in plugins, generalize the system-prompt rule

PR #3973 patched the blank-screen crash (Motion React hooks loaded from the
vanilla motion.js DOM bundle) at the runtime/write boundary and added a
Framer Motion note to the official system prompt. This closes the remaining
gaps:

- Root cause was in the plugins, not just the runtime: the 25-plugin
  motionsites batch (#3873) prescribes Framer Motion hooks in the React port
  but never locks how to load them, exactly as it locks fonts/colors/asset
  URLs. Add a "Motion loading (locked)" note to the 8 plugins that genuinely
  prescribe Framer Motion (3d-creator-portfolio, acreage-farming,
  evergreen-finance, liquid-glass-agency, luxury-botanical, mindloop-landing,
  portfolio-cosmic, shamoni). Plugins that map useScroll *down* to a passive
  listener, or use GSAP only (cinematic-landing-page), are intentionally left
  untouched.
- Generalize the system-prompt note to lead with the principle (two UMD
  builds: vanilla DOM vs React, hooks live only on the React build's
  window.Motion) while keeping one pinned example version.
- Add port-path regression coverage for the reported luxury-botanical plugin:
  full Motion hook set (useScroll/useTransform/useAnimationFrame/useMotionValue),
  the minified vanilla bundle, and the wrong-bundle + FramerMotion-global combo.

Validation: pnpm guard, contracts + daemon typecheck, daemon
artifact-runtime-compat.test.ts (8/8).

* fix(daemon): widen Motion UMD normalizer to jsdelivr + wrong-file shape

The runtime normalizer only matched the exact unpkg `motion@VER/dist/motion.js`
script shape, so two real agent outputs still slipped through to a blank screen:
a vanilla bundle served from jsdelivr, and the right package name pointing at the
wrong file (`framer-motion@VER/dist/motion.js`). Widen the matcher to both hosts
and both package spellings, preserve the original CDN host on rewrite, and
document the `<script src>`-only boundary (ESM imports / importmaps / esm.sh are
steered by the prompt + plugin notes, not rewritten). The React-hook usage gate
still keeps animate-only vanilla DOM artifacts untouched, and a new test pins
that the correct framer-motion.js bundle is never falsely rewritten.

---------

Co-authored-by: audit <a@b.c>
2026-06-09 10:26:06 +00:00
elihahah666
75f1472d53 feat(web): align Home composer facet rails with Community + drop 6 low-quality example templates (#3939)
* feat(web): align Home composer facet rails with Community + drop 6 low-quality example templates

Home composer sub-category rails now mirror the Community plugin grid
exactly — same sub-category set, order, and per-facet plugin slice:

- Prototype order: Landing/marketing, Brand/design, Dashboards, Apps,
  Developer tools, Docs/reports
- Slides order: Creative decks, Engineering talks, then Pitch/business,
  Course/training, Reports/briefings, Product/sales
- Sub-chips are derived from the full install set (not the curated
  example subset), so the rail shows every type Community shows
- Selecting a sub-category now lists the same plugins Community lists for
  it via applyFacetSelection (primary-category + sub-category match), so
  the example-prompt count matches the Community count badge

Also removes six example templates with broken/poor visuals (Art Landing,
Prisma Creative Studio, Urban Jungle, Modern Agency, AI Automation,
FlowMate) and their pinned-order entries in curatedPriority.

* fix(web): separate facet display order from matching precedence

Addresses review: reordering SUBCATEGORIES re-bucketed overlapping-tag
plugins because extractSubcategories() resolves via SUBCATEGORIES.find()
(first match wins). Dashboards/app/launch-deck plugins with secondary
design/marketing tags wrongly moved into Brand / design or Creative decks
in both Home and Community.

- Restore SUBCATEGORIES to its original matching precedence (stable buckets)
- Add SUBCATEGORY_DISPLAY_ORDER, applied in buildSubcategoryCatalog, so the
  rails/catalog render Landing/Brand/... and Creative/Engineering/... first
  without changing which bucket a plugin lands in
- Add regression coverage in plugins-home-facets.test.ts for overlapping-tag
  fixtures (dashboard+design, mobile+design, landing+brand, launch+marketing,
  pitch+marketing) and update the display-order expectations

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-08 17:56:31 +00:00
lefarcen
bad35b45c9 fix(daemon): stabilize HyperFrames render handoff (#3882)
* fix(daemon): stabilize hyperframes render handoff

* fix: align hyperframes skill handoff guidance

---------

Co-authored-by: audit <a@b.c>
2026-06-08 08:15:58 +00:00
elihahah666
a93869ee09 feat(plugins): 25 motionsites example plugins + daemon asset cache (#3873)
* feat(plugins): add 25 motionsites example plugins + daemon asset cache

Add 25 first-party example scenario plugins under
plugins/_official/examples/ (packaged from motionsites.ai templates via the
motionsites-to-open-design-plugin skill): each ships open-design.json,
SKILL.md, and a self-contained rendered example.html fidelity seed. All 25
pass PluginManifestSchema.

Their cross-border CDN images/videos (cloudinary, higgs.ai, motionsites,
cloudfront) are mirrored to Cloudflare R2 (plugin-assets.open-design.ai) and
high-fidelity compressed (732MB -> 302MB), so example.html / query / SKILL.md
reference the fast public origin instead of slow cross-border hosts.

Daemon asset cache (plugin-asset-cache.ts + /api/asset-cache): a same-origin
disk-cached proxy for any external preview media that remains. The preview
URL rewriter now routes external media (src/poster attrs, CSS url(), and JS
string constants) through it, so cross-border assets satisfy the sandbox CSP
(img-src 'self') and load from local cache. SSRF-guarded: http(s) only, no
credentials, and every resolved address must be public.

* fix(asset-cache): tie SSRF validation to the actual outbound connection

The previous guard resolved DNS in assertSafePublicUrl and then let fetch()
resolve again independently, so a DNS-rebinding host could pass the validation
lookup with a public address and steer the real connection to a private one
(e.g. 169.254.169.254). Move the authoritative check to a connection-time
undici Agent lookup (createValidatingLookup): the address that is validated is
the exact address the socket connects to, closing the TOCTOU gap.
assertSafePublicUrl is now a cheap up-front reject (scheme / credentials /
localhost / literal private IP) only. Adds createValidatingLookup unit tests
(public pass, rebinding-to-private reject, all:true any-private reject).

* fix(asset-cache): reject IPv4-mapped IPv6 literals in the private-IP guard

Node's URL parser normalizes a bracketed mapped literal like
`http://[::ffff:127.0.0.1]/` to the hex form `::ffff:7f00:1`, which the old
dotted-decimal regex missed — so a literal mapped host slipped past
assertSafePublicUrl (and literal IPs skip the DNS lookup hook), letting
`/api/asset-cache` target loopback/private IPv4 via its mapped representation.

Canonicalize IPv6 now: expandIpv6() folds `::` compression and any embedded
dotted IPv4 into eight 16-bit groups, and isPrivateAddress() detects the full
`::ffff:0:0/96` mapped range (hex or dotted), feeding the embedded IPv4 back
through the v4 private-range checks. Group-based classification also replaces
the prefix string-matching for ::, ::1, fe80::/10, fc00::/7, ff00::/8.
Regression coverage added for ::ffff:7f00:1 / ::ffff:127.0.0.1 and
http://[::ffff:127.0.0.1]/x.png.

* fix(asset-cache): full link-local range + stream-cap the upstream body

Two SSRF/DoS hardening fixes on the cache path:

- Link-local was matched as the single fe80:: prefix, leaking the rest of
  fe80::/10 (fe90::, febf::, …) through as "public". Classify with a mask
  ((groups[0] & 0xffc0) === 0xfe80); ULA/multicast use masks too now.

- maxBytes was not a hard ceiling for responses without a trustworthy
  Content-Length: arrayBuffer() buffered the whole body before the size check,
  a memory-exhaustion path for a caller-supplied proxy. Stream the body and
  abort the moment the accumulated size exceeds maxBytes, before concatenating.

Tests: fe80::1 / fe90::1 / febf::1 rejected; a no-Content-Length 800-byte
stream against a 16-byte cap rejects with 413 after <10 pulls (proves it stops
reading instead of buffering the full body).

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-08 07:31:41 +00:00
PerishFire
10dfd32a3e Revert "feat: add screenshot-based visual validation to critique loop (#3660)" (#3865)
This reverts commit 931780c914.
2026-06-08 06:24:44 +00:00
nettee
931780c914 feat: add screenshot-based visual validation to critique loop (#3660)
* feat(daemon): add visual validation atom

Generated-By: looper 0.9.3 (runner=worker, agent=codex)

* fix(daemon): fail closed in visual validation

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): narrow visual validation defaults

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): add visual validation to default critique stages

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): harden visual validation review fixes

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): fail closed in visual validation discovery

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* test(daemon): tighten visual validation discovery regression

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): match visual validation reference viewport

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): tighten visual validation capture flow

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): fail closed across visual validation refs

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): honor metadata entry file in visual validation

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): capture visual validation through preview route

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): fail closed without preview context

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): disable pre-start visual validation worker

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): narrow visual validation spec discovery

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): stop advertising visual validation as runnable

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): restore visual validation critique worker

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): delay visual validation until run success

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* test(daemon): cover post-run visual validation scheduling

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): gate post-run visual validation before finish

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* chore(nix): refresh pnpm deps hash

* fix(daemon): preserve deferred pipeline ordering

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(packaging): bundle Chromium for visual validation

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(scenarios): keep visual validation out of default critique loop

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(packaging): bundle Playwright headless shell

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(packaging): invalidate Playwright resource cache

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* fix(daemon): include visual-validation in bundled atom roster

Generated-By: looper 0.9.3 (runner=fixer, agent=codex)

* chore(nix): refresh pnpm deps hash

* fix: restore pre-run plugin surfaces and nix hashes

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* fix: preserve pre-run surfaces and tolerate headed-only chromium bundles

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* fix: launch visual validation with bundled chromium

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* fix: avoid Playwright fixture teardown races

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* fix: fail packaged visual validation on shell-only chromium

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* fix: isolate synthetic Playwright test bundles

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

---------

Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
2026-06-08 04:03:43 +00:00
elihahah666
df9ec8f40d examples: add 3D creator portfolio and Velar luxury real-estate templates (#3817)
* examples: add 3D creator portfolio and Velar luxury real-estate templates

Two first-party motionsites.ai template seeds under plugins/_official/examples/,
each shipping the manifest + locked SKILL.md spec + a self-contained rendered
example.html fidelity anchor.

- example-3d-creator-portfolio: dark gradient-text hero with a magnetic 3D
  portrait, scroll marquee, char-reveal About, and sticky-stacking project cards.
- example-velar-luxury-real-estate: typewriter preloader, scroll-driven building
  that scales up while pinning to a dark stats band, count-up stats, and a
  hover-expand video gallery.

Fixed decoration/portrait images are inlined as compressed WebP data URIs so the
card and detail previews never break in the sandbox; large GIFs/videos and stable
-CDN backgrounds stay as remote URLs. Both manifests validate against
PluginManifestSchema (od.kind=scenario).

* examples: use first-party metadata for motionsites templates

Align the 3D creator portfolio and Velar manifests with the
first-party metadata contract used by the rest of
plugins/_official/examples/** (MIT, author Open Design, repo homepage)
instead of CC-BY-4.0 / third-party motionsites provenance.

Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code)

* examples: point all inlined-asset references in the locked query at example.html

The per-section spec in od.useCase.query.en still named the original remote
hosts (figma.site portrait/decorations, cloudinary HOUSE_IMG) as the asset
source, while only the trailing note said to reuse the inlined data URIs. Since
the query is the authoritative generation brief injected on Use, a port could
copy the deprecated remote URLs and regress to sandbox-403 / broken images.

Rewrote those references to instruct reusing the inlined data:image/webp URIs
from example.html. Genuinely-remote assets on stable CDNs (the 21 motionsites
marquee GIFs, 9 higgs project images, 5 cloudfront gallery videos, the higgs
hero background) are unchanged.

* examples: align Velar nav dark-section refs in the locked query with the seed

The Fixed Navigation bullet in od.useCase.query.en said the nav-color logic
watches "Section 4 and Section 5", but the seed and SKILL.md define the dark
sections as Section 5 (dark statement band) and Section 6 (gallery). Since the
query is injected as the generation brief, the stale ref could make a port watch
the wrong sections and leave the nav dark over the gallery. Updated the string
to match the seed/skill wording.

* examples: give the 3D portfolio nav links real anchor targets

The hero nav shipped #price and #contact links with no matching ids in the
seed, so half the navbar did nothing in the preview (and ports would inherit
the dead links). Added id="price" to the Services section and a minimal
contact footer (id="contact") so all four nav anchors resolve to real targets.
The four-link names stay as the prompt specifies; only the seed gains anchors.

* examples: document the 3D portfolio contact footer in the locked query and skill

The previous fix added a #contact footer to example.html but left the injected
query and SKILL.md describing only five sections (no contact target), so a port
could still recreate a dead #contact anchor. Added the Contact footer section to
the SECTION ORDER, a nav→anchor mapping (every link must resolve), and a Contact
Section spec in both od.useCase.query.en and SKILL.md so the prompt, skill, and
seed all agree.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-07 15:08:47 +00:00
elihahah666
0d84245b98 feat(plugins): add Dashboard UI — Liquid Glass first-party prototype preset (#3779)
* feat(plugins): add Dashboard UI — Liquid Glass first-party prototype preset

Bundle a premium liquid-glassmorphism conference dashboard as an official
example prototype plugin. Picking it routes the plugin as the active driver and
reproduces the template: dual theme-swapped fullscreen background videos, a 4x2
glass/solid card grid, animated voice-wave participant indicators, and a
floating control bar.

- od.kind: scenario with its own generate pipeline (file-write + live-artifact)
  and the full build spec in od.useCase.query so the agent reproduces the design.
- Ships a rendered, self-contained example.html seed as the fidelity anchor and
  the HTML preview entry; the marketplace card uses the motionsites animated
  webp poster.
- All 30 avatars are inlined as base64 SVG data URIs so the preview never breaks
  on external avatar-host rate limits inside the sandbox; background videos and
  screen-share thumbnails stay on stable CDNs.

* fix(plugins): make dashboard-ui-glass avatar instructions consistent with the inlined seed

The top-of-file "Avatars (critical)" rule says to keep the bundled data: URI
avatars, but the Profile button and Meeting alert bullets still named
api.dicebear.com remote URLs — conflicting guidance that could lead a
React/Vite export to ship broken sandbox avatars. Both bullets now say to
reuse the corresponding inlined avatar from example.html.

* fix(plugins): drop dashboard-ui-glass zh-CN query override so it falls back to the full English brief

resolvePluginQueryFallback picks od.useCase.query['zh-CN'] ahead of the English
fallback, so the shortened Chinese string became the entire generation brief for
zh-CN users — dropping the locked avatar/network rules, the card-by-card layout,
and the interaction details the English brief carries, and producing a
materially different dashboard under a Chinese locale. Remove the zh-CN query
override so Chinese users fall back to the authoritative, complete English brief.
title_i18n / description_i18n (marketplace display strings) are unaffected.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-06 08:36:14 +00:00
ziyan2006
071db7ca1b [codex] Stabilize HTML deck navigation state (#3142)
* fix: stabilize html deck navigation state

* fix: avoid misclassifying transform decks as scroll decks

* fix: detect default root-scroller decks

---------

Co-authored-by: Nongzi <3051966228@qq.com>
2026-05-29 07:41:10 +00:00
Yuhao Chen
d0921ed335 fix(skills): avoid orphan web prototype files (#3253) 2026-05-29 03:18:19 +00:00
Jane
f8c860a505 feat(landing-page): localize plugins library across 18 locales (#3010)
* feat(landing-page): localize plugins library across 18 locales

PR #2926 shipped the new `/plugins/` library hub + four kind sub-routes
+ detail pages, but the chrome was English-only — visitors landing on
`/zh/plugins/` saw the old marketplace registry placeholder rendered
by the catch-all instead, and detail pages rendered identical English
copy regardless of locale prefix. This PR brings the plugin surface
to feature parity with `/zh/skills/`, `/zh/templates/`, `/zh/systems/`,
`/zh/craft/`.

## What changes

- New `app/_lib/plugins-i18n.ts` — single source for all plugin chrome
  copy (hub, list pages, chip rails, share dialog, detail-page meta
  labels). English baseline + 17 locale overrides keyed on
  `LandingLocaleCode` (the same short-code shape `localeFromPath()`
  returns). Missing keys per locale fall back to English so a
  partially-translated locale still renders sensibly. Translations
  cover hub copy, four tile titles + blurbs, seven artifact-kind
  labels + descriptions, 23 scene-subcategory labels, 18 detail-page
  chrome strings, and a six-key share-dialog table with a
  per-locale `shareTemplate({title, url})` function (translated for
  every locale where `_lib/i18n.ts` already had one — same voice).
- `app/pages/plugins/{,templates/,templates/[kind]/,skills/,systems/,
  craft/,[slug]/}/index.astro` — every hardcoded English string now
  reads `getPluginsCopy(locale)` keys. Page logic and routing
  unchanged.
- New short-code wrappers under `app/pages/[locale]/plugins/` — six
  files (hub + three sub-routes + `[kind]/` and `[slug]/`) following
  the same pattern `[locale]/skills/index.astro` already uses: each
  re-exports the canonical page component and adds a per-locale
  `getStaticPaths()` so the build emits 17 locale prefixes per
  plugin route. Total plugin-route prerender count goes from ~390 to
  ~7 000, matching the existing skill/template scaling.
- Catch-all (`[locale]/[...path].astro`) — old `getPublicPlugins` /
  `getRegistryCounts` registry rendering removed (placeholder UI
  that was never wired to a real marketplace data source). Plugin
  routes now live exclusively under `[locale]/plugins/...` short-code
  wrappers, so the catch-all stops claiming `'plugins'` as a route
  root. The dead-code path also drops a `pluginCounts.all` reference
  the title row was reading.
- `.plugins-tile-grid` styles promoted from a scoped `<style>` in the
  default-locale hub to global `app/sub-pages.css` so the
  short-code wrapper renders the same hub markup without re-mounting
  per-page CSS — `display: contents`-style scoping pitfalls in
  Astro's per-component CSS scoping made this the cleanest fix.

## Surface area

- [ ] **UI** — new page / dialog / panel / menu item / setting / empty state in `apps/web` or `apps/desktop`
- [ ] **Keyboard shortcut** — new or changed
- [ ] **CLI / env var** — new `od` subcommand or flag, new `tools-dev` flag, or new `OD_*` env var
- [ ] **API / contract** — new `/api/*` endpoint, new SSE event, or changed shape in `packages/contracts`
- [ ] **Extension point** — new entry under `skills/`, `design-systems/`, `design-templates/`, or `craft/`, or change to the skills protocol
- [ ] **i18n keys** — new translation keys (full plugin chrome added across all 18 locales)
- [ ] **New top-level dependency** — adding any new entry to the **root** `package.json`
- [ ] **Default behavior change** — changes what existing users experience without opting in
- [x] **None** — landing-page-only restoration of i18n parity for the plugin surface

## Validation

- `pnpm --filter @open-design/landing-page typecheck` → 0 errors
- `pnpm --filter @open-design/landing-page build:static` → 16 127 pages
  built (+6 584 over current main: ~388 plugin detail pages × 17
  locale prefixes plus the hub + four sub-routes × 17 locales).
- `copy-example-html.ts` reports `266 entry files + 65 referenced
  files`, identical to before — no regression in the asset-mirroring
  pipeline.
- Local Playwright smoke (`/zh/plugins/...`):
  - `/zh/plugins/` renders `<title>插件库 · Open Design</title>`,
    label `插件库`, h1 `407 个可组合的构件。`, four tiles labelled
    `模板 / 技能 / 设计系统 / 工艺`.
  - `/zh/plugins/templates/video/` renders h1 `48 视频`, scene chips
    `全部 / 动效 / 短视频 / 营销 / 产品 / 数据讲解`.
  - `/zh/plugins/example-article-magazine/` share dialog renders
    `复制下面的文案、然后跳到你想分享的平台粘贴即可` etc., share
    template auto-interpolates plugin title + URL into Chinese voice.
  - All 18 locale prefixes (`/zh`, `/zh-tw`, `/ja`, `/ko`, `/de`,
    `/fr`, `/ru`, `/es`, `/pt-br`, `/it`, `/vi`, `/pl`, `/id`, `/nl`,
    `/ar`, `/tr`, `/uk`) → 200 across hub + four sub-routes + sample
    detail page.
  - English `/plugins/` unchanged (default-locale path bypasses the
    `[locale]/...` wrapper).

* feat(landing-page): finish plugins i18n chrome across 18 locales

The first localization pass shipped a partial fix: hub headings, lead
copy, two-level page chrome, detail-page metadata labels, the share
dialog, and the chip rail were still falling back to English on every
non-English locale because plugins-i18n.ts only filled a chrome slice
for `zh` and the file header even claimed "7 artifact-kind labels and
25 scene-subcategory labels are translated" for every locale that did
not yet have those blocks.

Three changes close the visible gap:

1. plugins-i18n.ts: fills the 27 still-missing chrome fields per locale
   for zh-tw / ja / ko / de / fr / ru / es / pt-br / it / vi / pl / id /
   nl / ar / tr / uk. Includes the 7-key category map, the 23-key
   subcategory map, hubHeading / hubLead, the 4 *Label / *Heading /
   *Lead triples for the templates / skills / systems / craft hub
   pages, the 4 tile blurbs, the 4 browse buttons, sceneLabel, allChip,
   the 12 detail-page metadata labels (mode / scenario / platform /
   surface / author / manifest id / tags / preview caption / find on
   GitHub / homepage / open in new tab) and bucket label map, the
   detail share dialog (title / copy link / jump-to), and the
   header-side nav.plugins entry. zh receives the same 11 detail-page
   and share-dialog labels it was also missing.

2. header.tsx + site-footer.astro: routes the hardcoded "Plugins /
   Templates / Skills / Systems / Craft" labels through `nav.*` from
   HeaderCopy, so every locale gets its own dropdown trigger and
   footer column. Adds `nav.plugins` to HeaderCopy and fills it in 18
   locales with the local form ("插件" / "プラグイン" / "Plugins" /
   "Plug-ins" / "Plaginy" / "الإضافات" / etc).

3. plugin-row.astro + content-i18n.ts: chip rail. The bundled-plugin
   branch now runs raw `mode` / `scenario` slugs through the shared
   localizeTaxonomyValue, and that helper now also consults the
   plugins-i18n subcategory map before giving up. localizeTaxonomyValue
   now returns undefined on a true miss instead of the unknownTag
   placeholder, so chips drop quietly instead of showing "Category" /
   "分類" / "Categoría" for taxonomy slugs we have not localized yet.
   Callers that genuinely want the placeholder (`localizeContentTag`,
   blog `category`, system noun) still keep the explicit fallback.

Out of scope and tracked separately: per-plugin title and description
in plugins/_official/* (author-supplied English metadata, ~401 plugins
without an i18n schema in the manifest yet — needs RFC + tooling
before the manifests can be expanded), and adding the long tail of
mode / scenario / category slugs (`code-migration`, `plugin-sharing`,
`tune-collab`, `live-artifacts`, `engineering`, ...) to TAXONOMY_TERMS
so chips render localized labels for every taxonomy value rather than
dropping silently.

* feat(landing-page): cover plugins chip rail long-tail taxonomy slugs

PR #3010's first round localized the high-frequency mode/scenario
chips (prototype, video, image, marketing, design, ...) but left the
~37 mode/scenario and 14 category slugs that show up in real `od.*`
metadata — code-migration, plugin-sharing, design-system, planning,
scenario, refine, discovery, handoff, token-map, tune-collab, orbit,
live-artifacts, engineering, healthcare, hr, sales, support,
default-router, downstream-export, figma-migration, media-generation,
plugin-authoring, validation, 3d-shaders, animation-motion,
audio-music, creative-direction, design-systems, diagrams, documents,
image-generation, marketing-creative, screenshots, slides,
video-generation, web-artifacts, ... — falling through to undefined
and dropping their chip silently on every non-English locale.

The data layer is the source of truth here, so this expansion lands
in `content-i18n.ts:TAXONOMY_TERMS` / `CATEGORY_LABELS` rather than
the plugins-i18n catalog: a single dictionary entry per slug fans out
to every chip-rail consumer (catalog rows, detail metadata, the
templates/[kind] facets) without each consumer touching its own copy.

Translations cover all 17 non-`en` locales. Brand and product nouns
(Figma, Open Design, BYOK, plugin) stay literal; technical taxonomy
slugs get short equivalents that read as chips rather than full
prose. The result on `/ja/plugins/skills/` matches `/plugins/skills/`
chip-for-chip (30 chips both sides) instead of dropping 27 of them
the way the previous iteration did.

* feat(landing-page): read manifest title_i18n / description_i18n on bundled plugins

PR #3010's prior rounds localized chrome and chip rails but the
catalog's most prominent text — each row's plugin name and blurb —
stayed English on every non-English locale. The plugin manifest
schema (`packages/contracts/src/plugins/manifest.ts`) has supported
`title_i18n` and `description_i18n` (Record<locale, string>) on every
manifest from spec v1; ~24 of the 401 first-party manifests already
carry one for `zh-CN`. The reader was just never wired to use them.

This change does the reader half: bundled-plugins.ts captures the
two i18n maps off each `open-design.json`, plugin-row.astro and the
detail page resolve them at render time via two new helpers
(`resolveBundledTitle`, `resolveBundledDescription`) that mirror the
short→long fallback chain documented in the manifest spec
(`htmlLang` like `zh-CN` → short `LandingLocaleCode` like `zh` →
primary tag → `en` → English baseline). The static-paths pass still
runs once for all locales — it has to, since each manifest produces
one URL — but the title/description shown on the rendered page now
reads the locale off `Astro.url.pathname` and picks the right entry
out of the maps.

Verified locally: `/zh/plugins/example-card-twitter/` now reads
"Twitter 分享卡 / 推特金句 / 数据卡, 适合配推文" from the manifest's
existing `zh-CN` block instead of the English baseline.

Plugin-data half follows in a separate commit. The 17 non-English
locales × 401 manifests need backfilling so the reader has something
to resolve to; that's data, not schema, and lands as a sequence of
manifest patches rather than tangled with this code change.

* feat(plugins): translate scenarios bucket title/description across 17 locales

Closes the first chunk of #3028. Eleven scenarios plugins (the
default-scenario bundle for each taskKind: code-migration,
figma-migration, media-generation, new-generation, tune-collab,
plugin-authoring; the default design router; the React / Vue /
Next.js downstream-export starters; and the Refine baseline) get
title_i18n + description_i18n filled for all 17 non-English locales
the landing page serves (zh-CN, zh-TW, ja, ko, de, fr, ru, es,
pt-BR, it, vi, pl, id, nl, ar, tr, uk).

The reader landed in 7ddfe36; this commit is data-only. taskKind
slugs that other docs reference by name (`code-migration`,
`figma-migration`, `tune-collab`, etc.) stay literal in the
descriptions so cross-references still resolve. Brand nouns —
Open Design, Next.js, React, Vue, Figma — also stay literal.

`/ja/plugins/od-code-migration/` now reads
"コードマイグレーション(デフォルトシナリオ)" instead of the English
baseline; `/zh/plugins/skills/` shows "代码迁移(默认场景)" in the
catalog row.

Remaining buckets (image-templates 45, video-templates 50,
examples 140, design-systems 142 = 377 plugins) follow in
subsequent commits in this PR.

* fix(landing-page): drop CJK template wrap when source name is still English

The Chinese / Japanese / Korean fallback templates for craft, skill,
template, system, plugin, and blog text splice the source `name` /
`title` into a CJK sentence frame: ``${name}工艺规则``,
``Open Design 指南:${topic}``, ``${name} は…のスキルです``. When the
underlying SKILL.md / craft markdown / blog frontmatter still ships
an English name (true for ~95% of the catalog today), that produces
mid-sentence script straddling on `/zh/...`, `/zh-tw/...`, `/ja/...`,
`/ko/...` like:

  H1   : "Editorial typography hierarchy工艺规则"
  Lead : "这条 Open Design 工艺规则定义 Editorial typography hierarchy
          的执行标准…"
  Plug : "video 插件 · 3D Animated Boy Building Lego"

That reads worse than the all-English fallback, because the visitor
parses the page in two scripts at once.

Adds a `nameNeedsEnglishFallback` guard that fires for the four CJK
locales whenever the spliced-in name has no CJK characters of its
own, and threads it through every `localizeXxxText` helper:
craft, template, system, plugin, skill, blog. When it fires the
helper returns the raw English content untouched, so the section
renders end-to-end in one language. Chrome (header, footer, breadcrumb,
buttons, share dialog) keeps its CJK rendering — only the
title-and-lead block falls back.

Side benefit: the same guard kicks in on the long tail of plugin
manifests still pending `title_i18n` / `description_i18n` backfill
(tracked in #3028), so `/zh/plugins/<bundled>/` no longer pairs a
"video 插件 · 3D Animated Boy Building Lego" title with a Chinese
breadcrumb. The page reads "3D Animated Boy Building Lego" + the
English manifest description, while header / footer / breadcrumbs
stay localized. Once a manifest ships its i18n maps, the chrome and
body re-converge automatically.

Non-CJK non-Latin scripts (ar, vi, ...) keep the previous behavior —
their templates already read tolerably with English names. If that
turns out to be wrong on a real audit, the same guard generalizes by
adding the matching Unicode range and locale set.

* feat(plugins): translate image-templates bucket title/description across 17 locales

44 of 45 image-templates plugins get title_i18n + description_i18n
filled for all 17 non-English locales (zh-CN, zh-TW, ja, ko, de, fr,
ru, es, pt-BR, it, vi, pl, id, nl, ar, tr, uk). Generated via Claude
Sonnet 4.5 over the OpenRouter gateway, ~$1.38 in API spend, 156s
wall-clock. Brand and cultural references stay literal (Open Design,
Lego, Hanfu, Showa, Pokémon, Black Myth: Wukong). Long AI generation
prompts collapse to a 1-2 sentence summary capturing what the plugin
does — the description doubles as catalog blurb on the landing site,
not as the actual generation prompt (which lives in example.html /
the manifest's preview entry).

Skipped: `profile-avatar-realistically-imperfect-ai-selfie` returned
malformed JSON on three retries; will rerun with a tighter prompt in
a follow-up commit. Catalog rows for that plugin keep falling back to
the raw English fields per #3010's reader change, so nothing breaks.

Tracking: closes the image-templates row in #3028.

* feat(plugins): translate video-templates bucket title/description across 17 locales

49 of 50 video-templates plugins get title_i18n + description_i18n
filled for the 17 non-English landing locales. Generated via Claude
Sonnet 4.5 over OpenRouter, ~$1.47 in API spend, 177s wall-clock.
HyperFrames templates, the Three Kingdoms cinematic series, the
Seedance/short-film prompts, and the K-pop / wuxia / anime variants
all get a 1-2 sentence catalog blurb in each locale; brand and
cultural tokens (Black Myth: Wukong, Hanfu, Showa, Pokémon, Three
Kingdoms / 三国志, Lego, Disney, K-pop, HyperFrames) stay literal.

Skipped: `live-action-anime-adaptation-water-vs-thunder-breathing-duel`
returned malformed JSON on three retries; will rerun in followup.
Falls back to the raw English fields per the reader landed in 7ddfe36.

Tracking: closes the video-templates row in #3028.

* feat(plugins): translate examples bucket (117/140) title/description across 17 locales

117 of 140 examples plugins get title_i18n + description_i18n filled
for the 17 non-English landing locales. Generated via Claude Sonnet
4.5 over OpenRouter, $3.94 in API spend, ~13 min wall-clock at
8-way concurrency. Existing zh-CN translations on 24 manifests are
preserved (the merge keeps author-supplied entries and only adds
missing locales).

23 of 140 returned malformed JSON on three retries — the output
likely hit the 4000 max_tokens ceiling on plugins whose description
balloons across 17 locales. Those manifests fall back to English on
non-`en` rendering per the reader landed in 7ddfe36, and will rerun
in a follow-up commit with a larger token budget and a stricter
output schema.

Tracking: closes 117/140 of the examples row in #3028; the remaining
23 stay open in that issue's failure list.

* feat(plugins): translate design-systems bucket (141/142) title/description across 17 locales

141 of 142 design-systems plugins get title_i18n + description_i18n
filled for the 17 non-English landing locales. Generated via Claude
Sonnet 4.5 over OpenRouter, $2.55 in API spend, 301s wall-clock at
8-way concurrency.

Translator script gained two improvements between examples and this
bucket:
- max_tokens bumped from 4000 to 8000 so 17-locale outputs stop
  truncating on the long-tail manifests with verbose descriptions
- a balanced-brace JSON extractor that pulls the outermost `{ ... }`
  from the response, tolerating trailing prose Claude occasionally
  appends after the JSON object.

Result: only 1 manifest (`totality-festival`) failed parse this
batch, down from ~16% on the examples bucket. The next commit
re-runs the prior buckets' failures with the improved script.

Tracking: closes 141/142 of the design-systems row in #3028.

* fix(plugins): backfill 4 plugins that retried green after JSON extractor improvement

dcf-valuation, social-media-dashboard, wireframe-sketch (examples
bucket) and live-action-anime-adaptation-water-vs-thunder-breathing-duel
(video-templates bucket) parse cleanly under the balanced-brace
extractor introduced for the design-systems batch. The remaining
22 failures from the prior runs hit a different parse mode (Claude
emitting unescaped double quotes inside string values when the source
description contains its own English quotes like 'make it professional');
those will need a tighter prompt and rerun.

* fix(plugins): translate the last 22 plugins with quote-handling prompt fix

The 22 stuck plugins all carried English / Chinese double-quoted
phrases inside their description (\"make it professional\",
\"What's inside\", \"电子杂志 × 电子墨水\") that Claude was emitting
back inside JSON string values without escaping, breaking the parse.

Added one rule to the translator prompt — never use a straight double
quote inside a translated string, prefer single quotes / curly quotes
/ CJK 『 』 / 《 》 — and the previously stuck batch sailed through
clean: 22/22 ok, 0 retries, $0.85.

This closes the long tail of #3028:
- scenarios   11/11   ✓
- image-templates 45/45 ✓
- video-templates 50/50 ✓
- examples    140/140  ✓
- design-systems 142/142 ✓
- atoms       N/A (filtered from public catalog)

All 388 catalog-visible plugins now ship title_i18n + description_i18n
for all 17 non-English locales the landing page serves.

* fix(plugins): clean up four review-flagged i18n data issues

- apps/landing-page/app/_lib/plugins-i18n.ts:759 — Polish bucket
  label `examples: 'Przyklad'` was missing the diacritic; every
  other Polish string in the same block uses proper diacritics.
  Restore to 'Przykład'. (Reviewer: looper #4364985878.)

- video-templates/cinematic-route-navigation-guide — German
  title_i18n.de was a byte-for-byte copy of en ("Cinematic Route
  Navigation Guide") while the German description was already
  translated. Replace with "Cinematischer Routen-Navigationsleitfaden"
  to match the German voice the description sets.

- video-templates/hollywood-haute-couture-fantasy-video-prompt —
  Dutch title_i18n.nl was identical to en for the same reason.
  Translate the trailing noun phrase: "Hollywood Haute Couture
  Fantasy Videoprompt" (mirrors the Dutch description's compound
  word style).

- video-templates/video-seedance-three-kingdoms-guanyu-slaying-yanliang —
  Korean Hangul `돌진` had leaked into the Turkish description (a
  translation-pipeline artifact where the model copied the verb
  from the Korean output without translating it). Replace
  "saflarına돌진 eder" with the idiomatic Turkish "saflarına dalar".

All four are data-only fixes against existing manifests; no schema
changes, no reader changes. typecheck stays at 0 errors.

* fix(landing-page): localize aria-labels, alt text and BreadcrumbList JSON-LD on plugin detail page

The PR's prior rounds left six accessibility / structured-data
surfaces on `/{locale}/plugins/<slug>/` either entirely English or
mixing English chrome with the localized plugin title. Reviewer
flagged each one across multiple loops; this commit clears them all:

1. `aria-label` on the open-in-new-tab popout no longer reuses the
   visible label `pcopy.detailOpenInNewTab` (which carries the
   decorative `↗`). Added `detailOpenInNewTabAria` — same wording,
   no glyph — and the `<a aria-label>` consumes that key. The
   visible link text still ends in `↗`.

2. `<nav class="breadcrumb" aria-label="Breadcrumb">` now reads
   `aria-label={pcopy.breadcrumbLabel}`. Eighteen locales filled
   ("面包屑导航", "パンくずリスト", "Brotkrumen-Navigation",
   "Fil d'Ariane", "مسار التنقل", "İçerik haritası", ...).

3. Share-dialog `<button aria-label="Close">` now reads
   `aria-label={pcopy.shareDialogClose}`. Eighteen locales filled
   ("关闭", "閉じる", "Cerrar", "Закрыть", "إغلاق", ...).

4. Three template-literal a11y strings (`${pluginTitle} preview`,
   `Open interactive preview for ${pluginTitle}`, `${pluginTitle}
   interactive preview`) become function calls
   (`pcopy.previewImageAlt(t)`, `previewSummaryAria(t)`,
   `previewIframeTitle(t)`) so the sentence frame around the
   plugin title rotates with the page locale. Two `<img alt>` call
   sites (the static preview at line 210 and the click-to-expand
   thumbnail at line 179) both consume `previewImageAlt`.

5. `BreadcrumbList` JSON-LD position-2 now reads
   `name: pcopy.hubLabel` instead of hardcoded English `"Plugins"`.
   The visible breadcrumb at line 105 already renders
   `pcopy.hubLabel`; this aligns the structured data with the
   rendered chrome on every locale.

The new function-typed keys deliberately interpolate `pluginTitle`
(which is itself locale-resolved via `resolveBundledTitle`) so the
mixed-language guard from commit 002d457 is preserved: a manifest
without a per-locale title still flows through to a coherent
single-language a11y string because `pluginTitle` falls back to
English along with the rest of the section.

apps/landing-page typecheck stays at 0 errors.

Closes reviewer threads:
- #pullrequestreview-4364985878 (Open in new tab aria)
- #pullrequestreview-4368926224 (Polish typo + plus mixed-language alt/aria)
- #4373... (BreadcrumbList JSON-LD)
- #4374... (aria-label="Close" + aria-label="Breadcrumb")

* fix(landing-page): redirect legacy fa/hu/th /plugins/ paths to canonical

When the new `/{locale}/plugins/...` short-code wrappers landed, the
legacy catch-all `pages/[locale]/[...path].astro` dropped `'plugins'`
from its `paths` list. That intentionally avoids serving stale
marketplace-registry placeholder routes for the modern landing
locales — but it also takes `/fa/plugins/`, `/hu/plugins/`, and
`/th/plugins/` from 200 to 404, because those three legacy locales
live only in the old `_lib/i18n.ts:LOCALES` set and are not part of
`LANDING_LOCALES` (the modern 18-locale list the new wrappers serve).

Three `301`s in `_redirects` send those legacy URLs to the canonical
English `/plugins/...` so SEO and inbound links keep working until
the legacy locale set is retired entirely.

Reviewer thread (#pullrequestreview-4364052045) flagged this as a
non-blocking regression across multiple loops; this commit closes it.

* ci(landing-page): add merge_group trigger so the queue can clear PRs

`landing-page-ci.yml` only fired on `pull_request` and `push:main`,
which meant the required `Validate landing page` and
`Strict PR visual tests` checks never dispatched against the
`merge_group` ref the merge queue creates. The queue then sat at
"awaiting checks" until it timed out and ejected the PR (the
deadlock observed during the 5/26 release window).

Adding a `merge_group: { types: [checks_requested] }` trigger to
the same workflow lets the queued ref reuse the existing job graph,
matching the pattern in `ci.yml` which already wires `merge_group`.

Also drops `plugins/**` into the same paths filter as `pull_request`
since the new bundled-plugins reader (commit 7ddfe364) consumes
those manifests' `title_i18n` / `description_i18n` maps and the
landing-page CI must rerun when manifest data changes.

---------

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
2026-05-27 09:30:59 +00:00
Jane
ceb636aa1b feat(landing-page): plugin detail page interactive preview + share dialog (#2958)
* feat(landing-page): plugin detail page interactive preview + share dialog

The new `/plugins/<manifest-id>/` detail page that shipped in #2926
landed without the two affordances PR #2679 added to the legacy
`/skills/<slug>/` and `/templates/<slug>/` pages: a click-to-expand
iframe of the live artifact, and a share dialog with brand-keyword
copy plus four-channel jump buttons (X / LinkedIn / Reddit /
Facebook). This restores both, sourced from the bundled-plugin
manifest under `plugins/_official/<bucket>/<slug>/open-design.json`.

## Interactive preview

Three preview-type behaviours, gated on `od.preview.type`:

  - `video` (Cloudflare Stream URLs already in the manifest) —
    inline `<video controls poster=...>` with the playable MP4 as
    `<source>`. Detail-page row is unchanged from #2926; controls
    double as the open-full affordance.
  - `html` (a local `example.html` referenced by `od.preview.entry`,
    only the `examples/` bucket today) — `<details>` toggle wraps the
    poster image as the summary; clicking opens a sandboxed
    `<iframe>` that loads the entry HTML lazily, with an
    "Open in new tab ↗" pill in the frame's top-right corner so the
    artifact can be inspected at full screen.
  - `image` or no entry — static `<img>` (existing behaviour).

`copy-example-html.ts` is extended to mirror the local entry and any
`./assets/...` siblings to `out/plugins/<manifest-id>/<entry>` so the
iframe URL resolves on Cloudflare Pages instead of SPA-falling-back to
the homepage. The four examples carrying sibling-asset references
(flowai-live-dashboard-template, trading-analysis-dashboard-template,
open-design-landing, open-design-landing-deck) all render in-place.

## Share dialog

Same `<dialog data-share-dialog>` markup the legacy detail pages use,
so the global click handlers in `header-enhancer.astro`
(`data-share-open` / `data-share-copy` / `data-copy-link`) wire up
the open / copy actions automatically — no extra client bundle. Four
platform jumps (X / LinkedIn / Reddit / Facebook) plus a Copy-text /
Copy-link pair, with a single English template for now (the new
`/plugins/...` routes only generate English pages; localisation can
land alongside the i18n catch-all follow-up).

## Bundled in

- The `copy-example-html.ts` sibling-assets fix from open PR #2880.
  Without it the existing `/skills/<slug>/` iframe still 404s on
  Cloudflare Pages for after-hours-editorial-template and the four
  others; bundling it here means the same script handles both
  sources in one pass and sidesteps two PRs touching identical
  helper code.

* fix(plugins): remove dangling preview.entry from example-hyperframes

The hyperframes example folder ships a SKILL.md (it's an instruction
manual for using the HyperFrames HTML format) but no runnable
`example.html`. The manifest still claimed `preview.type: html` /
`preview.entry: ./example.html`, which made the marketing site try
to iframe a non-existent file and forced the preview pipeline into
its `Path 3` fallback card — leaving the catalog row visually
inconsistent with the eleven sibling `video-template-hyperframes-*`
plugins that have real Cloudflare-Stream poster URLs.

Drop the preview block entirely so the manifest stops promising a
demo it can't deliver. The landing-page detail row continues to
render the typographic fallback card (sourced from title /
description / mode), which is now the honest representation:
"this is an instruction skill, not a renderable template".

* fix(landing-page): address PR #2958 review feedback on plugin preview pipeline

Two blocking issues called out in code review:

1) `bundled-plugins.ts` exposed `previewEntryUrl` for every manifest
   that declared `preview.type: "html"`, even when the entry file
   wasn't shipped. Several first-party manifests fall in this state
   (example-design-brief's `./brief-preview.html`, example-x-research,
   example-pptx-html-fidelity-audit, example-hatch-pet,
   example-last30days, example-guizang-ppt, example-replit-deck,
   example-live-artifact, example-html-ppt, example-dcf-valuation).
   The detail page then rendered a click-to-expand iframe and popout
   link to a file that copy-example-html.ts had skipped, so the
   iframe URL SPA-fell-back to the homepage on Cloudflare Pages.

   `entryRelativeUrl()` now `existsSync()`-checks the resolved local
   path before returning a URL. When the file's missing the detail
   page falls through to the static thumbnail branch, exactly like
   plugins that ship no preview entry at all.

2) `copy-example-html.ts` recognised only `(src|href|poster)="./assets/..."`
   and then bulk-copied the entry's sibling `assets/` folder, so it
   missed two real ref shapes: bare-relative (`href="assets/styles.css"`,
   `src="assets/deck-stage.js"` under example-html-ppt-zhangzara-pin-and-paper)
   and cross-folder (`src="../open-design-landing/assets/hero.png"`
   under example-open-design-landing-deck).

   Replaced the heuristic with a generic walker that:
   - Parses every relative ref in the entry HTML
     (`(src|href|poster|srcset|data-src)=` plus `url(...)`), splitting
     srcset on whitespace/commas so multi-URL attrs are honoured.
   - Resolves each ref against `dirname(entrypointSrc)` for the source
     and against `dirname(iframeAbsPath)` for the destination —
     identical to how a browser resolves the same ref against the
     iframe URL. Files outside the source root or the iframe root
     are dropped.
   - Recurses into copied HTML / CSS / JS / SVG so multi-step chains
     (entry → assets/template.html → assets/fonts/foo.woff) don't
     strand intermediate files.
   - Tracks visited *destinations* rather than sources, so a single
     source that legitimately needs to land at two different out-paths
     (same-folder copy at /plugins/example-X/assets/foo.png AND a
     cross-folder copy at /plugins/open-design-landing/assets/foo.png
     for sibling decks that use `../open-design-landing/assets/foo.png`)
     gets both copies.

Verified manually:
- /plugins/example-html-ppt-zhangzara-pin-and-paper/assets/styles.css
  and assets/deck-stage.js → 200 (bare-relative)
- /plugins/open-design-landing/assets/hero.png and assets/about.png
  → 200 (cross-folder destination, no manifest-id prefix because
  iframe URL `..` collapses the prefix)
- /plugins/example-design-brief/ renders the static thumbnail only,
  no click-to-expand iframe (broken entry guard)
- /plugins/example-flowai-live-dashboard-template/assets/template.html
  → 200 (existing same-folder behaviour preserved)

Build now reports `copied 266 entry files + 65 referenced files`,
where the 65 includes both the same-folder `./assets/...` payloads
the previous heuristic captured and the bare-relative + cross-folder
shapes it didn't.

---------

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
2026-05-26 07:43:46 +00:00
icc
587f6de46d fix: restore Atelier Zero deck plugin prompt (#2822)
Co-authored-by: icc <iccccccccccccc@users.noreply.github.com>
2026-05-24 14:20:25 +00:00
lefarcen
c14baf07d3 Merge origin/main into release/v0.8.0
PR #2461 sync prep — resolves 14 conflicts merging 84 main-side commits
on top of 58 release-side commits accumulated during the 0.8.0 cycle.

Resolution summary:

Take main (theirs) where main carried deliberate forward progress:
- apps/web/src/components/PluginCard.tsx — 7 hunks, i18n migration:
  hardcoded English aria-labels/titles replaced with t() calls keyed
  on pluginCard.* (all 8 keys verified present in en.ts).
- apps/web/src/components/TasksView.tsx — 1 hunk, source-ingestion
  feature: sortedRoutines (newest-first), sourceIngestionTemplates,
  patchSourceForm, submitSourceIngestion. activeCount/pausedCount
  semantics preserved (now keyed on sortedRoutines, count unchanged).
- e2e/ui/app.test.ts — new node:fs/promises + tmpdir + path + @/timeouts
  imports needed by main-side test helpers.
- e2e/ui/settings-local-cli-codex-fallback.test.ts — menu-dismissal
  helper block added by main.

Keep both sides where each added a different field to the same object
literal:
- apps/web/src/components/ProjectView.tsx (locale + analyticsHints
  spread).
- apps/web/src/components/DesignSystemFlow.tsx (locale + analyticsHints).

Take release (ours) where release carried deliberate work that ships
0.8.0:
- CHANGELOG.md — release-side 0.8.0 entry + PR link refs; main's
  Unreleased section was the same body of work, now finalized.
- apps/landing-page/public/{apple-touch-icon,favicon}.png +
  apps/web/public/app-icon.svg — release-side visual refresh assets
  consistent with 0.8.0 stable ship.
- tools/pack/src/linux.ts — packageVersion const required by line 466;
  taking main's empty line would build-error.
- e2e/ui/project-management-flows.test.ts +
  e2e/ui/settings-api-protocol.test.ts +
  e2e/ui/settings-memory-routines.test.ts — release-side release-smoke
  hardening (shangxinyu1 + PerishFire) takes precedence on overlap.

Closes-issue / unblocks: PR #2461 sync release/v0.8.0 → main.
2026-05-23 12:17:18 +08:00
Eli-tangerine
10e11531a1 Improve deck home previews and plugin gallery performance (#2698)
Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-05-22 17:47:28 +08:00
Siri-Ray
e6da01e998 Add i18n metadata for official content (#2692) 2026-05-22 16:39:32 +08:00
Tuola-waj
0ba88a064d Add Codex interactive capability map example (#2657)
* Add Codex interactive capability map example

* Fix Codex map preview entry

---------

Co-authored-by: tuolaji <tuola@tuolajideMacBook-Air.local>
2026-05-22 15:49:16 +08:00
Yuhao Chen
bddec2391d Fix Simple Deck discovery form contract (#2602) 2026-05-22 14:05:24 +08:00
Eli-tangerine
ce95266586 [codex] Polish home composer working-directory controls (#2468)
* Polish design system home flows

* Polish home prompt presets

* Polish home working directory controls

* test: align home hero chrome smoke

* fix: stabilize home composer ci checks

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-05-21 00:22:46 +08:00
lefarcen
c80acfefeb fix(daemon,web): block pitch-deck placeholder publishes and unbreak framework decks (#2384)
Two preview-time bugs surfaced ahead of 0.8.0:

1. Pitch-deck example (#2215): the official html-ppt-pitch-deck prompt asked
   the agent to confirm three facts first, but the manifest had no
   structured `od.inputs`, so the platform's required-input gate had no
   fields to enforce and the run could publish HTML that still contained
   unresolved fundraising placeholders (`Name to confirm`, `$X.XM`,
   `Replace this panel with`, ...). Add structured required inputs to the
   manifest and a daemon-side publication guard that rejects HTML/deck
   artifact writes whose body still contains those placeholders. Scope is
   the file-write boundary only (no assistant-text scanning), so the
   guard cannot trip on the agent's chat prose mid-clarification.

2. Framework deck preview off-screen: `injectDeckBridge` injected
   `place-content: center !important` on `.deck-shell` for every deck-mode
   srcdoc, which forced the framework's `display: grid` shell to re-center
   its implicit track. The framework's `fit()` already centers a
   `transform-origin: top left` stage with an explicit `translate(tx, ty)`
   that assumes the stage's natural layout position is (0, 0); the two
   centerings stacked and the scaled stage landed ~1000px off-screen, so
   the preview showed a sliver of slide content in the top-left with the
   rest black. Skip the override when the framework's `id="deck-stage"`
   marker is in the doc, and drop the dead `display: grid; place-items:
   center` from the deck framework template so future drift can't
   re-introduce the same stack.
2026-05-20 16:20:34 +08:00
Joey-nexu
f1870cbf3d chore(featured): curate Featured picks down to top 10 across categories (#1966)
* chore(featured): curate Featured picks down to top 10 across categories

The picker's Featured chip currently surfaces 64 plugins because
`isFeaturedPlugin` (apps/web/src/components/plugins-home/facets.ts)
treats any finite `od.featured` number as featured, and the field
had been adopted incrementally by 51 skills + 13 templates without
a curation step. The result is a "Featured" tab that's effectively
"everything tagged at all" — no editorial signal.

Curate down to 10 picks, allocated to keep the showcase legible:

  0.001  skills/deck-swiss-international
  0.01   skills/deck-guizang-editorial
  0.02   design-templates/magazine-poster              [add]
  0.04   skills/doc-kami-parchment
  0.10   design-templates/web-prototype-taste-brutalist [add od: block]
  0.13   skills/video-hyperframes
  0.14   skills/frame-glitch-title
  0.15   skills/vfx-text-cursor
  0.16   skills/frame-logo-outro
  0.17   skills/deck-open-slide-canvas

Selection mirrors the html-anything `recommended: 1..10` ranking
(html-anything is the upstream content source for these skills, per
the `od.upstream` field on each SKILL.md). Two of those 10 picks
weren't in the prior featured set at all — `magazine-poster` had no
`od.featured` field and `web-prototype-taste-brutalist` had no `od:`
block at all — so they get added rather than just rebalanced.

Removes `od.featured` from the other 56 files. No UI code change;
the existing `isFeaturedPlugin` logic now reads a curated set
instead of an accidental one.

* chore(featured): align baked plugin manifests with curated top 10

The picker reads `od.featured` from each plugin's
`plugins/_official/examples/<id>/open-design.json` manifest, not from
the SKILL.md frontmatter the previous commit edited. Without this
follow-up the curated set of 10 would be invisible to users — the
picker's Featured chip would still surface 27 baked plugins from the
pre-existing manifests.

Mirror the SKILL.md curation into the baked layer:

  removed `od.featured` from 19 manifests:
    article-magazine, card-xiaohongshu, data-report,
    frame-data-chart-nyt, frame-flowchart-sticky,
    frame-light-leak-cinema, frame-liquid-bg-hero,
    frame-macos-notification, guizang-ppt, html-ppt,
    kami-deck, kami-landing, mockup-device-3d,
    open-design-landing-deck, ppt-keynote, resume-modern,
    social-reddit-card, social-spotify-card, social-x-post-card

  added `od.featured` to 2 manifests:
    magazine-poster -> 0.02
    web-prototype-taste-brutalist -> 0.10

Verified locally against `daemon /api/plugins`: featured count is
now exactly 10, matching the SKILL.md source of truth from the
previous commit.
2026-05-18 12:56:26 +08:00
pftom
9ea33e076b feat(context-plugins): add support for context plugins in project metadata and UI
- Introduced a new `contextPlugins` field in the `ProjectMetadata` type to accommodate plugins selected via `@` mentions, allowing for additive context in project creation.
- Updated the `HomeHero` and `EntryShell` components to handle and display context plugins, enhancing user interaction with selected plugins.
- Implemented rendering logic for context plugins in the metadata block, providing clear visibility of selected plugins and their descriptions.
- Enhanced the UI to support the removal of context plugins and display additional details on hover, improving the overall user experience.

This update significantly enriches the project creation process by allowing users to incorporate multiple context plugins seamlessly.
2026-05-14 15:29:49 +08:00
pftom
0edbf38171 feat(plugins): add specVersion and version fields to plugin and marketplace schemas
- Introduced `specVersion` and `version` fields to the plugin and marketplace schemas, ensuring better versioning and compatibility tracking.
- Updated various components and functions to handle the new fields, including database migrations, plugin snapshots, and marketplace management.
- Enhanced tests to validate the presence and correctness of the new fields in plugin manifests and marketplace entries.
- Improved documentation to reflect the changes in schema requirements and provide guidance on the new versioning system.

This update strengthens the plugin ecosystem by providing clear versioning, enhancing the reliability and maintainability of plugins and marketplaces.
2026-05-13 22:24:50 +08:00
pftom
d3d95121f3 feat(plugins): enhance visual score sorting and add new example templates
- Updated the `sortByVisualAppeal` function to prioritize featured ranks, ensuring that curated plugins are displayed prominently.
- Added tests to verify the new sorting logic, ensuring that plugins with numeric featured ranks are sorted correctly ahead of others.
- Introduced new example templates for a magazine article layout, a Twitter share card, and a Xiaohongshu card, expanding the available options for users.
- Enhanced the overall plugin preview experience by integrating these new templates, providing users with more visually appealing and functional examples.

This update significantly improves the plugin sorting mechanism and enriches the template offerings, enhancing user engagement and experience.
2026-05-13 21:02:05 +08:00
pftom
8b2d48a258 feat(daemon, web): enhance plugin preview handling and add new templates
- Introduced logic to assemble example slides with a companion template when the declared entry is missing, improving the user experience for plugin previews.
- Updated the server logic to handle special cases for `example-slides.html`, ensuring proper fallback to `template.html` when applicable.
- Enhanced tests to verify the new preview assembly functionality and ensure correct rendering of fallback content.
- Added new HTML and Markdown examples for various skills, including a magazine article layout and a Twitter share card, expanding the available templates for users.

This update significantly improves the plugin preview experience, providing users with more robust and visually appealing fallback options.
2026-05-13 20:58:24 +08:00
pftom
9e196d34af feat(daemon, web): enhance plugin sharing workflows and UI components
- Updated the plugin sharing prompts to utilize local daemon endpoints for publishing to GitHub and contributing to Open Design, streamlining the user experience.
- Refactored the `PluginsView` and `PluginShareMenu` components to support new sharing functionalities, including confirmation modals and improved link handling.
- Enhanced the CSS styles for the plugin share confirmation modal and related UI elements for better visual consistency.
- Added tests to verify the functionality of the new sharing workflows and ensure proper integration within the existing plugin management system.

This update significantly improves the plugin sharing experience, making it easier for users to publish and contribute their plugins effectively.
2026-05-13 14:35:09 +08:00
pftom
c36609c47d feat(daemon, web): implement plugin sharing project creation and enhance CLI functionality
- Added new flags for conversation, message, agent, and model in the CLI to support enhanced plugin sharing features.
- Introduced a new API endpoint for creating share projects for plugins, allowing users to publish to GitHub or contribute to Open Design.
- Updated the UI components to facilitate the new sharing functionalities, including prompts for user input during the sharing process.
- Enhanced the project management system to handle new plugin share actions, improving user interaction and experience.
- Added tests to ensure the reliability of the new sharing features and their integration within the existing plugin management system.

This update significantly enhances the plugin ecosystem by enabling users to share their creations more effectively and streamline collaboration.
2026-05-13 07:01:12 +08:00
pftom
13d5598b0c feat(web, daemon): enhance plugin import functionality and UI components
- Added support for uploading plugins via zip files and folders, improving the plugin import process.
- Introduced a new `PluginImportModal` for a streamlined user experience when importing plugins.
- Updated the `PluginsView` to include disabled states for unfinished plugin areas, enhancing clarity for users.
- Refactored various components to utilize the new `resolvePluginQueryFallback` function for improved localization handling.
- Enhanced CSS styles for better visual feedback and responsiveness in the plugin import interface.

This update significantly improves the plugin management experience, making it easier for users to import and manage plugins effectively.
2026-05-12 20:46:17 +08:00
pftom
443aea72c5 feat(daemon, web): enhance plugin handling and UI integration
- Introduced a new plugin upload mechanism with file size limits and memory storage, allowing users to upload plugins directly.
- Implemented fallback logic for plugin application, ensuring projects can be created without explicit plugin requests.
- Enhanced the UI to support plugin selection and integration, including a new `PluginsView` component for managing plugins.
- Updated various components to utilize localized text for plugin queries, improving user experience across different languages.
- Added tests for new plugin functionalities and local skill loading, ensuring reliability and correctness.

This update significantly improves the plugin management experience, providing users with better tools for plugin integration and interaction.
2026-05-12 20:42:40 +08:00
pftom
c12c816a44 feat(design-systems): add new design systems for Agentic, Airtable, Ant, Apple, Application, Arc, and Artistic
- Introduced comprehensive design documentation and JSON configurations for multiple design systems, including Agentic, Airtable, Ant, Apple, Application, Arc, and Artistic.
- Each design system includes detailed guidelines on visual themes, color palettes, typography, spacing, layout, components, and interaction principles.
- Enhanced the overall design framework to support diverse user interfaces and improve consistency across applications.

This update significantly enriches the design resources available for developers, enabling them to create visually cohesive and user-friendly applications.
2026-05-12 15:18:16 +08:00
pftom
5af84c09af feat(web): refactor PluginsHomeSection to use tag-based filtering and introduce PluginCard component
- Replaced the legacy tabbed categorization in `PluginsHomeSection` with a tag-driven approach, allowing dynamic filtering based on plugin tags.
- Introduced a new `PluginCard` component to encapsulate the rendering of individual plugin cards, improving separation of concerns and maintainability.
- Added a `usePluginCategories` hook to manage plugin visibility and filtering logic, enhancing the overall structure and testability of the component.
- Implemented a "More" pill for overflow tags in the filter row, improving user interaction with a cleaner UI.
- Updated CSS styles to support the new layout and improve visual consistency across the plugins home section.

This update significantly enhances the user experience by providing a more flexible and intuitive way to discover and interact with plugins.
2026-05-12 13:25:44 +08:00