* Update home starter template categories
* fix(web): address PR #2501 review follow-ups
- usePluginFacets.clearFacets() now also resets `mode` to 'all' so the
empty-state "Clear filters" CTA escapes Saved mode in one click. A
fresh browser clicking Saved (or Saved combined with a zero-match
search) was previously stranded on the empty view because the CTA
only cleared `selection`/`query`.
- Restore the "Link code folder" item in the composer Tools -> Import
panel. The earlier refactor dropped its `onLinkFolder` wiring and
left every remaining ImportItem disabled, so chats without linked
dirs lost the only enabled entry point to `openFolderDialog()` /
`patchProject({ metadata.linkedDirs })`.
Adds regressions:
- plugins-home-section: Clear filters from the Saved empty state
- ChatComposer.import-menu: folder-link click-through hits the folder
dialog and patches `linkedDirs`
---------
Co-authored-by: qiongyu1999 <2694684348@qq.com>
Co-authored-by: lefarcen <935902669@qq.com>
Conflict resolved by taking origin/main:
- apps/web/src/components/EntryNavRail.tsx design-systems rail
button icon name palette-filled (release-side) -> blocks (main);
main's icon swap is part of the more recent design-systems rail
pass.
* 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>
Conflicts resolved by taking origin/main on both files. Root cause:
main's PR #2460 (fix(landing): align logo.webp with brand icon) changed
HomeHero.tsx's .home-hero__brand-mark to render <img src=/app-icon.svg>
instead of an inlined <HeroBrandIcon /> SVG, and bundled the matching
CSS (26px round badge with bg-panel + border + padding 2px) plus a
gap/font-size tune. The release-side visual-refresh CSS still targeted
the SVG layout (38px square, transparent, inset SVG selector). Keeping
release's CSS would leave main's <img> unstyled.
- apps/web/src/styles/home/home-hero.css three blocks, all taken from
main: .home-hero__brand gap 8px, .home-hero__brand-mark redesigned for
<img> child, .home-hero__brand-name font-size 16px.
- apps/web/src/index.css two blocks, both taken from main: workspace
tab close column 22px and .workspace-tab__close 18x18 (paired
tune-down of tab UI spacing).
* feat(daemon): add project working directory management and editor hand-off functionality
- Introduced new flags for project commands to manage working directories, including `--working-dir` and `--dir`.
- Implemented API routes for listing available editors and opening projects in selected editors.
- Added a hand-off button in the ChatPane header to facilitate opening project folders in local applications.
- Enhanced the HomeHero component to include working directory and design system settings, improving user experience in project creation.
- Created HomeHeroSettingsChips component for inline management of working directory and design system selection.
* feat(chat): implement voice transcription proxy and enhance UI components
- Added a new API route for voice transcription using OpenAI's `/audio/transcriptions` endpoint, allowing users to send audio blobs directly for transcription.
- Integrated multer for handling audio file uploads in memory, ensuring efficient processing without disk storage.
- Updated the HomeHero component to include example prompt suggestions for plugins, enhancing user interaction.
- Introduced the EditorIcon component to visually represent different editors in the hand-off menu, improving the user experience.
- Refined the HandoffButton component to utilize the new EditorIcon, providing a more cohesive interface for selecting editors.
- Enhanced CSS styles for various components to improve layout and responsiveness, including adjustments to tab and button sizes for better usability.
* style(workspace-shell): enhance layout and overflow handling
- Updated CSS for .workspace-shell to ensure full viewport width and height, with proper overflow management.
- Adjusted grid layout to prevent content overflow and maintain responsiveness.
- Modified styles for .workspace-tabs-chrome to improve width handling and prevent overflow issues.
* refactor(chat): remove voice transcription proxy and related components
- Deleted the voice transcription proxy implementation, including the associated API route and multer configuration.
- Removed the MicButton component from the ChatComposer and HomeHero components to streamline the UI.
- Updated HomeHero to include example suggestions without the voice input functionality.
- Adjusted CSS styles for various components to maintain layout consistency after the removal of the MicButton.
* feat(daemon): implement minting of HMAC tokens for working directory management
- Added a new function `mintImportTokenFromCurrentSecret` to generate HMAC tokens bound to a specified base directory, enhancing security for working directory operations.
- Updated the `desktop-auth.ts` file to include the new token minting functionality, which returns structured errors when the desktop auth secret is cleared.
- Introduced new IPC message types for minting import tokens in the sidecar protocol, allowing seamless integration with the daemon's working directory management.
- Enhanced the `WorkingDirPill` component to utilize the new token minting flow for secure directory selection in desktop builds.
- Updated CSS styles for the HomeHero component to accommodate new example suggestion features and maintain layout consistency.
* fix(HomeView): import HOME_HERO_CHIPS constant for improved chip management
- Updated the HomeView component to import the HOME_HERO_CHIPS constant from the chips module, enhancing the management of hero chips within the component.
* feat(daemon): implement mintImportTokenViaSidecar for secure working directory management
- Introduced the `mintImportTokenViaSidecar` function to facilitate the minting of HMAC tokens for desktop-import operations via the daemon's sidecar IPC. This allows CLI commands to bypass authentication when the desktop-auth gate is active.
- Updated the CLI to utilize the new token minting function when setting the working directory, ensuring secure access to trust-gated API endpoints.
- Enhanced the sidecar server to handle minting requests and return structured error messages for improved user feedback.
- Added tests to validate the new token minting functionality and its integration with the working directory management process.
- Refactored related components to support the new token flow, improving overall security and user experience.
* feat(HomeHero): enhance UI components and styles for improved user experience
- Updated HomeHero component to replace active dot indicators with Plug icons for better visual representation of active plugins.
- Adjusted CSS styles for various elements, including padding and dimensions, to enhance layout consistency and responsiveness.
- Introduced new styles for active type icons and improved hover effects for buttons.
- Updated HomeHeroSettingsChips to change button titles and icons for clarity.
- Added tests to ensure proper rendering and functionality of updated components.
* feat(ProjectDesignSystemPicker): enhance design system selection with preview functionality
- Updated the ProjectDesignSystemPicker component to include a preview feature for design systems, allowing users to see a preview of the selected design system.
- Implemented hover functionality to update the preview based on the hovered design system.
- Added fullscreen preview capability for a more immersive experience.
- Enhanced CSS styles for the design system picker to improve layout and responsiveness.
- Introduced tests to validate the new preview functionality and ensure proper interaction within the component.
* feat: refactor project metadata handling and enhance design system picker
- Updated the default scenario plugin ID retrieval to use project metadata, improving the logic for determining the appropriate plugin based on project intent.
- Enhanced the ProjectDesignSystemPicker and related components to support localized design system summaries and categories, improving user experience.
- Introduced new translations for working directory and design system picker components, ensuring better accessibility and usability across different locales.
- Added a new 'live-artifact' project type to the HomeHero chips, expanding the functionality for users creating refreshable artifacts.
- Updated tests to validate the new project metadata handling and design system picker functionalities.
* feat: enhance localization and styling for design system components
- Added French translations for working directory and design system picker components, improving accessibility for French-speaking users.
- Updated CSS styles for the pet task item to ensure consistent padding and layout.
- Introduced a new test suite for HomeHeroSettingsChips to validate localization and design system selection functionality.
- Enhanced ProjectDesignSystemPicker tests to ensure proper localization and interaction with design system categories.
* fix: update .gitignore to include all claude-sessions directories and remove specific session files
- Modified .gitignore to ensure all claude-sessions directories are ignored by using a wildcard pattern.
- Deleted two specific claude-sessions markdown files to clean up unnecessary session data.
* fix: repair home automation ci regressions
* fix: stabilize artifact consistency e2e
* Remove folder picker changes from PR 2400
---------
Co-authored-by: pftom <1043269994@qq.com>
Co-authored-by: qiongyu1999 <2694684348@qq.com>
Conflicts resolved by taking origin/main on all six points:
- apps/web/src/components/HomeHero.tsx:479-487 brand div removed
(main dropped the .home-hero__brand wrapper; the release-side visual
refresh still had it).
- apps/web/src/components/HomeHero.tsx:894-898 attach Icon size
18 (main's update) replaces 20 from release.
- apps/web/src/components/HomeHero.tsx:913-927 submit button uses
<Icon name="arrow-up" size={22} /> (main's component refactor)
instead of the release-side inline SVG.
- apps/web/src/components/EntryShell.tsx:578-582 Discord Icon size
14 (main) instead of 16 (release).
- apps/web/src/styles/home/home-hero.css drop .home-hero__brand /
__brand-mark / __brand-name rules — main removed both the component
div and these CSS rules together; keeping the CSS would be dead code.
- apps/web/src/styles/home/entry-layout.css Discord badge icon color
#5865f2 (main, the brand color introduced by PR #2386) instead of
release's neutral var(--text-strong).
* Reapply "fix(web): demote Plugins and Integrations to nav rail footer (#1806)" (#2360)
This reverts commit 1ab8758045.
* fixup: align EntryHelpMenu Discord URL with #2386 update
The revert of #2360 brought back EntryHelpMenu.tsx as #1806 originally
added it, with DISCORD_URL = 'https://discord.gg/BYShPgWpq'. #2386 later
rotated the Discord invite to mHAjSMV6gz, but only in the places that
existed on main at the time (EntryShell avatar dropdown + the e2e test);
EntryHelpMenu didn't exist then, so it never got updated. The e2e test
the revert reintroduced asserts the new URL, so the component must
match.
* test(e2e): harden extended coverage contracts
* docs(testing): add e2e hardening status
* fix(web): persist artifact chips after daemon runs
* ci: install playwright browsers for e2e vitest
* Fix daemon run recovery across reloads
Pin daemon-created runs to assistant messages immediately so hard reloads before the create response can reattach.
Replay terminal and active run events from the beginning on reload so restored turns keep assistant text, thinking events, produced files, and artifacts.
Fixes#2366Fixes#2368Fixes#2371
* test(e2e): preserve fake runtime selection across reload
* fix(web): scope daemon run recovery to daemon mode
* fix(e2e): remove duplicate delayed smoke flag
* fix(web): scope replay artifact recovery to current run
* fix(daemon): remove duplicate run-create pin
* Fix daemon run recovery across reloads
Pin daemon-created runs to assistant messages immediately so hard reloads before the create response can reattach.
Replay terminal and active run events from the beginning on reload so restored turns keep assistant text, thinking events, produced files, and artifacts.
Fixes#2366Fixes#2368Fixes#2371
* Fix ProjectView daemon run recovery tests
Shared device frames serve at /frames/<name>.html and previously
assigned the raw ?screen= value to the inner iframe.src. A
project-relative value like screen=screens/foo.html resolved against
/frames/, producing /frames/screens/foo.html (404), instead of the
embedding project's /api/projects/:id/raw/screens/foo.html.
The five frame HTML files now resolve relative ?screen= values
against document.referrer when present (the embedding project
preview), falling back to location.href so standalone /frames/*
loads keep working. Absolute and root-relative paths are passed
through unchanged.
Adds an e2e Vitest spec that evaluates each frame's inline <script>
in a Node vm and asserts iframe.src under five scenarios per file
(25 cases total): project-relative against referrer, root-relative
pass-through, absolute pass-through, empty referrer fallback, and
missing ?screen= no-op.
Fixes#2234
* feat(web): introduce Automations tab with dual-track capability for routines
This commit adds a new Automations tab that consolidates routines, schedules, and live artifacts, allowing users to manage automations seamlessly. The tab features a modal for creating and editing automations, which supports various scheduling options (hourly, daily, weekdays, weekly) and project modes (create_each_run, reuse). The CLI is also updated to expose automation commands, ensuring consistency between the web UI and CLI interfaces.
Key changes include:
- New `NewAutomationModal` component for automation creation and editing.
- Updated `TasksView` to integrate the new Automations functionality.
- Enhanced styling for the Automations tab to improve user experience.
This implementation aligns with the dual-track capability exposure policy, ensuring all features are accessible via both the web UI and CLI.
* feat(daemon): enhance automation context handling and CLI commands
This commit introduces several improvements to the automation context management and updates the CLI commands accordingly. Key changes include:
- Added support for new context fields (`plugin`, `mcp`, `connector`) in automation commands.
- Updated the CLI to reflect new target options (`new-project`).
- Enhanced error messages for invalid target inputs.
- Introduced functions to handle context selection and normalization for routines, including the ability to parse and store context data in the database.
- Updated the database schema to include a new `context_json` field for routines.
- Improved the handling of context in routine routes and the web interface, ensuring that selected contexts are properly managed and displayed.
These changes aim to provide a more robust and flexible automation experience, aligning with the recent enhancements in the web UI.
* feat(web): enhance TasksView with automation run history and status indicators
This commit introduces several new features to the TasksView component, including:
- Added functionality to display automation run history for each routine, showing metadata such as status, timestamps, and project details.
- Implemented status indicators for routine runs, providing visual feedback on their current state (succeeded, failed, running, queued).
- Enhanced the UI to allow users to expand and view detailed run history, including the ability to open the corresponding project conversation.
- Updated styles to improve the presentation of automation statuses and history.
These changes aim to provide users with better insights into their automation routines and improve overall usability.
* feat(daemon): implement automation ingestion and proposal management
This commit introduces several new features related to automation ingestion and proposal management within the daemon. Key changes include:
- Added new modules for handling automation source packets and proposals, allowing for the storage, retrieval, and management of automation-related data.
- Implemented functions to list, create, and apply automation proposals, enhancing the automation workflow.
- Introduced new CLI commands for interacting with memory entries and automation sources, providing users with more control over their automation processes.
- Enhanced the server routes to support automation source and proposal APIs, enabling seamless integration with the existing system.
These changes aim to improve the overall automation experience, making it easier for users to manage and utilize automation proposals and ingestions effectively.
* fix(web): demote Plugins and Integrations to nav rail footer
Plugins and Integrations are platform-configuration surfaces, not
daily-use destinations. Moving them to the footer section of the
left nav rail — separated from primary items by a thin divider —
keeps them reachable while giving the primary four items
(Home, Projects, Automations, Design Systems) the visual weight
they deserve.
- EntryNavRail: remove Plugins/Integrations from the main __group
and place them in the __footer above the help launcher
- entry-layout.css: add __divider rule (1 px separator) to visually
mark the boundary between primary and secondary nav regions
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): remove settings dropdown, gear opens settings directly
The gear/cog button previously opened a dropdown that mixed three
unrelated concerns: community links (X, Discord), preference quick-
access (Language, Appearance), a feature shortcut (Use everywhere),
and a redundant Settings entry — creating two separate paths to the
same Settings dialog and duplicating Language/Appearance relative to
the Settings sidebar.
Changes:
- Gear button now directly opens the Settings dialog (no intermediate
dropdown layer)
- Follow @nexudotio on X and Join Discord moved to the Help menu at
the bottom of the nav rail, where community/external links belong
- Language and Appearance remain exclusively in the Settings dialog
- Use everywhere remains exclusively in the topbar chip
- Remove dead state (avatarMenuOpen, languageExpanded,
appearanceExpanded), ref, outside-click effect, and module-level
constants (APPEARANCE_THEMES, APPEARANCE_LABEL, describeModelChip)
that were introduced solely to support the dropdown
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(web): move output-type chips above chat input as tab bar
The home hero previously had two chip rows below the chat input that
mixed two unrelated dimensions: output type (Prototype, Slide deck,
Image…) and workflow source (Create plugin, From Figma, From folder,
From template). Users had no visual cue that these were different
categories.
This change separates the two dimensions clearly:
- Output type (create group) becomes a tab bar positioned above the
input card. Tabs share the same chip data and onPickChip dispatch,
so plugin selection, active state, and pending state are unchanged.
Active tab shows a colored underline; the bar border visually
connects to the input card below.
- Workflow source (migrate group) stays as the chip row below the
input card, now standing alone with unambiguous "how to start"
semantics.
- Subtitle updated from "Pick a plugin below" to "Pick a type"
to match the new placement.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): skip replace-prompt confirmation when switching output-type tabs
Output-type tab clicks (create group) are mode-selection gestures;
the user expects the prompt to update immediately without a dialog.
The confirmation is still shown for migrate-group chips (From Figma
etc.) where the replacement carries meaningful user-provided content.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): use brand logo as Home destination, drop redundant brand mentions
The entry nav rail previously rendered the brand logo and a separate
Home icon back-to-back; both invoked `onViewChange('home')`, so the
Home button was pure duplicate affordance. The hero pane also
displayed a third "Open Design" lockup that competed with the rail
logo and the rebranded title.
This collapses those affordances:
* `EntryNavRail` drops the dedicated Home `NavButton`. The brand
logo button now carries `aria-current="page"` and an `is-active`
visual state when the home view is showing, and its tooltip reads
"Open Design · Home" off-home so the navigation behavior stays
discoverable for new users.
* `entry-layout.css` adds the matching `.entry-nav-rail__logo.is-active`
accent treatment so the "you are here" cue reads at parity with
primary rail buttons.
* `HomeHero` removes the inline `home-hero__brand` lockup and the
associated CSS, then retunes the title/subtitle/type-tab spacing
so the headline group still pairs tightly with the type tabs and
input card below.
* `entry-chrome-flows` is updated to assert the logo carries the
active page treatment and that no `entry-nav-home` test id
resurfaces by mistake.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): auto-grow home chat input, disable internal scroll and drag-resize
The home hero textarea was capped at a fixed `min-height: 84px` with
`resize: vertical`, so users had to either drag the bottom-right
corner to enlarge it or scroll the textarea internally to read
longer prompts. That hid context (loaded plugin templates routinely
overflow three lines) and exposed a manual grip whose state was easy
to leave in an awkward height.
This change makes the chat box grow with its content:
* `HomeHero` adds a `useLayoutEffect` that, on every prompt change,
resets the textarea height to `auto` so the browser can measure a
smaller content, then writes back `scrollHeight` in pixels. The
effect uses layout phase (not effect phase) to avoid a one-frame
flash at the previous height when a plugin loads a long example
prompt.
* `home-hero.css` swaps `resize: vertical` for `resize: none` and
adds `overflow: hidden`, so the manual drag grip disappears and
the textarea never scrolls internally. `min-height: 84px` is kept
so the empty input still reads as a chunky chat box. The outer
page handles overflow when the prompt is genuinely very long.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): make output-type tabs read as folder-tabs attached to chat box
The previous tab bar used a small icon + label per tab and signaled
the active tab with a 2px accent underline sitting on a horizontal
divider line. That divider visually broke the relationship between
the tabs and the input card below — the active tab looked like a
free-floating header, not a flap of the chat surface, so users had
to do extra work to mentally connect "I picked Prototype" with the
prompt area immediately underneath.
This switches the tab bar to a folder-tab pattern:
* `HomeHero` drops the per-tab `Icon` element. The seven labels
(Prototype, Live artifact, Slide deck, Image, Video, HyperFrames,
Audio) already disambiguate at the type sizes used here, and the
icons were primarily decorative.
* `home-hero.css` rewrites the tab styling:
- The bar no longer paints its own baseline border; the input
card's top edge serves as the baseline.
- Each tab is a rounded-top container with a 1px transparent
border and a `-1px` bottom margin, so its bottom edge overlaps
the card's top border by exactly one pixel.
- The active tab borrows the card's panel background and border
color, and overrides its bottom border with the panel color
so it visually erases the card's top border for the tab's
width. The result reads as one continuous "Prototype is this
chat box" surface.
- The card's prior `margin-top: 8px` is removed so the tab bar
bottom and card top sit at the same y coordinate, which is the
geometric precondition for the 1px overlap to land cleanly.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): enlarge home chat attach and submit buttons for legibility
The attach (paper-clip) and submit (arrow-up) controls on the home
chat input rendered at 32px diameter with 14px and 18px glyphs
respectively. After stroke antialiasing the icons read at roughly
11–12px on typical displays — small enough that users reported the
glyphs were illegible and had to be discovered by trial-and-error.
This bumps both controls to 38px circles and grows their glyphs
(attach 14 → 18, submit 18 → 22). The primary call-to-action now
has clearly more visual weight than the surrounding muted hint
text, and the paper-clip is recognisable at a glance.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): paint a chevron on inline select slots in the home prompt
Inline select slots in the home prompt overlay (e.g. the
`high-fidelity` / `wireframe` fidelity picker on the Live artifact
template) rendered as plain pill highlights, visually identical to
free-text and read-only text slots. The slot's `appearance: none`
strips the browser's default chevron, so users had no affordance
hinting the value was switchable.
This wraps select-type slots in an `inline-flex` span and overlays
an explicit chevron-down `Icon` against the slot's trailing padding
(bumped from 18px to 22px to make room). The chevron inherits the
accent color via the wrap's `color` property so it themes correctly
in light and dark modes. Click semantics are unchanged because the
chevron is `pointer-events: none`.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): size inline number slots to their value, not the whole row
Number-type inline slots in the home prompt (e.g. the slide-count
spinner on the Slide deck template) inherited the generic slot
`min-width: 8ch` and then stretched to the browser's default
`<input type=number>` width, so a two-digit value like "10" ate
the entire remaining line and pushed the native spinner buttons
to the far right edge — far away from the value they control.
This sizes the number input to its actual content plus four
characters of trailing room for the spinner buttons (clamped to
6–14ch), and adds a `home-hero__prompt-slot-input--number`
modifier that overrides the slot `min-width` to 4ch. The
spinner now sits flush against the value and the slot reads as
a compact inline pill matching the surrounding text/select
slots.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): widen prompt line-height so slot pills do not collide vertically
Each interactive slot and mention in the home prompt paints a 2px
outline ring via `box-shadow`. At the previous `line-height: 1.55`
on a 15px font, two lines were ~23px apart while a single pill
occupied ~20px of vertical space (text box + ring on both sides),
leaving roughly 2px of clear space between rows. When the prompt
wrapped onto multiple lines — common for the Image template's
"Generate a {kind} of {subject}. Style: {style}. Aspect: {ratio}."
example — the rings from line N and line N+1 visually merged into
a single bar, making it ambiguous which pill the user was about to
click or edit.
This bumps the line-height of both the highlight overlay and the
underlying editable textarea to 1.85 (~28px per line), restoring
~8px of clear space between pill rows. The two values must stay
identical so the overlay glyphs continue to track the textarea
caret positions exactly; a brief comment in each rule documents
this coupling for future edits.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): paint dropdown chevron on select element with neutral color
The previous chevron treatment wrapped each select slot in an
inline-flex span and laid an accent-orange `<Icon>` over the
trailing padding. At the prompt's normal display size the orange
chevron blended into the orange pill ring corners, so users
perceived "a bunch of dropdown arrows" across every highlighted
slot, even though only the actual select rendered one.
Move the chevron onto the `<select>` itself as a small neutral-
gray `background-image` SVG. The grey contrasts clearly with the
pill's accent ring and the chevron lives inside the select's own
padding, so it can never visually overlap the value text and can
never appear on non-select slots.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): shrink select-slot dropdown caret so it stops reading as a check-mark
The 8×6 stroked chevron looked like a check-mark in zoomed views
because the stroke width was a large fraction of the glyph. Swap
for a small (9×5) filled triangle drawn as a `background-image`,
with `background-size` pinned so browsers can't scale it to its
intrinsic SVG box. The caret is now unambiguously a dropdown
indicator without crowding the value text.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): make read-only prompt slots visually distinct from editable pills
Multi-word context values are rendered as plain <span>s with
pointer-events: none, but they inherited the same orange pill +
ring treatment as the truly editable <input>/<select> slots.
Users couldn't tell which pills they could click into.
Strip the pill background, the ring, the radius, and the padding
from `.home-hero__prompt-slot-text` and replace them with a
subtle dashed bottom border. The orange foreground keeps the
slot family link, but read-only highlights now clearly read as
"context value spliced into the prompt" rather than as
"interactive control".
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): scale select-slot dropdown caret up to 12px wide for legibility
The 9×5 caret was too quiet at the prompt's font size to read as
a dropdown affordance. Bump to a 12×6 filled triangle and pad the
select's trailing space (24px) so the value text still has clear
breathing room from the caret.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): collapse plugins search and filter strips into one bar
The plugins-home gallery laid out search, count, mode (Featured),
total-in-catalog, clear-filters, the main category row, and the
sub-category row as four floating clusters. Search lived up in
the section header, far from the chips it actually scopes; the
mode strip wedged "Featured + 386 in catalog + Clear filters"
between the header and the category row with no obvious
ownership; and the two clear-filter affordances duplicated each
other (chip strip + empty-state).
Fold the mode strip into the category row: Featured is now the
leading chip on the same line as the category pills, and the
search field, the result count, and a compact Clear link sit as
a right-aligned tools cluster on that same row. The header
shrinks back to just the title, subtitle, and Browse registry
link. The sub-category row stays as the contextual second line
when a category is active.
Tests: keeps the existing data-testids (plugins-home-chip-featured,
plugins-home-row-category, plugins-home-clear, plugins-home-count,
plugins-home-search) so the existing 11-case section spec passes
without modification.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): hide Recent projects rail on first-run home when empty
A brand-new user landing on Home saw an empty dashed box with the
copy "No projects yet — type a prompt to start one." sitting
above the plugin gallery. The hero already prompts the user to
type, so the empty rail just adds vertical noise without telling
them anything new.
Return null from RecentProjectsStrip when the recent list is
empty (loading or not) so the rail appears only when there is
actually something to show. Update the entry-chrome e2e to
assert toHaveCount(0) on first run — codifying the new contract
that the rail is conditional, not always-mounted.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): hide structured inputs form when every field is in the prompt
The PluginInputsForm below the chat textarea surfaced every plugin
input — even the ones the prompt template already substitutes
inline as highlighted slot pills. For a plugin like Prototype
that's five identical labelled inputs duplicating the five slot
pills above them, making the chat box look like it has grown a
second composer.
Compute the set of placeholder keys actually referenced in the
prompt template (via INPUT_PLACEHOLDER_PATTERN) and skip those
when deciding what the structured form needs to render. The form
still appears for plugins that expose inputs not referenced in
the prompt text (e.g. a "Run in background" toggle), but
template-only plugins collapse the redundant second editor.
Update the picker spec accordingly: when every field is in the
template the form is now expected to be absent rather than to
render a duplicate of the inline slot.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): drop redundant filtered-count and Clear link beside the search
The combined plugins filter bar trailed the search field with
"59 / 386" and an inline "Clear" link, but both repeat what the
chip strip already shows: every chip carries its own count
(Slides 59, All 386, …) and clicking the All chip already resets
the filters. Users had no way to know what the bare "59 / 386"
fraction or "Clear" referred to without inference.
Strip the trailing tools cluster down to just the search input.
The empty-results message at the bottom of the gallery still
exposes a contextual "Clear filters" button when a stacked
filter yields no matches, so the affordance isn't lost — just
removed from a position where it didn't read as actionable.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): drop default subtitle copy from the Official starters strip
The Home gallery rendered a two-line explanatory subtitle under
"Official starters" — "Ready-to-use Open Design workflows bundled
with this runtime. Pick one to load a starter prompt, or browse
the registry for more." — every visit. Returning users skip it,
new users get the same message from the section title plus the
Browse registry link plus the visual card grid itself; the prose
read as filler chrome above the chip strip.
Default the subtitle prop to undefined and only render the <p>
when a caller passes an explicit string. Other surfaces that
mount PluginsHomeSection with their own copy keep their
subtitle; the bare Home gallery loses one row of vertical noise.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fade out empty workflow lanes in Plugins home filter
Empty top-level lanes (Deploy 0, Refine 0, etc.) and empty
sub-categories (Vercel 0 under Deploy, Figma 0 under Import, etc.)
used to look identical to populated ones, so users couldn't tell at
a glance which chips were real catalog buckets and which were
"contribute a plugin" invites. The strip kept all lanes visible by
design — the workflow shape (Import / Create / Export / Share /
Deploy / Refine / Extend) is part of what we want users to see —
so we keep them clickable, but tag count-zero chips with
data-empty='true' and give them a faded, dashed-border treatment.
"All" pills stay solid since their count reflects the parent lane,
not their own emptiness.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): update home nav test expectations
* fix(e2e): align critical smoke with entry chrome
---------
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
The .subtab-pill button hover rule hard-coded `rgba(255,255,255,0.6)` as the
hover background. In light theme this composites to a near-white wash that
sits cleanly under `--text`, but in dark theme it overlays a translucent
white on the dark panel and produces a bright, near-white surface beneath
the same light `--text`, dropping contrast to ~1.87 (well below WCAG AA 4.5).
The reporter (#1795, on 0.6.0) called this out on five Settings surfaces.
Four of them — BYOK / Appearance / Notifications / protocol-chip — were
incidentally fixed by the c5d77a03 dark-palette refresh because they use
the .seg-control / .seg-btn hover path, not the .subtab-pill path. The
Pet → pet source tabs (Built-in / Custom / Community) still reproduce on
0.7.0 because they use .subtab-pill, which never got a theme-aware hover.
Switch the hover background to `var(--bg-muted)`, an existing token that
mirrors `--bg-panel`'s active state shape (one step lighter than
`--bg-subtle`) and is defined per-theme. Composited contrast becomes
~9.4 in dark and ~14.3 in light against `--text`, comfortably above AA.
The same .subtab-pill rule is shared by RoutinesSection and DesignsTab, so
they pick up the fix as a side effect of fixing the source class.
Anchored by a Playwright regression test under e2e/ui/ that asserts WCAG
AA across both themes for the Pet source tabs and the seg-btn surfaces.
The test goes red on this commit's parent (Pets/dark, ratio 1.87) and
green here (all four assertions pass).
Pulls in the teammate's PR #1830 — e2e align to redesigned entry flows
+ watcher and codex runtime test fixes. Conflicts resolved:
- apps/daemon/tests/runtimes/registry-and-args.test.ts: imported both
withPlatform (HEAD, used 6x) and withEnvSnapshot (theirs, used 1x);
both helpers are needed in the file.
- apps/web/src/components/ProjectView.tsx: kept both ChatPane-remount
guards. Main's fix#1710 uses lastSyncedConversationIdRef tracking URL
sync; the teammate added lastSeenRouteConversationIdRef tracking last
observed route. Both refs are already defined in the file and the two
checks are complementary defenses.
- e2e/ui/settings-*.test.ts (5 files): took teammate's version wholesale
— they replaced inline `page.goto('/') + click Execution mode` with
`gotoEntryHome + openSettingsDialogFromEntry` helpers, which is exactly
the PR's intent.
* docs: plan linux client issue 709
* fix: complete linux headless lifecycle routing
* feat: add linux packaged inspect
* test: add linux headless packaged smoke
* ci: add linux headless packaged smoke
* ci: smoke linux AppImage release artifacts
* docs: document linux packaged client status
* chore: finalize linux client audit remediation
* docs: add linux client publication packet
* test: harden linux client smoke coverage
* ci: preserve linux smoke audit evidence
* refactor: consolidate linux e2e helpers
Move pathExists and the desktop/web/daemon app-key array out of
linux.spec.ts into linux-helpers.ts, where expectPathInside and
linuxUserHome already live. Keeps the spec file focused on tests and
the helpers file as the canonical home for shared Linux e2e utilities.
* fix: move linux e2e helpers to lib
* fix: address linux release review blockers
* fix: drop npm dependency from containerized linux build
writeAssembledApp() previously called runNpmInstall() which executed
`npm install` directly. Inside the containerized build path,
electronuserland/builder:base strips npm/npx/corepack, so the inner
tools-pack build would fail at the assembled-app install step.
Route the install through OD_TOOLS_PACK_PNPM_BIN: buildDockerArgs sets
the env to the standalone pnpm binary it bootstraps, and the new
resolveProductionInstallCommand helper consumes that env to run
`<bin> install --prod --no-lockfile --config.node-linker=hoisted`.
Host invocations with no env set keep the prior npm behavior.
--config.node-linker=hoisted preserves the flat node_modules layout
that electron-builder packs the same way as npm-installed trees.
New tests cover the resolver branches and assert the docker-arg-to-
resolver chain end-to-end so reviewers can see the container's inner
build receives the env that switches its install away from npm.
* fix: harden linux container bootstrap
* fix: validate desktop marker liveness in headless cleanup
cleanup --headless previously skipped on any parseable desktop-root.json, trapping recovery when the AppImage had crashed and left a stale marker. Validate the marker the same way stopPackedLinuxApp does: if the PID is not in the live snapshot list, proceed through cleanup instead of skipping.
Extract the validation into validateDesktopAppImageMarker so the stop and cleanup paths share one definition of live and owned. Tests cover both branches: a stale marker drives cleanup to remove the runtime/output roots, while a live marker drives cleanup to skip and preserve them.
* feat(chat-composer): enhance mention handling and input overlay
- Introduced a new overlay for inline mentions in the chat composer, improving user experience by visually indicating mentions as users type.
- Updated the `ChatComposer` component to manage mention entities and integrate them into the input field, allowing for better context and interaction.
- Enhanced the `AssistantMessage` component to support the display of plugin action panels based on the current project context, facilitating easier plugin management.
- Refactored related components to ensure consistent handling of project files and mentions across the application.
This update significantly improves the chat interaction model, making it more intuitive for users to engage with mentions and plugins.
* feat(plugin-management): enhance plugin action panels and UI components
- Updated the `AssistantMessage` component to include plugin action panels based on the latest project context, improving user interaction with generated plugins.
- Refactored the `PluginsView` to support detailed views for available marketplace entries, allowing users to access more information and actions for each plugin.
- Introduced new CSS styles for improved visual representation of plugin-related UI elements, enhancing overall user experience.
- Enhanced the `listPlugins` function to include an option for fetching hidden plugins, providing more flexibility in plugin management.
This update significantly improves the usability and functionality of the plugin management system, making it easier for users to interact with and manage their plugins.
* fix(assistant-message): refine plugin folder candidate selection logic
- Updated the `pluginFoldersTouchedThisTurn` function to improve the logic for selecting plugin folder candidates based on touched paths and message content.
- Introduced a new helper function, `pathMatchesFolderFileBasename`, to enhance the matching criteria for folder candidates.
- Added a check for explicit folder matches before falling back to a single candidate, improving accuracy in folder selection.
- Modified the `shouldRenderSlotAsText` function in `HomeHero` to include the name parameter, refining the rendering logic for slot text.
These changes enhance the functionality and reliability of the assistant message component in managing plugin folder candidates.
* feat(plugin-folder-actions): implement agent-routed CLI actions for plugin management
- Introduced a new `PluginFolderAgentAction` type to streamline actions related to plugin folders, including install, publish, and contribute.
- Updated the `DesignFilesPanel`, `FileWorkspace`, and `AssistantMessage` components to utilize the new agent action handling, improving user interaction with generated plugins.
- Refactored the action handling logic to send commands to the agent, enhancing the workflow for managing plugin folders.
- Added corresponding tests to ensure the new functionality works as expected and integrates seamlessly with existing components.
This update significantly enhances the plugin management experience by routing actions through the agent, allowing for a more cohesive and interactive user experience.
* Fix PR 1702 CI blockers
* Fix PR 1702 remaining CI checks
* Prebuild AGUI adapter after install
* Restore plugin project snapshot wiring
* feat(marketplace): refactor marketplace URL handling and enhance fetching logic
- Introduced new functions to normalize marketplace URLs and manage fetching of marketplace manifests, improving the reliability of marketplace integrations.
- Updated the server and plugin logic to utilize the new fetching mechanisms, ensuring consistent handling of marketplace data.
- Enhanced tests to cover new URL normalization and fetching scenarios, ensuring robustness in marketplace management.
This update significantly improves the marketplace experience by streamlining URL handling and enhancing data fetching capabilities.
* Fix project auto-send cleanup spec
* Reconcile run messages on cancel
* Use active design system as visual direction
* Fix active design system prompt wording
* feat(workspace-tabs): implement workspace tabs functionality and file attachment handling
- Introduced a new `WorkspaceTabsBar` component to manage workspace tabs, allowing users to navigate between different views (projects, marketplace, etc.).
- Enhanced file handling capabilities in the `HomeHero` and `EntryShell` components, enabling users to stage and attach files before project creation.
- Updated the `App` component to support auto-sending attachments alongside the first message in a project.
- Improved CSS styles for workspace tabs and attachment UI, ensuring a cohesive design and user experience.
This update significantly enhances the workspace navigation and file management features, providing users with a more intuitive and efficient workflow.
* refactor(workspace-tabs): streamline workspace tabs and UI components
- Removed unused components and actions from the `WorkspaceTabsBar` and `AppChromeHeader`, simplifying the codebase.
- Updated CSS styles for the workspace shell and tabs, enhancing visual consistency and reducing element sizes for a cleaner layout.
- Introduced a new client type detection mechanism to dynamically adjust the workspace shell's class, improving responsiveness.
- Added tests for the `WorkspaceTabsBar` to ensure proper navigation and tab management functionality.
These changes improve the overall performance and user experience of the workspace navigation system.
* Update critical e2e for entry modal flow
* Stabilize entry critical e2e flows
* fix(ui): adjust workspace tabs and header styles for improved layout
- Updated the CSS for workspace tabs and the app header, reducing element sizes and padding for a cleaner appearance.
- Introduced a new button in the `WorkspaceTabsBar` for quick access to the home tab, enhancing navigation.
- Minor adjustments to the layout and styles to ensure consistency across components.
These changes enhance the user interface and improve the overall user experience in the workspace navigation system.
* feat(workspace-tabs): implement pinned home tab functionality
- Added a new pinned home tab feature to the `WorkspaceTabsBar`, allowing the home tab to remain accessible during navigation.
- Updated tab management logic to collapse duplicate home tabs into a single pinned instance when restoring from local storage.
- Enhanced CSS styles for workspace tabs to accommodate the new pinned tab design.
- Updated tests to verify the behavior of the pinned home tab and its interaction with other tabs.
These changes improve navigation consistency and user experience within the workspace.
* refactor(workspace-tabs): enhance tab management and styling
- Updated CSS styles for workspace tabs, adjusting padding and flex properties for improved layout and consistency.
- Refactored tab creation logic to ensure unique IDs for project and marketplace tabs, enhancing navigation clarity.
- Removed deprecated functions related to pinned home tabs, streamlining the codebase.
- Improved test cases to verify independent behavior of home tabs during navigation.
These changes enhance the user experience by providing a more intuitive tab management system and a cleaner UI.
* style(workspace-tabs): update CSS for improved layout and visibility
- Adjusted CSS properties for workspace tabs, including overflow, position, and z-index to enhance layout and stacking context.
- Ensured consistent styling across tab components for better visual hierarchy.
These changes contribute to a more polished and user-friendly interface within the workspace.
* style(entry-layout): update CSS variables for improved layout consistency
- Replaced fixed width values with CSS variables for the entry rail to enhance flexibility.
- Adjusted padding and height properties for better visual alignment and spacing.
- Introduced a new background style for the entry main topbar to improve aesthetics.
These changes contribute to a more responsive and visually appealing layout in the entry view.
---------
Co-authored-by: qiongyu1999 <2694684348@qq.com>
Co-authored-by: Eli <129168833+qiongyu1999@users.noreply.github.com>
* refactor(web): rename Execution mode and tighten settings dialog UI
- Rename "Settings → Execution & model" to "Settings → Execution mode"
across the web UI, i18n keys, docs, and e2e selectors.
- Redesign SettingsDialog: kicker + title row in the modal head, a
flatMap-driven agent grid that renders the inline test-result row
beside the selected card, compact unavailable cards with right-aligned
install/docs links, and an install guide that only shows when the
user has no working agent picked.
- Trim verbose subtitle / hint copy across chat model, CLI proxy,
media providers, custom instructions, and memory sections.
- Add an `info` Icon variant for the redesigned settings hints.
- Update e2e selectors and docs that referenced the old menu label.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(web): polish Settings dialog — media providers, skills, MCP
Media providers
- Hide internal Stub fixture provider (settingsVisible: false)
- Split provider list into Available (integrated, editable) and Coming
Soon (collapsed <details> drawer with name/hint/Docs link only)
- Drop right-side Integrated/Configured badges from every row; all rows
in the main list are integrated by definition; inline grey "Saved"
chip next to the provider name is the only status indicator now
- "Saved" badge moves inline to the right of the provider name and uses
a neutral grey treatment (was a standalone green pill below the name)
- "Reload from daemon" button shows a 2s green "✓ Reloaded" flash on
success instead of leaving a permanent paragraph under the header;
errors remain sticky
Skills
- Replace three pill-row filter banks (Source, Type, Category) with a
compact single-row toolbar: search + three inline <select> dropdowns
side by side; active filter highlighted with a stronger border
MCP server
- Shorten section hint to one line
- Move WHAT YOUR AGENT CAN DO capabilities above the client dropdown
(motivate before asking to act)
- Move "Build the daemon first" warning below the code block where it
contextually explains why the command might fail, not as a top-level
error before the user has done anything
- Downgrade "Restart your client" left-border from accent orange to
border-strong grey — it is a next step, not a warning
External MCP
- Shorten section hint to one line
Misc CSS
- Add .sr-only utility for accessible off-screen live regions
- Add button.ghost.is-success-flash for transient success feedback
- Add .library-filter-selects / .library-filter-select for dropdown
filter rows
- Add .media-provider-coming-soon-* for the roadmap drawer
Co-authored-by: Cursor <cursoragent@cursor.com>
* [codex] Add Cursor Agent auth diagnostics (#1538)
* Add Cursor Agent auth diagnostics
* Handle Cursor not logged in auth status
* Address Cursor auth review feedback
* Classify Cursor stdout auth failures
* test: expand Memory and Routines coverage (#1521)
* test: expand settings and packaged coverage
* test: extend memory settings coverage
* test: cover routine settings failure states
* test: cover routine operation failures
* test: fix daemon test typing on CI
* test: decouple packaged smoke from orbit bug
* test: avoid live memory LLM calls in route tests
* test: fix daemon fetch typing in CI
* fix: restore preview comment and inspect toggles
* test: align manual edit flow with current inspector UX
* test: align comment attachment flow with current preview comments UI
* fix: probe resolved Codex launch path during detection
* fix: remove duplicate board activation helper after rebase
* test: update ghost cli detection mock
* test: align FileViewer toolbar expectation
* ci: move full app tests to extended lane
* ci: run app tests by changed scope
* ci: cover shared app inputs in test scopes
* ci: avoid setup-node cache in windows packaged smoke
* test: align extended settings and manual edit flows
* refactor(web): rename Execution mode and tighten settings dialog UI
- Rename "Settings → Execution & model" to "Settings → Execution mode"
across the web UI, i18n keys, docs, and e2e selectors.
- Redesign SettingsDialog: kicker + title row in the modal head, a
flatMap-driven agent grid that renders the inline test-result row
beside the selected card, compact unavailable cards with right-aligned
install/docs links, and an install guide that only shows when the
user has no working agent picked.
- Trim verbose subtitle / hint copy across chat model, CLI proxy,
media providers, custom instructions, and memory sections.
- Add an `info` Icon variant for the redesigned settings hints.
- Update e2e selectors and docs that referenced the old menu label.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(web): settings dialog UX polish — layout, dedup, and interactions
- Remove duplicate section headers from all settings sections
(Notifications, Appearance, Privacy, About, Design Systems, Skills,
MCP server, Connectors, Media providers, Routines)
- Restructure Notifications cards: title + toggle on same row, hint below
- Restructure Skills toolbar: search + New skill button in row 1,
filter dropdowns in row 2 with left-aligned labels
- Restructure Pet section: tabs and Wake button on same row
- MCP server: group capabilities and setup into separate cards,
remove nested double border on client picker
- Connectors: show connect errors as toast instead of inline card text,
position toast inside panel, hide single-provider tab
- Media providers: move Reload button to left-aligned small ghost button
- Memory: info icon shows path on hover, Path copied badge inline;
Extraction history and MEMORY.md as standalone collapsible cards;
group header hidden when only one type visible
- Pet grid cards: Adopt button hidden until hover, icon-only when adopted,
description truncated to 2 lines, text fills full width via abs positioning
- Agent cards: selected state uses accent border only, no background change
- Add sun/moon icons to Appearance theme buttons (Light/Dark)
- Shorten several hint strings for clarity
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): resolve i18n review comments from PR #1568
- Update settings.title and settings.envConfigure to localized
"Execution mode" in all 17 non-English locale files
- Add settings.memoryFlashPathCopied to all locales and use t()
in MemorySection instead of hardcoded English "Path copied"
- Add settings.agentModelHead to all locales and use t() in
SettingsDialog for "Model for:" agent model row header
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): update tests to match settings dialog redesign
- Add role prop to Toast (alert/status) so error toasts from
ConnectorsBrowser are announced immediately by screen readers
- Clear connectErrorToast on successful connector retry
- Update SettingsDialog.execution tests:
- Remove heading assertions for About and MCP server (headers
were intentionally removed as duplicate nav labels)
- Rewrite CLI env test to use codex-only fields (per-agent
filtering means only selected agent's fields are shown)
- Update Composio key hint text assertion to match shortened copy
- Replace filter button click with select change for Type filter
- Replace Configured/Unsupported/Integrated badge checks with
updated assertions matching the new media provider UI
- Replace disabled BFL row test with coming-soon section check
- Update SettingsDialog.media test: remove Fal.ai input assertions
(non-integrated providers no longer have editable fields)
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): unblock CI for #1568
Three small fixes to get Playwright back to green on the settings
dialog redesign:
1. `en.ts`: revert `settings.envConfigure` to "Configure execution mode".
This PR collapsed both `settings.title` (header gear) and
`settings.envConfigure` (entry-side foot pill) to the same string
"Execution mode", so `getByRole('button', { name: 'Execution mode' })`
resolved to two elements and tripped Playwright strict mode in the
three Composio-flow tests (entry-configuration-flows.test.ts:174,
228, 285). Restoring the distinct label also gives screen readers
a clearer hint for the pill, which doubles as a status display.
Non-English locales still alias the two keys; happy to follow up
on those, but they don't gate the (English-only) Playwright suite.
2. entry-configuration-flows.test.ts:167 — `Connectors` heading is now
rendered at `<h2>` in the modal-head (SettingsDialog.tsx:1545), with
the inner `<h3>` removed by design (see comment around line 1448).
Updated the assertion from `level: 3` to `level: 2`.
3. project-management-flows.test.ts:360 — same change for the `Pets`
heading.
Verified locally with `pnpm --filter @open-design/web typecheck` and
`pnpm --filter @open-design/e2e typecheck`. The actual Playwright
specs need the dev server up; I didn't rerun them here, but the
locator changes are mechanical and match the new DOM.
* fix(web): use exact match for Execution mode button locator
Playwright's `getByRole({ name })` defaults to substring matching, so
`{ name: 'Execution mode' }` still resolved to both the header gear
(aria-label "Execution mode") and the entry-side foot pill (aria-label
"Configure execution mode" — substring contains "Execution mode").
Strict mode tripped in the three composio-flow tests at lines 202,
257, and 319.
Adding `exact: true` makes each call resolve to just the header gear,
which opens the same dialog the foot pill does — the test outcomes
are unchanged.
---------
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Caprika <56862773+alchemistklk@users.noreply.github.com>
Co-authored-by: shangxinyu1 <shangxinyu@refly.ai>
Co-authored-by: lefarcen <935902669@qq.com>