Commit Graph
230 Commits
Author SHA1 Message Date
pftom 886f925cdf Merge remote-tracking branch 'origin/main' into iodized-nephew 2026-06-22 23:54:04 +08:00
d3ebed564c [codex] Update Open Design X account links (#4611)
* fix: update Open Design X account links

* test(web): assert settings X link target

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-22 09:04:49 +00:00
d19c53d274 Agent-driven brand extraction + two-loop memory overhaul (#4260)
* 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(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>

* 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).

* 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

* fix(brands): non-blocking extraction start + lifecycle-accurate status (#4470)

Acceptance fixes for the Brand Kit surface (PR #4260, even-ferry),
addressing five reported issues:

- Perf: `startBrandExtraction` no longer blocks the POST /api/brands
  response on the synchronous programmatic harvest+finalize. It now waits
  only a short budget (~1.2s) so fast origins still land on a ready,
  applyable design system (the instant "aha"), while slow/blocked origins
  return immediately on the "Extracting…" skeleton and finalize in the
  background. Measured: example.com POST dropped from a ~19s block to
  ~1.2s, then finalized to `ready` in the background.

- Brand Kit stays stuck on "Extracting…" after a manual stop: the backing
  run's canceled/failed status now reconciles the brand to `failed` with a
  reason (this extends the existing reconcile; adds a regression spec).

- Brand Kit ignores a backing run that is awaiting user input
  (anti-bot wall / question form): new reversible `needs_input` brand
  status, derived on read (never persisted) so it flips back once the user
  answers. Surfaced as a "Needs input" badge + hint in the card and a
  distinct status dot in the list; the list keeps polling while paused.

- Home → Recent projects showed brand-extraction projects as
  "Not started": /api/projects now falls back to the brand lifecycle for
  brand projects whose run-derived status is `not_started`
  (extracting→running, needs_input→awaiting_input, ready→succeeded,
  failed→failed), so a live extraction is never shown as not started.

- "Use in new chat" produced no visible result: it now carries a
  confirmation notice through the Home intent channel so Home shows a
  "Using <brand>" toast, making the navigate+apply verifiable (the
  composer already preselects the brand's design system).

Tests: daemon brand-routes (canceled→failed, needs_input transient) and
brand-extraction-engine (fast return + background finalize) specs; web
BrandPreviewCard specs (needs_input badge/hint, Use-in-new-chat notice).
#4 validated end-to-end against a real daemon. guard + typecheck green.

* [codex] Fix brand extraction incomplete states (#4486)

* fix brand extraction incomplete states

* fix web memory tests for advanced modal

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

* fix onboarding P0 brand-step navigation

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

* fix daemon brand extraction test timeout

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

* fix brand extraction fallback prompt state

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>

* [codex] Fix brand extraction terminal status reconciliation (#4532)

* Fix brand extraction terminal status reconciliation

* Keep prefetched brand pages previewable

* fix(brands): preserve ready extraction status

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

* fix(brands): persist terminal extraction signal

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

* fix(brands): clear stale terminal retry markers

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>

* Fix brand kit modal intent handling (#4528)

Co-authored-by: Siri-Ray <2667192167@qq.com>

* fix(web): let design system contents scroll in narrow review layout (#4526)

Co-authored-by: Siri-Ray <2667192167@qq.com>

* [codex] Fix Brand Kit preview lifecycle guards (#4527)

* Fix brand kit preview lifecycle guards

* fix(brands): keep detail selected on delete failure

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

* fix(brands): handle delete HTTP failures

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>

* ci: retrigger pull_request checks

* test(e2e): stabilize entry settings shard

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: PerishCode <perishcode@gmail.com>
Co-authored-by: lefarcen <935902669@qq.com>
Co-authored-by: PerishFire <39043006+PerishCode@users.noreply.github.com>
Co-authored-by: Siri-Ray <2667192167@qq.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-22 08:34:05 +00:00
6cf48c29b5 ci: reduce Blacksmith usage and stabilize PR checks (#4603)
* ci: move lightweight workspace checks to hosted runners

* ci: split UI P0 project runtime shard

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

* Stabilize UI P0 project runtime tests

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-22 04:51:04 +00:00
d3896fa51a [codex] Clean deprecated launcher payloads on updater startup (#4524)
* fix(packaged): recover stale launcher and sidecar state

* fix(packaged): write launcher cleanup from installer sync

* perf(tools-pack): reuse windows payload caches

* perf(tools-pack): avoid slow windows 7z filters

* fix(tools-pack): bound windows payload archive hangs

* test(packaged): stabilize sidecar tests on windows

* fix(tools-pack): harden launcher runtime sync helper

* fix(tools-pack): invalidate nsis cache for installer helpers

* fix(tools-pack): hash nsis helper source in bundled cli

* fix(packaged): restart when existing desktop has stale sidecars

* chore(release): bump beta base to 0.11.1

* fix(e2e): seed windows smoke onboarding in runtime data

* ci(release): let beta runs use default queueing

* ci(release): restore beta concurrency guard

* ci(release): enable beta mac x64 by default

* ci(release): disable beta mac x64 by default

* fix(updater): clean deprecated launcher payloads on startup

* fix(e2e): align stable dry-run fixture version

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

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-22 04:21:30 +00:00
Marc ChanandGitHub d5d9a761ca refactor(daemon): organize source modules (#4454)
* docs(daemon): add agent guidance

* refactor(daemon): organize source modules

* chore(guard): update daemon design system import

* refactor(daemon): shorten domain module filenames

* fix(daemon): correct pitch-deck manifest path after test move

The pitch-deck manifest test moved one directory deeper into
tests/design-systems/ but kept the old '../../..' repoRoot, resolving
to apps/ instead of the repo root and failing to find
plugins/_official/examples/html-ppt-pitch-deck/open-design.json.

* fix(daemon): retarget media model verifier

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

* docs(daemon): refresh AGENTS legacy paths after module reorg

* test(e2e): allow manual edit P0 CI scaling

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

* test(daemon): fix frontmatter import path

Generated-By: looper 0.9.10 (runner=fixer, agent=opencode)

* fix(web): avoid replaying legacy terminal runs

Generated-By: looper 0.9.10 (runner=fixer, agent=opencode)

* fix(web): preserve legacy terminal replay recovery

Generated-By: looper 0.9.10 (runner=fixer, agent=opencode)

* fix(daemon): correct live-artifacts test data root

* fix(daemon): cover moved route registrars in context contract

Generated-By: looper 0.9.10 (runner=fixer, agent=opencode)

* fix(daemon): restore moved runtime artifact imports

Generated-By: looper 0.9.10 (runner=fixer, agent=opencode)
2026-06-20 16:08:20 +00:00
5190db7f00 feat(web): redesign onboarding connect step as a cloud sign-in landing (#4513)
* feat(web): redesign onboarding connect step as a cloud sign-in landing

Reworks the onboarding first screen into a centered cloud sign-in
landing: brand glyph, headline, one primary cloud sign-in button, and
two secondary links (local CLI / your own key) that each open a
dedicated setup page. Removes the AMR card + three-way runtime picker.

Also:
- Drop the three-step stepper across onboarding; Back link moved
  top-left on every sub-page.
- Top-right language (compact, opens down-left) + theme (one-click
  light/dark) controls; theme applies synchronously to avoid lag.
- About-you fields become flat tappable chips instead of dropdowns.
- Replace Marketing role with Marketing agency (pinned first).
- Cloud button is state-aware: shows Continue (signed in) when already
  signed in and advances directly; shows a brief loading state while the
  login status resolves (fetched in parallel on mount).
- Fix onboarding container height (100vh -> 100%) so the footer is not
  clipped below the tab bar.

Adds onboardingCloud{Title,Body,SignIn,Continue,Alternative,Or,Rights}
i18n keys; renames onboardingRoleMarketing -> onboardingRoleAgency
across all locales.

* fix(web): attribute already-signed-in Continue into the AMR funnel

The redesigned onboarding cloud landing shows a Continue (signed in)
button when the user is already signed in, which advanced to the next
step via setStep without recording any AMR entry attribution. Only the
sign-in flow (handleCloudSignIn) recorded onboarding_amr_card /
onboarding_amr_sign_in_continue, so already-signed-in users who clicked
Continue were invisible to the AMR attribution funnel — systematically
under-counting that conversion path.

Record the same card + sign_in_continue entries before advancing so the
two cohorts (fresh sign-in vs. already signed in) are attributed
consistently. Runtime/mode/agent are already set to amr by the existing
amrAgent effect, so this is attribution-only with no behavior change.

* fix(web): pin amr runtime on already-signed-in Continue so it records

The already-signed-in Continue branch advanced without setting runtime,
relying on the amrAgent effect to backfill runtime='amr'. If amrAgent
hadn't resolved yet at click time, the onboarding_complete_result event
could record runtime_type='none' instead of 'amr_cloud'. Set runtime/
mode/agent explicitly here (as handleCloudSignIn already does) so the
completion event records the cloud runtime regardless of effect timing.

* test(web): update onboarding tests for the cloud sign-in landing

The connect-step redesign replaced the AMR runtime card + runtime picker
with a centered cloud sign-in landing, so the onboarding suites still
asserted removed UI (the /Open Design AMR/ card, AMR version text, the
'Sign in to continue' CTA, dropdown About-you fields).

Remap to the new UI while preserving coverage:
- AMR auth flows (pending/polling/cancel/error/timeout/recovery) now
  trigger via the landing 'Sign in to Open Design Cloud' button; assert
  'Signing in…', the Cancel sign-in button, and role=alert errors.
- 'Continue (signed in)' advances past the signed-in connect step.
- Gate-tooltip coverage retargeted to the still-existing BYOK-unverified
  and Local-no-agent gates on the bottom Continue CTA.
- About-you picks go through chip buttons (chooseChipOption) instead of
  dropdowns; analytics-payload assertions unchanged.
- The two AMR-card skeleton tests now assert the surviving behavior: the
  landing stays usable during agent detection with no card/skeleton.

apps/web suite: 334 files / 3333 tests green.

* test(e2e): capture the new cloud sign-in landing in the visual entry suite

The visual-entry suite waited on the removed runtime-selection surface
(the 'Choose a runtime' heading and the .onboarding-view__amr-cloud-card
model picker), so its precondition assertions failed before the
screenshot — element(s) not found. Retarget the capture to the new
Open Design Cloud sign-in landing (cloud CTA + secondary runtime links).
captureVisual only writes an artifact (no baseline diff), so no baseline
regeneration is needed.

* test(e2e): update amr-onboarding UI test for the cloud sign-in landing

The redesign replaced the AMR runtime card + runtime picker with the
Open Design Cloud sign-in landing, so the shared gotoOnboarding helper
(waiting on the removed 'Choose a runtime' heading) failed all tests.

Remap to the new UI while preserving coverage: AMR sign-in/poll/cancel/
recovery now drive the landing cloud button; About-you picks go through
chips; gates assert against the BYOK/Local panel headers. The three
tests that exercised the removed per-runtime model picker on the connect
card are narrowed to the surviving coverage (signed-in AMR completes
setup / carries agentId 'amr' into the first run). 23 tests green
locally via the Playwright harness.

* test(e2e): update packaged onboarding smoke (mac/win) for the cloud landing

The packaged @electron-smoke onboarding specs probed the removed
runtime-card DOM (.onboarding-view__amr-cloud-card / __alternatives /
__model-picker, aria-pressed selection). Retarget the eval snapshot,
type, validator, and click expression to the new cloud sign-in landing:
the primary cloud CTA (.onboarding-cloud__primary) plus the two
secondary runtime links (.onboarding-cloud__secondary), and add a Back
(.onboarding-view__back-to-cloud) step so the smoke can expand BYOK then
Local without the (landing-only) links. Verified via e2e typecheck;
these env-gated packaged-Electron smokes run in the release pipeline.

* fix(web): close the Search tabs popover when onboarding becomes active

The onboarding redesign hid the Search-tabs trigger button while
onboardingActive is true, but the popover portal below rendered
unconditionally on tabsMenuOpen. A popover left open across a route flip
to /onboarding (e.g. browser back/forward, which bypasses activateTab/
createNewTab) survived as a stray 'Search tabs' dialog floating over the
first-run flow with no visible control to dismiss it.

Close the menu in an effect when onboarding activates, and gate the
portal on !onboardingActive so it cannot render even for the frame
before the effect runs. Adds a red-spec regression test (opens the
popover, rerenders to the onboarding route, expects the dialog gone).

Addresses reviewer feedback on PR #4513.

---------

Co-authored-by: elihahhahahah11 <294718562+elihahhahahah11@users.noreply.github.com>
2026-06-20 04:25:29 +00:00
PerishFireandGitHub 358a426b2b ci: rename atom workflows (#4522) 2026-06-19 03:22:43 +00:00
lefarcenandGitHub e79934b12a test(e2e): de-flake manual-edit bridge element selection (#4512)
The P0 'manual edit' UI tests intermittently time out at 30s on
`frame.locator(selector).click()` inside selectPreviewElementThroughBridge
(seen dequeuing #4497 and #4501 from the merge queue, on unrelated
landing-only / docs-only changes).

Root cause is a click-vs-resettle race, not a product bug: entering manual-edit
mode re-injects the edit bridge and re-emits its targets a tick later
(`setTimeout(postTargets, 0)` in edit-mode/bridge.ts) while the preview iframe
is still settling, so the first click is occasionally swallowed and then hangs
on Playwright's post-click stability check until the test timeout.

Wrap the click + selection assertion in expect(...).toPass() with a short
per-attempt timeout, so a single dropped click is retried through the settle
window instead of failing the run. Final assertions are unchanged.

Flaky by nature, so no deterministic red spec; verified e2e typecheck and
that the wrapped assertions match the original. CI 'UI P0 (project-runtime)'
exercises the live path.
2026-06-19 03:21:48 +00:00
c1701f709a [codex] codify workflow handoff capabilities (#4503)
* codify workflow handoff capabilities

* Harden workflow marker jq lookups

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

* harden autofix head validation

* Preserve Nix hash fallback guidance

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

* Gate Nix hash fallback comments

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

* Clear stale Nix fallback comments after autofix

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

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-18 08:37:18 +00:00
PerishFireandGitHub c782aeb3bb ci: stop duplicate post-merge validation (#4469) 2026-06-17 10:04:03 +00:00
PerishFireandGitHub b49c9b7932 Refine CI hot and full validation modes (#4466) 2026-06-17 09:32:29 +00:00
AmyandGitHub 73d07d8dfb test(e2e): stabilize AMR onboarding assertions (#4462) 2026-06-17 09:08:09 +00:00
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
PerishFireandGitHub 15d3759834 [codex] Optimize CI topology and Playwright suites (#4460)
* Consolidate PR validation into ci

* Tune absorbed CI runner tiers

* Fold visual validation into CI Playwright shards

* Run PR shards during manual CI dispatch

* Optimize CI topology and scopes

* Increase UI P0 Playwright workers

* Relax visual Playwright timeout
2026-06-17 08:24:52 +00:00
CaprikaandGitHub fdb1638183 [codex] Refresh local CLI auth state after API key switches (#4453)
* Refresh Codex auth status after CLI changes

* Probe Claude Code auth status

* Stabilize project route during agent refresh

* Respect API key auth during CLI probes
2026-06-17 16:05:58 +08:00
AmyandGitHub 8ff19c6b41 [codex] Add main-risk smoke and E2E coverage (#4322)
* test(e2e): cover daemon reload artifact recovery

* test(e2e): expand critical flow coverage

* test(daemon): add startup and recovery smoke coverage

* test(e2e): add visual and desktop chrome smoke coverage

* ci: gate packaged onboarding smoke to nightly

* fix(web): repair artifact replay type narrowing

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

* fix(ci): repair preflight smoke coverage checks

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

* fix(web): tighten artifact recovery polling

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

* fix(web): keep error recovery retries alive

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

* fix(e2e): relax brittle UI P0 assertions

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

* fix(web): recover pointer artifact outputs

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

* fix(e2e): stabilize manual edit reload smoke

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

* fix(e2e): avoid noisy win onboarding cleanup

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

* fix(web): stop failed artifact recovery polling

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

* fix(daemon): isolate startup smoke data root

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

* fix(web): recover standalone html artifacts

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

* fix(web): guard pointer artifact recovery by run time

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

* fix(ci): narrow strict visual gate to critical smoke

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

* fix(ci): limit PR visual capture to critical cases

* fix(ci): keep PR visual capture complete

* fix(web): keep reload artifact recovery retryable

* fix(ci): clarify PR visual gate layering

* fix(e2e): stabilize visual home P2 capture

* fix(e2e): align visual gallery detail clicks

* fix(e2e): preserve packaged install during onboarding cleanup

* fix(ci): shard PR visual capture

* fix(ci): remove duplicate nix validation from ci

* fix(ci): keep visual capture screenshots flat

* fix(ci): point nix hash autofix at ci-nix

* fix(ci): stabilize PR P0 recovery gate

* fix(web): ignore stale artifact pointers during recovery

* fix(web): reset BYOK model after clearing key

* ci: run critical UI P0 subset on PRs

* ci: combine PR UI P0 critical shards

* ci: combine PR visual capture shards

* ci: preserve visual capture shard manifests

* fix(web): clear ProjectView delayed timers on unmount

* test(e2e): harden onboarding connect gate coverage

* test(e2e): align AMR auth recovery and visual catalog timeout
2026-06-17 16:01:53 +08:00
lefarcenandGitHub e1b8d9921e Merge pull request #4421 from nexu-io/release/v0.11.0
release: Open Design 0.11.0 — The Bazaar
2026-06-17 15:27:29 +08:00
d0d1df8e60 fix(web): portal New Project design-system dropdown so it isn't clipped (#4346)
* test(e2e): red-spec reproducing #4303 design-system dropdown clipping

The New Project design-system popover (local DesignSystemPicker in
NewProjectPanel.tsx) opens with plain position:absolute and is clipped
by its .newproj-body { overflow-y: auto } ancestor, so lower options are
truncated. This P1 UI spec opens the picker on a short window and asserts
the popover does not spill past the .newproj-body / viewport bottom.

https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6

* fix(web): portal New Project design-system dropdown so it isn't clipped (#4303)

The New Project modal's design-system picker opened its popover with plain
position:absolute, anchored inside .ds-picker. Its clipping ancestor is
.newproj-body { overflow-y: auto } (the modal scroll container), so when the
trigger sat low in the body or the window was short, the popover was truncated
and the sections below bled through — the reported misaligned/truncated UI.
This is platform-independent (shared web CSS rendered by the same Chromium in
macOS and Windows desktop), not a macOS-only regression.

Mirror the shared DesignSystemPicker: render the open popover through a portal
to document.body, positioned from the trigger's viewport rect with
viewport-aware up/down placement and a clamped max-height, so it escapes the
clip box. A scoped .ds-picker-popover-portal variant flips the popover to
position:fixed (z-index above the modal backdrop) and lets the list flex and
scroll inside the bounded height. The sibling PlatformPicker shares the same
absolute-popover pattern and is left for a follow-up.

https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6

* fix(web): clamp design-system popover height to available viewport space

Review follow-up (#4346, thanks @mrcfps): the anchor used
Math.max(200, Math.min(440, space)), so when both sides of the trigger were
under the 200px preferred minimum (a very short window) the fixed popover was
still sized to 200px and overflowed the viewport instead of staying scrollable.

Size the popover to the chosen side's actual available space, honoring the
200px preferred minimum only when the side can fit it. The list already flexes
and scrolls inside the bounded height, so a smaller box just scrolls rather than
spilling past the viewport edge.

Extend e2e/ui/new-project-ds-picker-clipping.test.ts with a tight-viewport case
(1280x360) that asserts both sides fall under 200px and the popover stays within
the viewport.

https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-17 14:32:28 +08:00
lefarcenandGitHub 1e2f47fb8d fix(amr): surface vela login URL/code so sign-in survives a failed browser handoff (#4402)
* fix(amr): surface vela login URL/code so sign-in survives a failed browser handoff

AMR (vela) sign-in is a device-authorization flow: `vela login` prints the
activation URL + user code to stdout, then best-effort opens the browser and
keeps polling until the server-issued expiry (>5min). The daemon spawned it
headless, only read the first 250ms of output, and the UI showed nothing but a
"Signing in…" spinner — so when the browser failed to open (stripped PATH in a
packaged build, blocked network) the user had no URL to fall back to and stared
at a dead spinner for the full AMR_LOGIN_TIMEOUT_MS (5 minutes).

- daemon: parseVelaLoginActivation + lifetime stdout/stderr capture surface
  activationUrl / userCode / browserOpenFailed on VelaLoginStatus.
- web: the AMR account pill's signing-in state now shows an activation block
  (open sign-in page + copy code) as soon as the URL is known, instead of only
  a spinner; it adapts to the active theme.
- web: an AMR run that fails with AMR_AUTH_REQUIRED now offers inline sign-in in
  the chat error card (the login pill) and auto-retries once on success, rather
  than bouncing the user out to Settings.

Tests: red->green parser spec (validated against real vela login output),
AmrAccountControl activation-block specs, ChatPane inline-auth specs.

* test(amr): real-vela E2E for the login activation capture seam

Spawns an actual `vela login` child through the daemon's spawnVelaLogin and
asserts readVelaLoginStatus surfaces the real activation URL + code while the
login is in flight, then cancels (never approves, so no config is written and
any existing session is untouched). Covers the daemon capture wiring
(beginLoginActivationCapture -> readVelaLoginStatus) that the pure parser spec
can't reach. Auto-skips where the vela CLI isn't installed, so CI is unaffected.

* fix(amr): polish inline auth retry layout

* fix(daemon): try AMR login direct first, fall back to IPv4 proxy

loopback AMR API proxy (forced IPv4) to dodge broken `amr-api.open-design.ai`
edge paths for some hosts (#3726). But behind a corporate transparent proxy
that hijacks `amr-api.open-design.ai` onto an internal gateway (e.g.
飞连/CorpLink → 30.x), the extra proxy hop makes the upstream lose the client
IP and reject device authorization with
`502: Invalid IP address: undefined` — even though the direct path resolves
fine. Result: AMR "Authorize" fails in every packaged build that ships this
change (beta/main), while release builds without it still work.

Only `vela login` was rerouted; the model catalog and chat inference already
go direct (to amr-link / VELA_LINK_URL), so this restores login to the same
direct-first default. The IPv4 proxy is kept strictly as a fallback: the
route now starts login over a direct connection and only retries through the
proxy when the direct attempt fails to start — never when a login is already
in flight. Both cohorts win: transparent-proxy users succeed directly,
broken-edge users (#3726) still get the proxy.

Tests: fake-vela gains FAKE_VELA_LOGIN_FAIL_WITHOUT_API_URL to model a broken
direct path; the login suite now asserts direct-first (no VELA_API_URL on a
healthy path) and proxy-fallback (VELA_API_URL set only after a direct
failure, incl. OD_PUBLIC_BASE_URL derivation).

* fix(amr): clear stale login activation details

* fix(amr): refresh login status immediately after auth starts

* fix(amr): sync inline auth card with login status

* fix(amr): tighten inline auth retry state

* fix(amr): wait for direct login activation before fallback

* fix(amr): show activation details only in chat auth card

* fix(amr): guard clipboard copy explicitly in the activation block

navigator.clipboard?.writeText(...).then(...) already short-circuits the whole
chain when the clipboard API is absent, but make the guard explicit so the copy
handler reads as a clean no-op rather than relying on optional-chain reach.

* fix(amr): don't kill a slow-but-healthy direct login; only fall back on real failure

The login activation watchdog turned a merely slow direct CreateDeviceAuthorization
into a hard failure: after the grace it killed the direct child and let the route
retry through the IPv4 proxy — the exact proxy hop that 502s on the transparent-proxy
networks this fix targets. Now the grace only stops blocking the request; a still-
running direct attempt is left alive (the UI polls /status), and the proxy fallback
fires only on an explicit pre-activation exit/error. The grace is overridable via
OD_AMR_LOGIN_ACTIVATION_GRACE_MS so the new route test can exercise the slow-direct
path quickly (fake-vela gains FAKE_VELA_LOGIN_ACTIVATION_DELAY_MS).

Addresses review feedback on #4402.

* test(e2e): AMR auth failure now signs in inline, not via Settings

The chat AMR_AUTH_REQUIRED card replaced its 'open Settings to authorize' bounce
with an inline sign-in pill (POSTs vela login in place, auto-retries on success).
Update the [P0] runtime-recovery spec to assert the inline flow: clicking
Authorize & retry issues the login request and opens no Settings dialog. The
non-AMR 'Switch to AMR' recommendation flow (AmrGuidance) is unchanged.

* fix(amr): only auto-retry inline auth on a real sign-in transition

The inline AMR auth card auto-retried the failed run whenever /status reported
signed-in — via both the 500ms shared-status poll and the pill's onStatusChange.
Because the per-assistant-id guard resets on each retry (new run = new id), a run
that keeps failing AMR_AUTH_REQUIRED while /status reads signed-in retried
forever (caught by the runtime-recovery UI P0 spec). Now we retry only on an
explicit signed-out -> signed-in transition; a null/unknown status never
fabricates one, and once signed-in we don't retry again until an explicit
signed-out is seen.

- Unit specs updated to drive the transition (and a loop-guard spec for the
  already-signed-in case).
- e2e: the AMR auth spec asserts the inline sign-in flow (no Settings bounce);
  the switch-to-Codex spec mocks /status signed-out, the realistic state for an
  AMR_AUTH_REQUIRED failure, so the Authorize & retry action is offered.

* fix(amr): fall back to the proxy on a post-grace direct login failure

The direct-first login route only fell back to the IPv4 proxy when the direct
child crashed inside the 250ms startup grace. A direct vela login that survives
the grace and then errors out before printing its activation URL (the common
broken-edge shape, #3726) returned 202 and stranded the user on a dead direct
login. Re-introduce waitForActivation: the route now blocks until the direct
attempt reaches device-auth steady state (prints its activation URL) or
exits/errors before it; only a pre-activation exit/error triggers the proxy
retry, and a slow-but-healthy direct login is left running (never killed).

fake-vela now prints the activation block (so the daemon can detect steady
state) and gains FAKE_VELA_LOGIN_FAIL_WITHOUT_API_URL_DELAY_MS; the route suite
gains a regression where the direct attempt fails past LOGIN_STARTUP_GRACE_MS
and must still reach the proxy. Addresses review feedback on #4402.
2026-06-17 14:29:15 +08:00
PerishFireandGitHub 4b9a15734d [codex] Consolidate PR validation into CI (#4451)
* Consolidate PR validation into ci

* Tune absorbed CI runner tiers

* Fold visual validation into CI Playwright shards

* Run PR shards during manual CI dispatch
2026-06-17 14:21:04 +08:00
PerishFireandGitHub 891981d460 [codex] Optimize CI runtime topology (#4450)
* Optimize e2e tools-dev runtime parallelism

* Remove visual networkidle wait

* Optimize e2e vitest parallelism

* Optimize Nix flake caching

* Test CI on Blacksmith runners

* Allow parallel manual CI runs

* Tier CI runner sizes

* Temporarily narrow CI debug scope

* Instrument watcher CI timeouts

* Instrument watcher event diagnostics

* Avoid default polling in watcher tests

* Skip runtime trace during watcher debug

* Probe ARM runner tiers for CI

* Focus CI runner probe on x64 browser

* Probe browser workers by runner size

* Probe Playwright file parallelism

* Probe Playwright worker scaling on 8v

* Reshape CI topology

* Fix split E2E Vitest CI lane

* Simplify daemon CI topology

* Optimize Windows payload CI setup

* Revert "Optimize Windows payload CI setup"

This reverts commit 5cbc48c0af.

* Cache better-sqlite3 Nix binding separately

* Revert "Cache better-sqlite3 Nix binding separately"

This reverts commit 0384e3787e.

* Remove unused Nix cache setup from CI

* Use Blacksmith ARM for lightweight CI jobs
2026-06-17 12:53:06 +08:00
lefarcenandGitHub 67ade60bce fix(e2e): seed win smoke onboarding into the live daemon data dir (#4444)
The packaged Windows smoke's onboarding seed derived its target path from
the installed app's baked config, which falls back to AppData and never
matches the data dir the running daemon actually reads. `tools-pack win
start` rewrites `namespaceBaseRoot` to the tools-pack runtime root and hands
it to the runtime via OD_PACKAGED_CONFIG_PATH, so the live daemon's
RUNTIME_DATA_DIR is always under `runtimeNamespaceRoot`. The seed landed in
the AppData fallback instead, so the daemon never read `onboardingCompleted`.

This stayed invisible until #4389 removed the step-0 "Skip" affordance from
the now-required Connect onboarding step: `ensureMainAppShell` used to click
Skip to reach home, so an ineffective seed didn't matter. With Skip gone and
the seed missing its target, the app sat on onboarding and the smoke failed
with "packaged windows runtime did not reach main app shell".

Write the seed to `<runtimeNamespaceRoot>/data/app-config.json` — the exact
dir the running daemon reads (already asserted for logs at line ~400) and the
same approach the macOS smoke uses. Drop the now-dead manifest-derivation
helper chain.
2026-06-17 12:12:56 +08:00
lefarcen 39cad2b8a5 chore(release): bump version to 0.11.0 for release/v0.11.0 2026-06-17 11:05:56 +08:00
lefarcenandGitHub 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
lefarcenandGitHub a4abae3804 fix(release): build the daily beta from main, not the latest release branch (#4393)
* fix(release): build the daily beta from main, not the latest release branch

notify-daily-feishu picked the highest-semver release/vX.Y.Z branch and
built beta off it. Once that branch ships stable, its base version equals
the latest stable, so release-beta's strictly-greater-than-stable guard
rejects every scheduled run until someone hand-bumps the retired branch —
which is exactly how the daily beta + Feishu card silently stalled for
days after 0.10.1 shipped.

Beta is the daily R&D channel, so track the development tip (main), which
always leads stable. Keep the workflow_dispatch `ref` input for one-off
builds from a specific branch.

* test(release): scope daily-beta resolve check and assert ref override

Strengthen the regression test per review: scope the assertions to the
resolve job and prove both control-flow branches — the empty-input
default writes ref=main, and the workflow_dispatch override still
forwards ${{ inputs.ref }} verbatim — so a refactor can't keep the test
green while breaking the preserved override path.
2026-06-16 13:00:24 +00:00
pftom 0bd8cb13b1 Merge remote-tracking branch 'origin/main' into iodized-nephew 2026-06-16 20:28:25 +08:00
pftom 0284577472 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.
2026-06-16 17:56:02 +08:00
f81439bdae feat(onboarding): gate Connect step, sequential stepper, restyle progress bar (#4389)
* feat(onboarding): gate Connect step, sequential stepper, restyle progress bar

- Remove "Skip for now" — Connect is now a required step, not skippable.
- Gate Continue until the selected runtime is usable: AMR signed in, an
  available local CLI selected, or a BYOK connection test that passed.
- Make the stepper a strictly-sequential wizard: only already-reached steps
  are clickable, no forward jumps. Keys off a maxStepReached counter instead
  of the async AMR login probe, so the indicator no longer flickers
  disabled->enabled while that status resolves.
- Disable the "+" new-tab affordance (button + Cmd/Ctrl+T) while on the
  onboarding route, so opening a tab can't bypass the Connect gate.
- Restyle the stepper as a thin segmented progress bar with centered labels;
  drop the oversized "Welcome" hero title.
- Deprecate the now-unreachable onboarding `skip` / `skipped` analytics enums
  (kept for historical data; no longer emitted).

* test(onboarding): update specs for the new Connect gate behavior

CI flagged onboarding tests still asserting the removed/changed UI.

Vitest (apps/web):
- e2e helper: wait for Continue to be enabled before clicking — AMR detection
  lags, so the Connect gate keeps it disabled until vela/status confirms
  signed-in; clicking a disabled button was a no-op and stalled at step 0.
- "switches runtime" test: assert Continue is now disabled after switching to
  a not-yet-ready Local runtime (gate behavior).
- about_you_submit-once test: advance via Continue instead of a stepper
  forward-jump, which is no longer allowed.
- replace the Skip-exits test with one asserting the Connect step has no Skip
  affordance and emits no skip/skipped telemetry.

Playwright (e2e/ui):
- gotoOnboarding: key off the "Choose a runtime" heading instead of the
  removed "Welcome" hero title.
- replace the skip-exits P0 with a no-Skip-affordance assertion.
- visual-home: same Welcome -> Choose a runtime marker update.

---------

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-16 09:55:57 +00:00
pftom 2a150e0286 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.
2026-06-16 17:37:59 +08:00
lefarcenandGitHub 30b8eac48c chore(release): bump version to 0.10.2 on main (#4387)
main read 0.10.1 (== latest stable 0.10.1), so the daily beta build's
strictly-greater-than-stable version guard refused to produce a beta
from main. Advance the 0.10.x dev line to 0.10.2 across the same 16
lockstep workspace package.json that #4381 bumped, and align the
packaged-smoke stable dry-run fixture to 0.10.2.

This continues the existing beta line on R2 (0.10.2-beta.4) so a build
from main produces 0.10.2-beta.5.
2026-06-16 06:08:40 +00:00
lefarcenandGitHub 66d9cf9fb6 fix(release): accept releaseVersion/releaseNumber in beta metadata reader (#4383)
The daily beta build (notify-daily-feishu) reads beta/latest/metadata.json
via scripts/release-beta.ts, which only understood the legacy
betaVersion/betaNumber fields. The unified release publisher and the
in-flight tools-release rewrite stamp the feed with generic
releaseVersion/releaseNumber instead, so once a build from that tooling
wrote the feed the daily reader died with 'must include betaVersion or
baseVersion+betaNumber' and the scheduled beta + Feishu card stopped.

Accept either field spelling so the reader survives whichever publisher
last wrote the feed.
2026-06-16 05:29:52 +00:00
lefarcenandGitHub a3a5f02d87 chore(release): bump version to 0.10.1 on main (#4381)
Back-fill the 0.10.1 version bump that shipped via the release/v0.10.1
branch (tag open-design-v0.10.1, already published) but never merged
back to main. The feature/perf content of that release already landed
on main via #4198, #4203 and #4202; only the version-number bump and
the packaged-smoke stable fixture were left behind, so main still read
0.10.0.

This applies the release-specific deltas onto current main:
- bump version 0.10.0 -> 0.10.1 across the 16 workspace package.json
  in the 0.10.x release set (apps/daemon, apps/desktop, apps/landing-page,
  apps/packaged, apps/web, e2e, root, packages/contracts, packages/download,
  packages/host, packages/launcher-proto, packages/platform,
  packages/sidecar-proto, packages/sidecar, tools/dev, tools/pack)
- align e2e packaged-smoke stable fixture to 0.10.1

launcher-proto was added to main after the 0.10.1 release branch was cut,
so it was not in the original release commit; it is part of the lockstep
0.10.x release set (private workspace package, sibling of sidecar-proto),
so it is bumped here to keep main release metadata consistent.

Independently-versioned workspace packages (agui-adapter, components,
diagnostics, metatool, plugin-runtime, registry-protocol, tools/serve,
telemetry-worker) are intentionally left untouched.

Supersedes the stale release/v0.10.1 PR (#4205).
2026-06-16 03:59:48 +00:00
CaprikaandGitHub f2fef8d9a5 [codex] fix prompt title summaries (#4348)
* fix prompt title summaries

* fix ui p0 title expectations

* use selected agent for title suggestions

* strip generated titles across streams
2026-06-15 15:32:29 +00:00
Passive BookandGitHub 95900a615b Fix design system preview image asset URLs (#4177)
* fix: rewrite design system preview image assets

* fix: reopen design review feedback cards

* fix: preserve app urls in design previews

* fix: preserve design preview asset suffixes

* fix: rewrite inline design preview css assets

* fix: refresh design manifest labels

* fix: surface invalid design manifests

* test: stabilize workspace restoration p0

* fix: validate design manifest card entries
2026-06-15 08:54:42 +00:00
Marc ChanandGitHub 6c555f93d6 chore(ci): stabilize visual regression screenshots (#4290)
* Stabilize visual regression screenshots

* Stabilize BYOK visual settings states
2026-06-15 02:53:00 +00:00
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
AmyandGitHub f82a4e3828 fix(web): apply composer BYOK model selection (#4209) 2026-06-12 08:50:17 +00:00
AmyandGitHub 571b43dce0 [codex] Expand UI E2E coverage and P0 CI signal (#4196)
* add PR UI P0 gate

* fix(ci): keep critical UI check in required workflow

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

* ci: split workspace restoration P0 shard

* ci: reduce visual and daemon test wall time

* ci: skip duplicate critical UI gate on PRs

* ci: increase daemon test sharding

* test(e2e): expand critical UI flow coverage

* test(e2e): promote critical onboarding and automation flows

* test: expand ui e2e coverage

* test: repair PR P0 onboarding and media sync checks

Generated-By: looper 0.9.7 (runner=fixer, agent=codex)
2026-06-12 04:41:49 +00:00
21e01f6a25 Fix raw asset review cards in design systems (#4093)
* fix: avoid raw asset review cards

* fix: resolve web component styles in dev

* fix: keep design system component images reviewable

* fix: use webpack for local web dev sidecar

* fix: improve design system review cards

* fix: render design system review previews from srcdoc

* fix: keep image ui kit cards generic

* fix: rebase inlined preview css urls

* test: allow slow send-now navigation

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
2026-06-11 15:37:02 +00:00
SarinandGitHub 2f301902d7 fix(web): keep New Project design-system dropdown above form sections (#4026)
The 'Design system' dropdown in New Project rendered behind the form
sections below it (Target platforms, Companion surfaces, Fidelity,
Create), so the form bled through the open popover.

Every .newproj-section carries a residual identity transform from the
od-fade-slide-up entrance animation (animation-fill-mode: both), turning
each section into its own stacking context. .ds-picker is such a section,
so the popover's z-index was trapped inside the picker and could not rise
above later sibling sections. Lift the OPEN picker's stacking context
above its siblings so the dropdown paints on top.

Red->green Playwright spec samples points down the open popover and
asserts elementFromPoint resolves into the popover.
2026-06-11 14:06:46 +00:00
AmyandGitHub d055737de7 [codex] Add PR UI P0 gate (#4142)
* add PR UI P0 gate

* fix(ci): keep critical UI check in required workflow

Generated-By: looper 0.9.7 (runner=fixer, agent=codex)
2026-06-11 09:09:00 +00:00
AmyandGitHub 8c3500c807 [codex] Cover preview toolbar and conversation history flows (#4134)
* test(e2e): expand home and project detail coverage

* test: cover preview toolbar and conversation history flows

* test: lower priority of supplemental e2e cases

* Revert "test: lower priority of supplemental e2e cases"

This reverts commit 86d9872500.
2026-06-11 07:17:40 +00:00
4c8914dc71 feat(web): split onboarding newsletter into its own third step (#4106)
* feat: move onboarding newsletter signup to its own third step

* test(e2e): walk amr-onboarding through the new newsletter step before finishing

* fix(web): keep about_you_submit exactly-once on the onboarding completion path

The newsletter step is now its own (final) step with a clickable stepper
and Back button. Emitting the about_you_submit survey snapshot when the
user leaves the About-you step double-fired on Back-then-Continue and
fired zero times on a forward stepper jump. Move it onto the completion
path, stamp it with fixed About-you coordinates (it describes the
About-you submission regardless of which step finishes), and guard it
with a per-session ref so it is exactly-once. Adds regression tests for
the stepper-jump and Back-then-Continue flows.

* test(web): walk amr onboarding e2e through the newsletter step before finishing

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
Co-authored-by: lefarcen <935902669@qq.com>
2026-06-10 16:14:59 +00:00
70c70ff9a3 feat(web): replicate-first Use menu + send-button attention pulse (#4059)
* feat(web): lead the plugin detail Use menu with Replicate this content

The split-button menu only exists when the plugin ships an example
query, and reproducing the previewed result is what most users open it
for — so the replicate option now comes first and structure-only Use
drops to second.

* feat(web): pulse the send button after a plugin Use or example-prompt pick

Choosing Use / Use with query in the plugin detail modal, or clicking an
example-prompt card, seeds the composer and returns the user to it — but
nothing signals that sending is the next step. Flash the send button
twice (house ease-out, 0.25s delay so the scroll-back settles first,
none under prefers-reduced-motion) via a new HomeHeroHandle.pulseSend()
fired from routePluginUse and useExamplePlugin.

* feat(web): replicate-content as the primary detail CTA + sheen-style send pulse

- The detail modal's primary Use button now reads (and acts as)
  'Replicate this content' when the plugin ships an example query;
  structure-only Use moves behind the caret menu. Shared via
  pluginUsePrimaryAction so all four detail variants agree.
- The send-button attention effect drops the ring+scale flash for a
  soft light sweep crossing the button twice — same trigger points,
  same reduced-motion opt-out.
- Plain structure-only Use now pulses only when the composer is
  actually submittable (draft text or staged files); flashing a
  disabled send button pointed at a dead end.

* feat(web): first-run guidance trail — prototype chip and first preset card sheen

Brand-new users (no projects, fresh storage) get a sheen pulse on the
Prototype type chip ~1s after Home settles; picking any type chip
advances a persisted stage and the first example-prompt card pulses
once when the chip's presets render, completing the trail (the existing
send-button pulse covers the final beat after a card pick). Users with
projects have the stage completed silently so the trail never shows.

The send-button sheen generalizes into a shared
.home-hero__attention-sheen class (accent-tinted glint on light chip /
card surfaces), still skipped under prefers-reduced-motion.

* fix(web): gate the first-run guide on project loading completing

firstRunGuide was true whenever projects was the initial empty array,
so the trail could arm for an existing user whose projects were still
loading. Make the prop tri-state (undefined while loading): the guide
neither arms the chip pulse nor silently completes the stage until the
projects answer is known.

* fix(web): close any in-flight guide stage for existing users + gate the card pulse

A chip pick during the projects-loading window can advance the guide
stage to 'card' before firstRunGuide resolves; if the user then turns
out to have projects, the stage lingered and the beat-2 effect (not
gated on firstRunGuide) could sheen the first preset card for a
non-new user. The firstRunGuide === false branch now completes ANY
unfinished stage, and the card-pulse effect requires
firstRunGuide === true.

* fix(web): pulse Send from the static prompt-example path too

The fallback prompt-example cards (rendered when a chip has no example
plugins) seed and focus the composer entirely inside HomeHero, so they
never reached the HomeView-routed pulseSend(). Extract a local
triggerSendAttention() shared by the imperative handle and
usePromptExample, with a focused spec clicking a
home-hero-prompt-example card.

* fix(test): null-guard the first prompt-example card lookup

tsc (noUncheckedIndexedAccess) rejects passing exampleCards[0] straight
to fireEvent.click; guard explicitly.

* fix(web): gate the Send pulse on the composer actually being submittable

usePlugin() now resolves a boolean: whether the bound plugin left the
composer submittable (inputs valid, apply not failed/superseded). All
three pulse call sites (use-with-query, plain Use, example preset pick)
consult it, so a plugin with required inputs and no defaults routes the
user to the inputs form without a misleading flash on the disabled Send
button. Spec: required-input plugin via detail-modal replicate → Send
stays disabled and unsheened.

* fix(web): carry the guide's beat 2 through the static prompt-example fallback

A chip with no plugin presets renders static prompt-example cards, but
the beat-2 effect only watched filteredExamplePlugins — a fresh user on
that path never got the card pulse and the persisted stage stuck at
'card'. Either card surface now satisfies beat 2, the first static
prompt-example button carries the sheen, and a regression spec covers
the presetless-chip path.

* test(e2e): route freeform Use through the Use-plugin-only menu option

The replicate-first menu change makes the detail modal's primary Use button
seed the example query for query-bearing starters, so the structure-only
freeform path now lives in the caret menu's 'Use plugin only' option. Update
the P0 critical 'keeps the prompt freeform' spec to open the caret menu and
click that option, matching the shipped behavior.

* test(e2e): route the remaining freeform Use cases through the menu option

The replicate-first primary CTA also seeds the prompt for query-bearing
starters rendered via PluginExampleDetail/PreviewModal, so the neighboring
[P1] 'Use plugin from the details modal' case (an html-preview fixture with an
example query) that clicked the primary button and asserted an empty composer
would fail once it runs outside the @critical gate. Route it through the caret
menu's 'Use plugin only' option like the P0 case, and correct the now-stale
'no pre-fill' comments on the chip-only and use-with-query cases.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
Co-authored-by: lefarcen <ontf116@gmail.com>
2026-06-10 12:00:53 +00:00
AmyandGitHub a0221deaba [codex] Fix onboarding dropdown styling (#4066)
* Fix onboarding dropdown styling

* Fix onboarding dropdown placement test

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

* Fix searchable onboarding dropdown regressions

Generated-By: looper 0.9.7 (runner=fixer, agent=codex)
2026-06-10 09:28:21 +00:00
844a0c0af1 fix(web): scope Use actions to the plugin detail modal and decouple the Community filter from hero chips (#4037)
* fix(web): remove inline Use actions from Community gallery tiles

The Home Community gallery tile grew an inline Use / Use with query
split button in its title bar, repeating per card. The gallery tile is
a pure live preview: opening the detail modal is where Use and Use
with query live. Drop the gallery use menu (and its CSS) and route the
visual-home use-with-query e2e flow through the detail modal's split
Use button. The rich management layout (PluginsView installed tab)
keeps its hover-overlay Use menu.

* fix(web): decouple the Community category filter from hero type chips

Picking an example-prompt type chip (Prototype / Slide deck / ...) —
including the default chip on first paint — force-synced the Community
grid's category selection through presetSelection, silently rewriting
the user's browsing filter. The two surfaces share a taxonomy but are
independent controls: the chip drives what the composer generates, the
pills only filter the gallery. Remove the presetSelection plumbing
(HomeView memo -> PluginsHomeSection prop -> usePluginFacets effect);
the Community grid now boots on All and only moves when its own pills
are clicked.

* fix(e2e): match the Deck Writer detail dialog by plugin name

Deck Writer carries a previewEntry, so its detail surface is the
PreviewModal whose dialog is labelled 'Deck Writer preview' — the
'... details' label only exists on the scenario detail. Match the
dialog on the plugin name so the visual use-with-query flow finds it.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-10 06:54:30 +00:00
AmyandGitHub 39cf931290 Remove project instructions UI and preserve stream errors (#4045)
* Remove project instructions UI and preserve stream errors

* Stop injecting hidden project instructions

Generated-By: looper 0.9.7 (runner=fixer, agent=codex)
2026-06-10 06:14:46 +00:00
3f5fe0f96c feat(amr): forward AMR_CLIENT_SOURCE to vela + source on wallet links (#4005)
* fix(landing): keep auth redirects on AMR wallet

* feat(amr): tag vela CLI launches with AMR_CLIENT_SOURCE + source on wallet links

So vela analytics can attribute Open Design's command funnel and model spend
back to this host (source=open_design), and the AMR wallet landing carries the
source for the web page_view.

- runtimes/env: set AMR_CLIENT_SOURCE=open_design for the amr agent spawn (not
  PII, so no telemetry-consent gate)
- integrations/vela: spawnVelaLogin forwards OD_INSTALLATION_ID (consent-gated)
- web/daemon: AMR wallet recharge URL gains ?source=open_design

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

* test(web): expect ?source=open_design on AMR console/recharge URLs

The AMR console/recharge links the OD app opens into vela web now carry
?source=open_design so vela attributes the visit to Open Design. Update the
console/recharge URL assertions accordingly.

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

* test(daemon): expect ?source=open_design on AMR insufficient-balance recharge URL

DEFAULT_AMR_RECHARGE_URL now carries the source param for attribution.

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

* chore(amr): bump bundled vela CLI to 0.0.15 + fix e2e recharge URL assertion

- tools/pack: bundle @powerformer/vela-cli 0.0.15 (the release carrying the
  source-attribution logic that reads AMR_CLIENT_SOURCE and tags model_request)
- e2e: expect the insufficient-balance recharge URL to carry ?source=open_design
  (addresses review on DEFAULT_AMR_RECHARGE_URL)

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

* chore(nix): refresh pnpm-deps hashes after vela CLI bump

The tools/pack @powerformer/vela-cli bump changed pnpm-lock.yaml, invalidating
the daemon/web fetchPnpmDeps fixed-output hashes. Update to the values the Nix
flake check computed.

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

---------

Co-authored-by: audit <a@b.c>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 02:02:48 +00:00
6313286232 feat(home): plugin detail "Use plugin" split menu + align use-with-query with example-prompt seed (#3997)
* feat(home): plugin detail "Use plugin" split menu + align use-with-query with example-prompt seed

- PreviewModal.primaryAction gains an optional split-button menu. The plugin
  detail modal's "Use plugin" now offers two variants — 仅使用插件 (use) and
  复刻此内容 (use-with-query) — wired through the existing routePluginUse action,
  i18n'd across all 19 locales (new preview.usePlugin / usePluginOnly* /
  replicateContent* keys).
- use-with-query now seeds the composer with the SAME human-friendly text the
  Home example-prompt cards use. Extracted examplePresetSeedPrompt (+ its
  dependencies) from HomeHero into a shared plugins-home/presetSeedPrompt module
  so both surfaces share one source of truth, instead of the detail modal
  dumping the raw od.useCase.query meta-instruction ("follow the en field
  verbatim; start from example.html") into the textarea.
- The example-prompt active plugin chip now shows the same × clear button as the
  Community path (activeBadge.isExplicitPlugin distinguishes a user-picked
  plugin from a task-chip default).
- Analytics: community_gallery/use_plugin (action=use|use_with_query) lands the
  documented row-118 event; chat_composer/plugin_chip_clear mirrors
  working_dir_clear for the chip ×.

* feat(prompt): generate artifact copy in the user's UI locale

Chinese (and other non-English) prompts were producing English pages: when a
template / plugin / design-system ships English reference content, the agent
copied that wording verbatim. The UI-locale override only covered chat prose
and generated form controls, not the artifact body.

Extend the locale override so all user-visible copy in the generated
HTML/React/page/deck (headings, body, nav, button/link labels, captions, alt
text, form fields) is written in the run's UI locale by default — and reference
content in another language must be translated/adapted, not shipped verbatim.
Brand names / code / identifiers stay as-is; an explicit user request for a
different output language still wins.

* fix(plugin-details): scenario fallback gets the use/use-with-query split menu

Review follow-up (#3997): PluginScenarioDetail was a single onUse(record,'use')
button, so any plugin routed to the text/scenario fallback lost the new split
action — users couldn't pick "Use plugin only" vs "Replicate this content" even
when od.useCase.query exists. Reuse the shared buildPluginUseMenu in the footer
as an upward-opening split button (caret menu), matching the html/design/media
variants, and keep a plain single button when there is no query.

Also update the home use-with-query visual e2e: use-with-query now seeds the
rendered preset text ("Draft a topic deck.") rather than the raw `{{topic}}`
query, matching the example-prompt card path.

Regression tests: scenario+query renders the split menu caret; scenario without
query keeps a single button.

* fix(home): preserve placeholder write-back when use-with-query seed is the query

Review follow-up (#3997, blocking): use-with-query unconditionally nulled
`queryTemplate`, dropping the only path that writes composer edits back into
`active.inputs`. For presets whose seed IS the rendered (human-friendly) query,
that meant editing a hydrated value before running submitted the plugin with
stale default inputs.

examplePresetSeedPrompt now returns `{ text, fromRenderedQuery }`. routePluginUse
keeps the raw `{{...}}` query template (and `queryTemplateAllowsPrefix`) only when
the seed came from the rendered query; it still nulls the template when we fell
back to a description / meta-instruction seed (no placeholders to extract). The
meta-instruction → description fix is unchanged.

Tests: friendly-query use-with-query now asserts the placeholder edit flows back
into pluginInputs (empty-draft and edited-draft-prefix cases); the
meta-instruction case still seeds the description with no write-back.

* fix(home): persist explicit-pick flag for active plugin chip visibility

Review follow-up (#3997): the active plugin chip's visibility + clear-button
gate inferred "explicit pick" from `record.id !== defaultPluginIdForChip(chipId)`.
An example-prompt preset whose plugin id equals the chip's default plugin — the
prototype rail binds `example-web-prototype`, which is also the prototype chip's
default — was therefore misclassified as a task-default binding, so its chip/×
never appeared even though the user explicitly picked the preset.

ActivePlugin now carries an `explicitPick` flag, set on the example-prompt
preset (useExamplePlugin) and Community / detail-modal (routePluginUse) paths.
Both `activeBadge` (chip label vs plugin title + ×) and
`shouldShowActivePluginChip` (the chip-visibility gate) short-circuit on it
before falling back to the id heuristic — so an explicit pick always surfaces
its own chip, while a type-chip default binding still stands in for the task
chip. Added a HomeView.activePluginChip regression covering the preset-equals-
default case.

* fix(home): keep prefix matching on for use-with-query placeholder extraction

Review follow-up (#3997): `queryTemplateAllowsPrefix` only enabled prefix
matching when the composer already had text BEFORE the user clicked Replicate.
The empty-draft → prepend-intro → edit-placeholder path then fell through:
extraction stayed anchored at `^`, so a placeholder edit after a freshly-added
intro stopped writing back into active.inputs and submit could re-apply stale
defaults.

Enable prefix matching whenever we track the query template (`hasTemplate`).
Suffix matching is equally correct with no prefix, and now tolerates an intro
the user prepends after the seed is inserted. Added the empty-draft → add
prefix → edit placeholder regression.

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-09 16:04:03 +00:00