mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
7840acb23d9a3f7d9692fc194d50e4a99ea5a574
2568
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7840acb23d |
[codex] Pick PR #4952 to main (#4983)
* Fix logo previews and AMR card layout (#4952)
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
(cherry picked from commit
|
||
|
|
b1d4e59003 |
feat(landing-page): strengthen the vibe-design pillar + hub-and-spoke internal links (#5003)
* feat(landing-page): strengthen the vibe-design pillar + wire hub-and-spoke links The 4 vibe-design blog posts were splitting the bare "vibe design" query across each other (GSC: 3 pages clustered at pos 5-6 in the same locale), and the pillar (what-is-vibe-design) under-competed the top-ranking guides (Visily ~2,200 words + FAQ + decision matrix; Cerence ~2,100). Upgrade what-is-vibe-design into a proper pillar: - Add a "When vibe design is the right call — and when it isn't" decision section and a 7-question FAQ (PAA / featured-snippet surface), taking the body from ~1,150 to ~1,860 words. - Complete the hub-and-spoke: the pillar now links out to all three cluster posts (vibe-design-tools, vibe-design-vs-vibe-coding, vibe-design-with-stitch) in-context, consolidating topical authority on the pillar and clarifying to search engines which page owns the head term. - Sharpen the differentiator competitors miss — prompt to shipped code, open-source, agent-native — since Visily stops at a mockup and Cerence is an interview. Follow-up: re-translate the localized bodyHtml (keep-11 locales) to match. Locale pages keep their prior full translation until then (not broken, just one version behind). * fix(landing-page): keep vibe-design readingTime aligned with translated bodies readingTime is a shared field the blog template renders for every locale. Since this PR intentionally leaves the localized bodyHtml on the shorter prior copy until the translation follow-up, keep readingTime at 6 so the 10 localized pages stay accurate; it moves to 9 in the localization PR when every body grows to match the expanded English article. * feat(landing-page): per-locale blog readingTime override A shared readingTime can't be right for both the expanded English body and the localized bodyHtml still on the shorter prior translation (reviewer: 9 overstates the localized pages, 6 understates English). Add an optional per-locale readingTime to the blog i18n schema, render it in [slug].astro when present, set the English body to 9, and pin the ten rendered locales to 6 until the localization follow-up grows their bodies. Verified: EN shows 9 min, ja/de/es show 6. * fix(landing-page): use per-locale readingTime on the blog index too The detail page honored the per-locale readingTime override, but the blog index (and its /[locale]/ wrapper) still rendered the shared English value on both the featured and regular cards. Apply the same locale-aware lookup there so non-English index cards match their article. Verified: EN index card shows 9 min, JA shows 6. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
d270b401f2 |
fix(daemon): fail OpenCode tool-only empty responses (#4835)
* fix opencode tool-only empty responses * fix reasoning-only empty responses |
||
|
|
8d83d24907 |
[codex] Keep AMR settings card actions inline (#4993)
* Keep AMR settings card actions inline * Keep AMR plan badge outside clipped benefits * Move AMR plan badge to account row * Prevent AMR benefit badges from clipping * Remove lower cost AMR badge * Rename AMR console action to manage * Carry over logo preview and AMR manage fixes |
||
|
|
3370d70144 |
fix(landing): remove AMR nav branding (#5001)
Co-authored-by: rebel-nexu-zero[bot] <rebel-nexu-zero[bot]@users.noreply.github.com> |
||
|
|
6fb5c37108 | Fix home submit handoff state (#4886) | ||
|
|
8b179ab996 |
fix(landing): reserve about-panel image aspect-ratio so the lazy-swap can't collapse (#4995)
PR #4987 tightened the homepage lazy-load margin (1500px -> 600px), so the below-the-fold about-section paintings now swap in as the user scrolls to them instead of being pre-loaded a full screen early. That exposed a latent bug: `.about-panel-img img` was `width:100%; height:auto` with no reserved ratio, so between the 1×1 placeholder and the decoded webp the box rendered as a full-width 1:1 SQUARE (~320px too tall, showing the browser's broken-image/alt glyph and overlapping the caption) before snapping to the real ratio. Reserve `aspect-ratio: 1768 / 1144` (the paintings' real dimensions) plus a faint skeleton fill. The box is correct from first paint: a clean skeleton while the webp streams, then zero layout shift when it lands. Verified on a throttled connection: loading box is 900×582 (was 900×900), CLS shift 0px, and the painting fills the box exactly on decode. |
||
|
|
e61b86b48d |
fix(web): show seven recent projects on wide home layouts (#4628)
* fix(web): show seven recent projects on wide home layouts * fix(web): remeasure recent projects row after load |
||
|
|
33f9a49c6b | fix(web): keep buttons in one row (#4785) | ||
|
|
7fa6ed2fdb |
feat(landing-page): add screenshot-to-code + AI prototype generator tool pages (#4991)
Batch 3 of the /solutions/ tool-page family (SEMrush-picked), built from
the same template as batches 1-2:
- /solutions/screenshot-to-code/ targets the "screenshot to code" intent
— drop in an image of any UI and the agent rebuilds it as clean,
component-based code. Distinct input modality from design-to-code and
figma-to-code.
- /solutions/ai-prototype-generator/ targets "ai prototype generator"
(Commercial intent, competitor long-tails vs Figma/Cursor/Penpot).
Deliberately differentiated from the existing /solutions/prototype/
use-case page: distinct H1 ("The AI prototype generator that ships
code" vs "Prototype at the speed of a prompt"), generator/tool framing,
competitor comparison, and the two pages cross-link so Google reads them
as complementary rather than duplicate.
Both reuse the .solution-page layout, ship a warm-paper hero
illustration, join the Solution dropdown + hub Tools group (now seven
generators), cross-link the cluster, breadcrumb under the /solutions/
hub, and are localized to all keep-11 locales (en/zh first-party, the
other nine Agent-translated).
Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
|
||
|
|
101a42cb0d |
perf(landing): cut homepage LCP — defer JS + below-fold art, shrink backdrops, early locale redirect (#4987)
* perf(landing): load matter-js + cobe on demand, not inlined The homepage inlined the full matter-js physics engine (~83KB) and the cobe globe runtime (~13KB) into every document, even though both are below-the-fold decorations. That shipped ~96KB of decorative JavaScript in the critical HTML to every visitor — phones and reduced-motion readers included — inflating the document the browser must download and parse before the page settles. Vendor both runtimes to public/enhancers/*.js (regenerated from node_modules on every build/dev, so they always match the installed versions) and inject each one via IntersectionObserver only when its section nears the viewport. Reduced-motion readers skip the matter-js download entirely and just get the server-rendered banner. The site still ships zero Astro-bundled / ES-module JavaScript — these are hand-vendored classic scripts injected by a runtime-created script element, so the `Verify zero external JavaScript` gate stays green. Homepage document: 358KB -> 264KB (brotli wire 94KB -> 51KB); the two runtimes now load lazily, cached immutably per versioned URL. * perf(landing): defer below-the-fold homepage art off the LCP path The Cloudflare RUM network trace showed homepage LCP (~2.4s, the hero webp) was starved of bandwidth: ~1.9MB of images — most of it below the fold — was fetched in the first ~700ms and competed with the hero for the connection. Culprits: two full-bleed section backdrops loaded via CSS `::before` (lab-stage-art 454KB, cta-bg 335KB), the Labs dock preloading ~500KB of preview stills on init, the contributor orbit building ~350KB of avatars on init, and a few raw eager <img>. Defer all of it until its section nears the viewport: - precise-lazyload gains a `data-precise-bg` mode (adds `.precise-bg-in`, which the CSS uses to gate the `::before` background-image — you can't set a pseudo-element's background from JS) and a configurable `imgRootMargin`. The homepage mounts it at 600px instead of the catalog default 1500px so its heavy art doesn't join the initial burst. - A shared `__whenNear(selector, cb)` helper gates the Labs dock (`enhanceLabSwitch`) and contributor orbit (`enhanceContributorOrbit`) init behind an IntersectionObserver. - `cta-window` gets `loading="lazy"`; the near-fold hero product shot gets `fetchpriority="low"` so the hero-bg (the LCP element) wins the pipe. Verified in a headless browser against the built site: initial requests drop 50 -> 20, the ~1.76MB of below-fold art is withheld until scrolled to (then loads on cue), CLS stays 0.001, and every enhancer still works (section backdrops paint, Labs dock switches, falling-text physics runs 23/23, globe renders, 16 contributor avatars build). * perf(landing): shrink oversized homepage backdrops to display size The two full-bleed section backdrops shipped far more pixels than they ever render: cta-bg was 2776×1554 (335KB) and lab-stage-art 2262×1358 (454KB), but both display at roughly 960px CSS — 1920px covers even a 2× retina panel. Re-encoded at 1920px wide, q82 webp: cta-bg.webp 335KB → 174KB (-48%) lab-stage-art.webp 454KB → 276KB (-39%) ~340KB saved with no visible quality loss (verified at 2× device scale — the painterly murals stay crisp). Only the pixel dimensions dropped; the quality factor is high. The homepage's gated `background-image` URLs bump their `?v=` so the immutable edge cache serves the new files immediately. * perf(landing): redirect locale from <head> so the wrong-locale first load aborts A non-English visitor hitting the English root ran the locale auto-redirect from a <script> late in <body>, so the browser had already streamed most of the document (and kicked off its head resources) before bouncing to /zh/ etc. — a wasted near-full first load. Move the auto-redirect decision to the top of <head> (first thing after the viewport/theme-color meta) so it fires as the document starts streaming and aborts the rest of the wrong-locale load. The switcher UI wiring, which needs the DOM, now defers itself to DOMContentLoaded, so it works whether the script runs in <head> (homepage) or late in <body> (other layouts). All existing guards are untouched — canonical-only pages, autoredirect-off pages, and already-localized roots still no-op, so English and crawler traffic pays only a tiny inline read. Verified: root / still redirects to /zh/ for a zh browser with no loop, and all 11 language-switcher links bind correctly post-DOMContentLoaded. |
||
|
|
b5adcc2d76 |
[codex] Add AMR sign-in to landing header (#4934)
* feat(landing): add AMR sign-in header * feat(landing): center sign-in popup, scrim the page, return home after login Improve the AMR sign-in popup flow on the landing header: - Center the vela login popup over the current window (multi-monitor aware) instead of letting the browser place it arbitrarily. - Dim the page with a focus scrim while the popup is open so it reads as a modal step; remove it on success, cancel, or timeout. - After a successful login, close the popup and return the main window to the localized Open Design homepage (in place when already there). - Fall back to a same-tab navigation when the popup is blocked. Applied to both the sub-page enhancer (header-enhancer.astro) and the homepage's inlined copy (index.astro). * fix(landing): normalize AMR home redirect --------- Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> |
||
|
|
572b87cfc4 |
Classify opaque runtime failure details (#4966)
Co-authored-by: Siri-Ray <2667192167@qq.com> |
||
|
|
da3704a331 | Polish AMR settings card (#4984) | ||
|
|
6be4e56544 |
feat(workspace): add plan mode and Excalidraw sketch flows (#4862)
* feat(daemon): add 'plan' session mode and update related functionality - Introduced a new session mode 'plan' alongside existing 'design' and 'chat' modes, allowing for editable document creation. - Updated various functions and interfaces to accommodate the new session mode, including normalization and usage in commands. - Enhanced markdown rendering capabilities by integrating micromark and its GFM extension for improved markdown processing. - Added new input types for question forms, expanding the range of user interactions. - Updated UI components to reflect changes in session modes and ensure proper handling of next steps based on the current mode. * feat(chat): integrate SessionModeToggle into ChatComposer and HomeHero - Added SessionModeToggle component to both ChatComposer and HomeHero for improved session management. - Updated HomeHero styles to accommodate the new mode switcher layout. - Adjusted countdown timer in QuestionsPanel to extend the skip countdown from 120 seconds to 10 minutes, enhancing user experience. - Added tests to ensure the countdown functionality works as expected. * feat(FileViewer): implement synchronized scrolling for Markdown editor and preview - Added functionality to synchronize scrolling between the Markdown editor and preview panes. - Introduced new types and utility functions for managing scroll behavior. - Enhanced the MarkdownViewer component to handle scroll events and maintain scroll position across different modes. - Updated the component's state management to accommodate the new scrolling features. * feat(excalidraw): integrate Excalidraw into the project - Added @excalidraw/excalidraw as a dependency in package.json. - Updated vitest configuration to include an alias for Excalidraw. - Imported Excalidraw CSS in the layout component for styling. - Modified AssistantMessage component to handle optional projectId. - Enhanced FileOpsSummary to display delete operations. - Implemented new Excalidraw scene management in SketchEditor and FileWorkspace components. - Updated MarkdownViewer to support file mentions and improved file handling. - Refactored various components to accommodate Excalidraw integration and ensure compatibility with existing features. * feat(files): improve sketch and file handoff flows * test: align post-merge expectations * chore(nix): refresh pnpm deps hash * fix(workspace): stabilize sketch persistence and ci checks * fix(workspace): address review blockers in editable files * fix(workspace): persist cleared sketch scenes * test(workspace): type sketch editor mock scene * fix(workspace): serialize sketch autosaves * fix(workspace): keep sketch save revisions current * test(e2e): stabilize project workspace smoke flows * fix(analytics): preserve plan mode for BYOK runs * test(e2e): stabilize new project rail interactions * fix(files): stop bash delete parsing at shell operators * test(e2e): stabilize ui cold-start suites * fix(viewer): preserve absolute markdown image sources * feat(workspace): preload sketches and enhance markdown save options - Added functionality to preload persisted sketches before opening the tab. - Introduced new MarkdownSaveOptions type to manage save behavior. - Updated saveMarkdownText to handle options for refreshing files and showing saving state. - Enhanced FileViewer to maintain focus and selection during metadata refresh. - Implemented a Toast component for user feedback on save and export actions. * fix(web): stabilize markdown and sketch editor polish * fix(web): finish sketch editor merge resolution * chore(nix): refresh pnpm deps hash * fix(plan): bypass discovery and stabilize markdown sync * fix(web): simplify scene retrieval in SketchEditor component * feat(web): enhance markdown viewer with auto-save functionality - Implemented passive auto-save status in the MarkdownViewer component, replacing the manual Save button with an auto-save indicator. - Introduced new hooks and state management for tracking auto-save events and displaying the last saved time. - Added support for synchronized scrolling between the markdown editor and preview. - Created a new markdown-scroll-sync module to handle scroll synchronization logic. - Updated localization files to include new strings for auto-save messages. - Added a SketchEnginePrewarm component to optimize Excalidraw loading times. * feat(web): enhance session mode toggle with cost indicators - Added cost tiers for each session mode in the SessionModeToggle component, providing users with a visual representation of usage costs. - Introduced a new ModeCostTag component to display cost information alongside session mode labels. - Updated localization files to include new keys for cost labels and notes. - Enhanced styling for cost indicators to improve user experience and clarity. - Refactored EntryShell to open the new project modal instead of creating a blank project directly from the rail. - Implemented a utility function in markdown-scroll-sync to check for vertical progression in block offsets. * feat(web): add max height adjustment for session mode description card - Introduced maxHeight prop to the ModeDescriptionCard component to control the height of the description card based on available space. - Implemented useLayoutEffect in SessionModeToggle to dynamically calculate and set the maximum height of the description card, ensuring it does not overlap with the project tab bar. - Updated tests to verify that session modes display their expected usage/cost correctly in the UI. - Enhanced localization files to include new cost-related strings for various languages. * feat(web): implement goBack function for improved navigation and update auto-open logic - Added a new `goBack` function to handle in-app navigation, allowing users to return to the previous route instead of a hardcoded destination. - Updated the `navigate` function to maintain history state for better back navigation. - Refactored auto-open logic to prioritize produced artifacts, allowing markdown files to be opened alongside HTML files. - Updated tests to cover new navigation behavior and artifact selection logic. - Enhanced localization files to include new descriptions for workspace actions. * refactor(web): remove create design system functionality and update design files panel actions - Removed the `onCreateDesignSystem` prop and associated button from the DesignFilesPanel component. - Updated the empty state actions to include a button for creating a new document via the `onPaste` function. - Adjusted tests to reflect the removal of the design system creation action and ensure the new document button is functional. - Enhanced the MarkdownViewer component by adding a placeholder for the text area and removing the header bar for a cleaner interface. - Updated localization files to include a new placeholder string for the markdown editor. * fix(web): restore markdown placeholder translations * refactor(web): streamline MarkdownViewer and enhance localization - Removed unnecessary state management and reload functionality from the MarkdownViewer component for improved performance. - Added a placeholder text for the markdown editor in multiple localization files to enhance user guidance. - Updated styles for the save state indicator in the viewer to improve visual clarity and alignment. - Adjusted tests to reflect changes in the MarkdownViewer and ensure proper functionality. * fix(web): adjust SketchEditor button size and remove shortcut hints - Reduced the icon size in the SketchEditor component from 13 to 12 for better alignment. - Updated the removeSketchMermaidShortcutHints function to also remove the submit shortcut hints from the dialog, enhancing the user interface by decluttering unnecessary elements. - Adjusted tests to verify the absence of shortcut hints in the modal after updates. * fix(web): address plan mode follow-up polish * fix(web): align ci expectations after merge * test(e2e): stabilize project workspace helpers * test(e2e): scale settings visual timeout * fix(prompts): lock ElevenLabs voice picker choices * test(e2e): pin project workspace P0 worker * test(e2e): use rail new project entry * test(e2e): relax app restoration startup waits * fix(web): limit markdown pipe escaping to tables --------- Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com> Co-authored-by: Amy <1184569493@qq.com> |
||
|
|
9923c13d9e |
feat(landing-page): add AI landing page generator + Figma-to-code tool pages (#4985)
Batch 2 of the /solutions/ai-<x>-generator/ tool-page family, built from the same template as batch 1 (breadcrumb under the /solutions/ hub, single-sourced dropdown labels, related-tools matrix): - /solutions/ai-landing-page-generator/ targets the "ai landing page generator" intent — prompt to a real, responsive landing page, then shipped code. - /solutions/figma-to-code/ targets "figma to code" with a Claude-native angle: pull frames through the Figma MCP so Claude Code / Codex read the design directly and generate component-based code, no locked-in export. Both reuse the .solution-page layout, ship a warm-paper hero illustration, join the Solution dropdown + /solutions hub Tools group, cross-link the generator cluster, and are localized to all keep-11 locales (en/zh first-party, ja/ko/de/fr/ru/es/pt-br/it/tr Agent-translated). Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
d379650dc1 |
add Instagram, LinkedIn, and Xiaohongshu to the settings social links (#4977)
The settings popover already linked X, Threads, and YouTube; add the three remaining official Open Design accounts (Instagram, LinkedIn, Xiaohongshu) as follow rows, and add matching rotating "useful info" tips in the design files panel so each account is surfaced there too. New i18n keys are fully localized across all 19 locales, and the settings_popover analytics `element` union gains follow_instagram / follow_linkedin / follow_xiaohongshu. Co-authored-by: Tuolalala <xinglige0205@gmail.com> |
||
|
|
b2512e9a7e |
ci: block direct PRs into release branches except release automation (#4982)
Colleagues have been opening PRs straight into release/vX.Y.Z (e.g. into release/v0.13.0), bypassing main + the backport flow. Add a guard workflow: on a PR opened/reopened/edited with a release/** base, if the author is not a release-automation bot (open-design-release-bot, github-actions), post a comment explaining the backport flow (merge to main, add `backport release/vX.Y.Z`) and close the PR. Closing (not a failing check) is the only real gate here: release/* branches have no required status checks and no merge queue, so a red check would not block a merge. Co-authored-by: lefarcen <ontf116@gmail.com> |
||
|
|
be701787d6 | fix(web): clarify plugin remix actions (#4969) | ||
|
|
2dfaae3d3b |
feat(landing-page): batch 6 long-form tutorials + keep-11 localization (#4976)
* feat(landing-page): upgrade 5 tutorials to long-form guides with distinct real screenshots (batch 6) Batch 6, five angles: - dylan-michael: Open Design for agencies (Apache-2.0 commercial safety + cost-managed model switching) - ai-fire-academy: restyle without rebuilding (iterate visual identity on the same content) - ai-fusion: the four content libraries (skills, systems, templates, and the auto-enforced craft layer) - nyndra: a developer's under-the-hood look (deterministic loop + architecture + BYOK proxy) - tony-xhepa: which coding agent to run it with (13+ supported, how to pick) Each tutorial gets three distinct real in-app screenshots (no two share the same set). * feat(landing-page): localize batch 6 long-form tutorials to the keep-11 locales Agent-translated long-form bodies for the 5 batch-6 tutorials into the keep-11 non-English locales. Tag + image-src parity validated per locale. Per-article shards; index now 31 articles. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
af562dee19 |
feat(landing-page): AI UI generator + design-to-code tool pages, nav/hub wiring, keep-11 localization (#4961)
* feat(landing-page): add AI wireframe generator tool page First of the /solutions/ai-X-generator tool-page family (SEO action plan P0-3; Pixelcut/Figma tool-SEO model adapted to OD). Targets the 'ai wireframe generator' cluster (480/KD38 + best ai wireframe generator 2026 590/KD8). Reuses the .solution-page layout + the real prototype-category plugin grid; hero is a public-path od-site-illustration (prompt -> wireframe -> shipped UI). New 'aiWireframeGenerator' SolutionPageKey with en + zh copy (SolutionLocaleCopy is Partial, so other locales fall back to English). Honest positioning: OD takes the wireframe to shipped code you own, not a throwaway image. astro check 0 errors. Nav dropdown entry deferred (positional label-tuple coupling) — page is reachable via sitemap + internal/related-tools links for now. * fix(landing-page): replace misleading plugin grid with text feature cards on wireframe tool page * feat(landing-page): localize related-tools matrix on wireframe tool page Move the cross-link matrix from a hardcoded English list into solution-pages-i18n (en + zh, optional related/relatedTitle fields) so the labels localize like the rest of the page and sibling generator pages can extend the list as they ship. * feat(landing-page): add AI UI generator + design-to-code tool pages Extend the /solutions/ai-<x>-generator/ tool-page family with two more SEO tool pages built from the wireframe-generator template: - /solutions/ai-ui-generator/ targets the "ai ui generator" intent — prompt to a real, component-based UI, then shipped code. - /solutions/design-to-code/ targets the "design to code" / "ai design to code" intent, keyword-mapped against the /blog/design-to-code-tools listicle (blog owns "best ... tools", the tool page owns the tool intent). Each reuses the .solution-page layout, ships en + zh first-party copy (other locales fall back to English), a warm-paper hero illustration, and a localized related-tools matrix that cross-links the three generators so they form an interlinked cluster. Follow-up: surface the Tools group in the /solutions hub and the header dropdown (all-locale CommonCopy keys). * feat(landing-page): surface AI generator tool pages in solutions nav + hub Add a Tools group to the Solution dropdown and the /solutions hub so the three generator pages (AI wireframe / AI UI / design-to-code) have real inbound links from sitewide navigation, not just sitemap + cross-links. - HeaderProductMenuCopy gains a tools label + a toolItems tuple, translated across all 18 landing locales (fixed-length tuple keeps missing translations visible at typecheck time). - Header dropdown renders Tools as the first group, ahead of Use cases and Roles. - The /solutions hub renders a matching Tools section, sourcing its heading from the product-menu copy and feeding the cards into the CollectionPage ItemList JSON-LD. * feat(landing-page): localize the three tool pages to the keep-11 locales The AI wireframe / AI UI / design-to-code tool pages shipped with en + zh body copy and fell back to English for the other rendered locales, which read as half-translated next to the fully-localized site chrome. Add full, Agent-translated body copy for the remaining keep-11 locales (ja, ko, de, fr, ru, es, pt-br, it, tr), matching each locale's existing solution-page terminology and tone. hrefs/thumbs and proper nouns are preserved verbatim. * fix(landing-page): single-source tool dropdown labels from solution-page copy The Solution dropdown read tool names from HeaderProductMenuCopy.toolItems while the hub cards read them from the solution-page breadcrumb, and the two had already drifted in Japanese (per review). Drop toolItems entirely and derive the dropdown labels from getSolutionPageCopy(locale, key).breadcrumb so the nav and the hub share one translation source and cannot diverge. * fix(landing-page): breadcrumb the tool pages under the /solutions/ hub This PR wires /solutions/ into the header dropdown and hub cards as a real parent for the three generator pages, but the leaf breadcrumbs and their BreadcrumbList schema still flattened to Open Design -> <page>. Insert a localized /solutions/ middle item in both the rendered <nav> and the JSON-LD on all three tool pages so the trail matches the navigable hierarchy. Label comes from header.nav.solution (already localized). --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
56c410e9ef |
[codex] strengthen daemon diagnostics coverage (#4948)
* test: expand automation coverage gaps * test: cover additional automation gaps * test: strengthen daemon diagnostics coverage * fix(e2e): align media provider project modal helper |
||
|
|
7d74775340 |
fix(web): restore Settings updater status controls (#4946)
* fix: improve settings update checks * fix: remove update state preview * fix(web): enable settings updater downloads * fix(web): install downloaded payload updates * fix(web): retry updater quit from settings --------- Co-authored-by: Mason <jinmeihong0201@gmail.com> Co-authored-by: rebel-nexu-zero[bot] <rebel-nexu-zero[bot]@users.noreply.github.com> |
||
|
|
faa0ed23b7 |
feat(landing-page): batch 5 long-form tutorials + keep-11 localization (#4967)
* feat(landing-page): upgrade 5 tutorials to long-form guides with distinct real screenshots (batch 5) Batch 5, five distinct non-cannibalizing angles: - ai-teaches-better: the 6-layer anti-slop quality engine - compile-future: turn a reference image (Dribbble shot) into a real page, free via Gemini - justyn: same-prompt head-to-head vs Claude Design + multi-variation - eli-rigobeli: make slide decks from a video/article, on free credits (title rewritten from Portuguese) - better-stack: why even a budget model designs well (design systems + skills carry it) Each tutorial gets three distinct, angle-relevant real in-app screenshots (no two share the same set). * feat(landing-page): localize batch 5 long-form tutorials to the keep-11 locales Agent-translated long-form bodies for the 5 batch-5 tutorials into the keep-11 non-English locales (zh, ja, ko, de, fr, ru, es, pt-br, it, tr). Tag + image-src parity validated per locale. Per-article shards; index now 26 articles. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
ca89845d03 |
feat(brands): surface the draft design system live and browse images in a lightbox (#4777)
* feat(brand-extraction): enhance programmatic extraction with reconciliation and UI improvements - Introduced `reconcileProgrammaticExtractionTranscript` to manage the state of brand extraction transcripts, ensuring accurate status updates during extraction processes. - Updated the `cancel-extraction` route to handle asynchronous operations, allowing for better user feedback and immediate reconciliation of extraction states. - Enhanced the `startBrandExtraction` function to support draft design system creation, ensuring that users can see their systems immediately, even if extraction fails or is stopped. - Improved error handling and logging for reconciliation processes, providing clearer insights into failures during brand extraction. - Added tests to validate the new reconciliation logic and ensure that the extraction process behaves as expected under various scenarios. These changes improve the overall user experience by providing more robust handling of brand extraction states and enhancing the visibility of the extraction process. * feat(brand-extraction): enhance brand preview rendering and UI feedback - Added functionality to render brand previews into projects when a draft is stopped, improving user experience by providing immediate visual feedback. - Updated the `startBrandExtraction` function to include metadata for design system IDs and statuses, ensuring accurate tracking of brand extraction states. - Enhanced the `renderBrandPreviewIntoProject` function to support new status types, including 'draft', allowing for better representation of brand states. - Introduced new localization strings for draft-related messages, improving clarity for users during the brand extraction process. - Added tests to validate the new preview rendering and status handling, ensuring robustness in the brand extraction workflow. These changes improve the overall user experience by providing clearer feedback and enhancing the visibility of brand extraction processes. * feat(design-kit): browse design-system images in a lightbox carousel The image-preview lightbox showed a single static image with no way to move between samples. Replace the single-image state with an index into the visible, non-broken samples so the modal becomes a carousel: prev/next chevrons, an "N / total" counter, ArrowLeft/ArrowRight keys, and wrap-around. Broken tiles are filtered once through a shared lightboxItems memo so the gallery and lightbox indices stay aligned with the delete handler. * feat(brands): reveal the draft design system the moment extraction starts A brand extraction pre-creates a draft `user:` design system, but the project view only rendered it once the registry summary had refreshed, leaving the Design System tab empty for the whole extraction. Build a fallback summary from project metadata so the draft renders immediately, auto-open the Design System tab when extraction begins or is cancelled, and hydrate the freshly created project with its brand metadata. Draft pre-create now records the source URL in provenance and fails loudly instead of swallowing the error. Because ProjectView imports DESIGN_SYSTEM_TAB at module scope, every FileWorkspace test mock must export the constant. * fix(design-system-picker): restore fullscreen preview styles dropped in routines.css reorg The brand-extraction routines.css reorganization accidentally removed the `.project-ds-picker-fullscreen` rule block, its `project-ds-picker-fullscreen-in` keyframes, and its responsive overrides. The modal-window drag guard and two style specs still depend on those rules (the fullscreen design-system preview must stay above modal chrome), so they went red. Restore the block verbatim to match main. * feat(brand-extraction): add continue extraction functionality for incomplete brands - Introduced a new API endpoint to restart the deterministic programmatic extraction for existing brands without creating duplicates. - Implemented a tracking mechanism for ongoing extractions to manage their state effectively. - Enhanced the UI components to support the new continue extraction action, including loading states and callbacks. - Updated relevant tests to ensure the new functionality works as expected and integrates smoothly with existing workflows. These changes improve the user experience by allowing users to resume brand extractions seamlessly, enhancing the overall efficiency of the brand management process. * feat(skills): integrate skill management into the application - Added a new SkillDetailsModal component to display detailed information about skills. - Enhanced the ChatComposer and HomeHero components to support skill selection and details viewing. - Updated the ComposerPlusMenu to include a skills submenu, allowing users to search and pick skills. - Implemented functionality to handle skill details in various components, improving user interaction with skills. - Refactored existing components to accommodate skill-related features, ensuring a cohesive user experience. These changes enhance the application's capabilities by providing users with better access to skill information and management, streamlining workflows involving skills. * feat(brand-extraction): improve brand assistant message handling and UI feedback - Enhanced the AssistantMessage component to better manage events and display content, ensuring that messages are rendered correctly based on their content and events. - Updated the ChatPane component to hide empty brand assistant messages and improve the visibility of relevant content, enhancing user experience during brand extraction processes. - Introduced new utility functions to determine the visibility of brand assistant events and content, streamlining the logic for displaying messages. - Refactored the ProjectView component to handle brand browser assist confirmations more effectively, ensuring that the UI responds appropriately to user interactions. - Added tests to validate the new message handling logic and ensure that brand extraction messages are displayed correctly. These changes enhance the overall user experience by providing clearer feedback and improving the management of brand assistant messages during extraction workflows. * fix(brands): address browser assist review blockers * fix(web): restore new project modal entrypoints * fix(web): switch to replacement brand retry conversations * fix(web): restore skill-change preview invalidation * fix(brand): harden retry completion flow * fix(brand): close extraction lifecycle races * test(e2e): wait for privacy banner dismissal * fix(brand): guard retry startup races * fix(brand): isolate extraction retry attempts * fix(design-systems): clean up partial draft creation * fix(brands): let stop supersede stalled transcript * fix(brands): fail thin browser html retries * fix(brands): preserve stopped html retries * fix(brands): reject off-path browser retries * fix(brands): expose deterministic retry in cli * fix(brands): serialize cancel with finalization * fix(brands): bound cancel settlement wait * fix(brands): bound retry takeover waits * refactor(next-step-actions): replace titles with localized keys and update related prompts * fix(brands): retry after browser read failures * fix(brands): accept canonical browser redirects * fix(brands): reset retry assist stall timer * test(web): align picker compact preview assertions * fix(brands): harden design kit cleanup paths * test(e2e): stabilize AMR runtime recovery checks * feat(brands): enhance brand extraction from post-wall pages - Introduced `browserHarvestIsUnusable` function to determine if a harvested page lacks usable brand signals, allowing for more permissive extraction from content-rich pages that may embed anti-bot widgets. - Updated `extractBrandFromHtml` to utilize the new function, ensuring that valid post-wall pages are processed correctly. - Enhanced `isChallengePage` to differentiate between genuine content-rich pages and bot protection interstitials, improving the accuracy of brand extraction. - Added tests to validate the new behavior, ensuring that pages with minimal color palettes or embedded widgets are handled appropriately. * feat(brands): improve handling of recoverable extraction states - Refactored brand extraction logic to maintain a `needs_input` status for recoverable scenarios, such as blocked pages or mid-load content, instead of marking them as `failed`. - Updated related functions and routes to reflect this change, ensuring that the user interface presents a calm, retryable state rather than a terminal failure. - Enhanced tests to validate the new behavior, confirming that the system correctly identifies and manages recoverable extraction attempts. * feat(projects): add design-system project creation from existing projects - Implemented a new command `od project create-design-system` to duplicate a regular project as a design-system workspace, including a prompt for design-system generation. - Enhanced the API to support the creation of design-system projects, ensuring proper metadata and file copying from the source project. - Added a detailed prompt structure for the design-system generation process, outlining requirements and expected outputs. - Introduced tests to validate the new functionality, ensuring that design-system projects are created correctly with the appropriate context and files. - Updated the UI components to integrate the new design-system creation functionality, allowing users to initiate the process seamlessly. * feat(projects): add project duplication workflow * fix(brand): keep browser assist recovery retryable * fix(plugins): roll back failed template duplicates * feat(brand): enhance browser assist functionality and improve user guidance - Introduced a new `brandBrowserAssistOdCard` function to generate browser assist cards for better user interaction. - Updated the content structure in `reconcileProgrammaticExtractionTranscript` to include browser assist cards when applicable. - Enhanced user guidance in error messages for stalled and stopped extraction processes, providing clearer instructions for recovery actions. - Added tests to ensure the new browser assist card functionality is correctly integrated and displayed in the chat interface. - Improved localization for various user prompts and messages related to browser assist actions. * feat(design-browser): enhance design file handling and user notifications - Added support for opening design files directly from the status message in the DesignBrowserPanel. - Introduced a new `actionTarget` property to differentiate between design files and regular files in status messages. - Implemented a `stopLoading` function to halt page loading when necessary, improving user experience during snapshot captures. - Updated localization files to include new status messages and project type labels. - Enhanced toast notifications for browser snapshots with improved styling and functionality. - Added tests to ensure new features work as expected and do not interfere with existing functionality. * feat(app): implement design system project creation with preset prompts - Updated project creation logic to route through the default design router, ensuring user interaction prompts for design system selection. - Introduced a new localization key for the design system creation prompt, enhancing user guidance. - Adjusted plugin ID to avoid assumptions about prototypes, improving the flexibility of project creation. - Updated tests to reflect changes in project creation behavior and ensure correct routing and prompt handling. * feat(chat): update icon sizes and implement draft persistence in HomeView - Increased icon sizes in ChatComposer from 13px to 16px for better visibility. - Added localStorage persistence for the Home composer prompt and design system selection to retain user input across tab switches. - Implemented functions to read and write drafts to localStorage, ensuring a seamless user experience. - Cleared drafts upon run creation to prevent reappearance of previous inputs. - Enhanced Toast component to handle auto-dismissal correctly, even with changing parent components. * fix(pr): address review blockers * fix(web): preserve authoring prompt confirmation * test(daemon): cover project CLI copy commands * fix(web): surface skill detail load failures |
||
|
|
6c424f4ad5 |
fix(release): populate github.commit in prerelease metadata so the changelog has a baseline (#4960)
The Feishu release card (notify-release-feishu.yml) builds its changelog as `git log <previous>..<current>`, reading <previous> from the published prerelease/latest/metadata.json `.github.commit`. That field is written by githubInfo(), which reads the RELEASE_COMMIT env. release-beta sets RELEASE_COMMIT on every build + publish job; release-prerelease set it on none, so every prerelease published an empty github.commit. Each prerelease then found no baseline and the card always rendered "首个 Prerelease 包,无上个版本可 对比" — the changelog was permanently empty, not just for a fresh release line. Add RELEASE_COMMIT to the four prerelease build jobs and the publish job, mirroring release-beta. Both are required: publish-metadata rejects a per-platform manifest whose github.commit disagrees with the metadata commit, so the build jobs (which write per-platform manifests) and the publish job (which writes the final metadata.json) must stamp the same built commit. Red spec in packaged-smoke-workflow.test.ts asserts each prerelease build + publish job carries RELEASE_COMMIT (red on main, green here). |
||
|
|
41c3b8fe0c |
fix(daemon): normalize additive cache usage so cache-hit ratio never exceeds 1 (#4903)
The first-call and aggregate cache-hit ratios assumed every `openai` usage source folds the cache-read subset into `input_tokens` (cached ⊆ input). That holds for OpenAI chat-completions and codex's rollout, but the Responses-API / ACP usage the AMR/vela and pi streams emit reports `input_tokens` as the UNCACHED remainder with cache-read tokens reported separately on top, so cache_read > input. Dividing cache_read by that too-small denominator pushed cache_hit_ratio and first_call_cache_hit_ratio far above 1.0 (~78% of AMR and ~57% of pi follow-up run_finished events) and collapsed uncached_input_tokens to 0. Resolve effective-input through one shared helper that detects the additive shape from a hard arithmetic invariant — a cache-read subset can never exceed the total it is a subset of, so cache_read > input proves the payload is additive — and folds cache-read/creation into the denominator (anthropic semantics). Every cache_read <= input payload stays byte-identical; only the previously-corrupt additive case is repaired. Red spec asserts the AMR-shaped additive event yields ratio <= 1 (was 4.7) and uncached == input (was 0), plus an inclusive-OpenAI guard so codex/openai do not regress. |
||
|
|
6083517588 |
feat(landing-page): batch 4 long-form tutorials + keep-11 localization (#4941)
* feat(landing-page): upgrade 5 tutorials to long-form guides with distinct real screenshots (batch 4) Batch 4 converts five thin tutorial entries into original long-form guides, each from a distinct, non-cannibalizing angle: - iishny: an honest first look (bugs, fixes, wiring any model via OpenRouter) - 01coder: from prompt to live URL — edit, inspect, one-click deploy (Vercel/Cloudflare) - panda: five end-to-end workflows that chain skills into real pipelines - chase: Open Design's open-source lineage and where it fits in the OSS toolbox - where-do-i-click: the absolute-beginner guide — install on your PC, build your first page Each tutorial gets three distinct, angle-relevant real in-app screenshots (no two tutorials share the same set), reusing the captured Open Design app shots. * feat(landing-page): localize batch 4 long-form tutorials to the keep-11 locales Agent-translated long-form bodies for the 5 batch-4 tutorials into the keep-11 non-English locales (zh, ja, ko, de, fr, ru, es, pt-br, it, tr). Each preserves the English HTML structure exactly (validate-i18n.py: tag + image-src parity). One per-article shard each under app/_data/tutorials-longform/; index now 21 articles. * fix(landing-page): strip trailing whitespace in where-do-i-click tutorial * fix(landing-page): make localized intros language-neutral (drop 'rewritten in English') For the two non-English-source tutorials (first-look-community, 01coder), the localized long-form intros translated the English-source clause 'rewritten in English', so non-English readers saw a page in their language claiming it was rewritten in English. Replace the localized intro paragraph with a language-neutral phrasing in each of the keep-11 non-English locales; the English Markdown source is unchanged. Addresses Looper's non-blocking review note on #4941. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
2d194b24a6 |
feat(landing-page): localized /pricing/ page synced with the cloud subscription modal (#4933)
* feat(landing-page): add localized /pricing/ page synced with the cloud subscription modal Adds a Pricing entry to the top nav and a new /pricing/ page that mirrors the Open Design Cloud (vela) subscription modal: three-tier plan cards (Plus/Pro/Max) with the plan wordmark logos, monthly/yearly toggle, first-month / yearly-discount pricing, model-credit and design-task metrics, the customer story, the FAQ, and the Team/enterprise banner. - Plan numbers come from a baked snapshot and are reconciled at runtime from the cloud's published plans.json, so a price change in the cloud reflects here with no landing-page rebuild. - All visible copy is localized for en/zh/zh-tw/ja/ko/de/fr/ru/es/pt-br (mirrored from the cloud), with English fallback for other locales; the nav label is translated across all landing locales. - Subscribe CTAs deep-link into the cloud console with the selected tier+interval and checkout=auto, so checkout starts in the cloud (auth-gated) and returns to the console on success. * fix(landing-page): address pricing review feedback --------- Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> |
||
|
|
e75cb416fc |
[codex] Add BYOK provider presets (#4902)
* Add BYOK provider presets * Fix BYOK preset picker accessibility names Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Hide unsupported Bedrock BYOK preset Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Restore BYOK preset test coverage Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Restore BYOK protocol fallback coverage Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Hide Bedrock from BYOK protocol tabs Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Downgrade unsupported Bedrock chat configs Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Clear Bedrock secrets during config downgrade Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Scrub nested Bedrock config on downgrade Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Persist Bedrock config downgrade migration Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Disable MiMo model discovery fetch Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Tighten Bedrock runtime URL detection Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Scope BYOK key drafts to provider presets Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Preserve BYOK provider form drafts Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Filter BYOK media models from chat discovery Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Fix BYOK provider draft persistence Generated-By: looper 0.9.11 (runner=fixer, agent=codex) * Fix BYOK account model load status * Fix BYOK provider status coverage --------- Co-authored-by: Siri-Ray <2667192167@qq.com> Co-authored-by: Looper <looper@noreply.github.com> |
||
|
|
365553fc5d |
[codex] Fix deck keyboard double-step navigation (#4897)
* fix deck keyboard double navigation * fix deck slide handler detection Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Defer deck bridge slide fallback Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Fix self-handling deck navigation fixture Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Keep deck bridge fallback synchronous Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * Preserve synchronous deck bridge fallback Generated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex) * fix deck bridge constant slide handlers * fix deck bridge stopped-handler state sync * Fix focused deck keyboard double navigation --------- Co-authored-by: Siri-Ray <2667192167@qq.com> Co-authored-by: Looper <looper@noreply.github.com> |
||
|
|
3a8461f25b |
Fix onboarding language menu placement (#4939)
Co-authored-by: Siri-Ray <2667192167@qq.com> |
||
|
|
bf14f80d70 |
feat(landing-page): how to use Claude Code for frontend design (how-to, i18n) (#4938)
* feat(landing-page): add 'how to use Claude Code for frontend design' how-to with full i18n SEO content engine (action plan P0-1 follow-on). Targets the high-volume on-brand term 'how to use claude code for frontend design' (~1900/KD20). A genuine how-to: install the official frontend-design plugin, prompt with aesthetic direction not pixels, guide design dimensions, iterate, then move from a one-off screen to an ownable design system (where OD fits, disclosed). Cites the official anthropics/claude-code frontend-design plugin (external authority link). Full 10-locale i18n (zh/ja/ko/de/fr/ru/es/pt-br/it/tr), structurally audited (h3/internal+external link/href parity). astro check 0 errors. Warm editorial cover. * fix(landing-page): fully localize Turkish install step (drop leaked English 'Type') nettee review: the tr bodyHtml rendered 'Type <code>/plugin</code> yazın.' mixing English and Turkish. Removed the English 'Type' so it reads natively as '<code>/plugin</code> yazın.' --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
3fb3e3ca4a |
ci(release): finalize-release — bump main + drop backport label after a stable ships (#4936)
* ci(release): finalize-release — bump main + drop backport label after a stable ships * ci(release): arm merge queue + request core-maintainer review on the bump PR main enforces require_code_owner_review and the bump touches CODEOWNERS-owned release manifests, so a bot approval can't merge it hands-free (unlike backport-automerge / bake-plugin-previews-automerge, whose targets/diffs avoid code-owner review). Open the PR, arm the squash merge queue (gh pr merge --auto, proven on main by bake-plugin-previews-automerge), and request the @nexu-io/core-maintainers review that the code-owner rule needs. * ci(release): trigger finalize via workflow_run, not release:published release-stable.yml promotes its own draft to published with gh release edit using GITHUB_TOKEN, and a release event minted by GITHUB_TOKEN does not trigger other workflows — so a release:published trigger would never fire. React to release-stable completing instead (the backport-automerge / bake pattern), and gate on the open-design-vX.Y.Z release actually being published (draft=false) so dry-runs (metadata/prepublish) correctly no-op. * ci(release): resolve version from latest published release, not head_branch PerishCode review (blocking): release-stable supports building one ref while dispatched from another via its `ref` input, so workflow_run.head_branch can be the dispatch ref, not the built release branch — parsing it would miss-fire or read the wrong version. Read the version from the latest published release instead (release-stable marks it --latest), which is branch-independent. Drop the head_branch job-if guard; the draft/prerelease/X.Y.Z guards + bump idempotency keep dry-runs a clean no-op. * test(release): pin finalize-release workflow topology PerishCode review (blocking): .github/AGENTS.md asks cross-workflow behavior changes to update the topology tests, not rely on YAML review alone. Add a focused [P2] test in packaged-smoke-workflow.test.ts (alongside the backport / bake automerge coverage) that pins finalize-release's trusted-consumer contract: workflows: [release-stable] + success/dispatch gating, App-token use, version resolved via gh release view (latest/tag) with NO workflow_run.head_branch dependency, draft/prerelease/X.Y.Z + skip handling, forward-only synchronized bump, core-maintainer review request, and SHA-pinned merge-queue arming. --------- Co-authored-by: lefarcen <ontf116@gmail.com> |
||
|
|
1d83115fd4 |
chore(plugin-previews): refresh baked preview manifest (#4905)
Co-authored-by: open-design-bot <bot@open-design.ai> |
||
|
|
faa990c253 |
feat(landing-page): AI design agents + AI prototyping tools listicles (i18n) (#4935)
* feat(landing-page): add AI design agents + AI prototyping tools listicles with full i18n Listicle engine batch 4 (SEO action plan P0-1/B1), reaching the 8-piece target low end: - ai-design-agents — targets the 'ai design agents' cluster (110/KD18); OD's own category. Honest three-way split (creative production / task agents / agent-native design-to-code), scoping out 'design agencies' and image/video gen noise; OD leads the agent-native category. - ai-prototyping-tools — targets 'best ai prototyping tools' (action-plan target topic); grouped by throwaway-vs-becomes-the-product, OD as the agent-native prototype-to-shipped pipeline. Each: scorecard table, FAQ, internal-link hub, warm editorial cover, full 10-locale i18n (zh/ja/ko/de/fr/ru/es/pt-br/it/tr) structurally audited (h3/link/href parity). astro check 0 errors. OD positioned as the agent-native / ownership option, never a cheap clone. * fix(landing-page): correct malformed </em> tag in ja prototyping post nettee review: the ja bodyHtml had a closing tag with a trailing space (</em >), which ships as raw invalid HTML since bodyHtml is injected directly. Normalized to </em>. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
bb3d826c69 |
Refine Open Design CLI picker controls (#4928)
Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com> |
||
|
|
231cf67fa4 |
feat(landing-page): batch 3 long-form tutorials with distinct screenshots + keep-11 localization (#4924)
* feat(landing-page): upgrade 5 tutorials to long-form guides with distinct real screenshots (batch 3) Batch 3 converts five thin tutorial entries into original long-form guides, each from a distinct, non-cannibalizing angle: - design-engine (Codedigipt): pick/swap the model behind it - self-hosted (AI Stack Engineer): architecture, self-host, BYOK layers - aicodeking: team workflow — versioned skills + brand DESIGN.md + anti-slop - brendan (O'Connell): design from your existing brand (agent scrapes your site) - roy-shavit: design without burning tokens (title rewritten from Hebrew) Screenshots: instead of reusing one shared trio across every tutorial (the prior batches' pattern), each tutorial gets three distinct, angle-relevant real in-app screenshots captured from the running Open Design app (workspace, slide deck, motion gallery, plugins hub, plugin library, a generated prototype), so adjacent tutorials no longer look identical. * feat(landing-page): localize batch 3 long-form tutorials to the keep-11 locales Agent-translated long-form bodies (title + summary + bodyHtml) for the 5 batch-3 tutorials into the keep-11 non-English locales (zh, ja, ko, de, fr, ru, es, pt-br, it, tr), including the per-tutorial distinct image captions. Each preserves the English HTML structure exactly (validate-i18n.py: per-locale tag + image-src parity). One per-article shard each under app/_data/tutorials-longform/, merged by the index (now 16 articles). * fix(landing-page): restore blog posts dropped by stale worktree base The batch-3 branch was cut from an older worktree state that predated four blog posts (best-ai-design-tools, bolt-new-alternatives, design-to-code-tools, lovable-alternatives) and a blog index update now on main. Those files were unintentionally carried as deletions. Restore them verbatim from main so this PR only changes tutorials + their i18n. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
f63916961d |
Use JPG social image for meetup blog card (#4920)
Co-authored-by: tuolaji <tuola@tuolajideMacBook-Air.local> |
||
|
|
a25f246551 |
feat(landing-page): add figma + v0 alternatives listicles with full i18n (#4925)
Listicle engine batch 3 (SEO action plan P0-1/B1): - figma-alternatives — targets 'figma alternatives' cluster (1000/KD21); honest two-camp map (open-source canvas / native / AI-native), holds the red line — explicitly does NOT claim to replace Figma's multiplayer canvas; keyword-mapped vs /alternatives/figma/ + existing figma-alternative-open-design blog - v0-alternatives — targets 'v0 alternative' cluster (140/KD12); completes the bolt/lovable/v0 alternatives trio, grouped by why you leave (pricing/scope/own) Each: scorecard table, FAQ, internal-link hub, warm editorial cover, full 10-locale i18n (zh/ja/ko/de/fr/ru/es/pt-br/it/tr) structurally audited (h3/link/href parity). astro check 0 errors. OD positioned as agent-native / ownership entry, never a cheap clone. Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
b0b1bd2cdd |
feat(landing-page): content listicle engine — first 4 SEO listicles (i18n) (#4921)
* feat(landing-page): add best AI design tools 2026 listicle First post of the content listicle engine (SEO action plan P0-1/B1). Targets the commercial 'best ai design tools 2026' cluster (590 vol / KD22) plus gettable secondaries (ui/ux, product, ux design designer queries, KD13-37), deliberately scoped to digital UI/UX/web design. Differentiation vs the ranking-farm competitors: names the agent-native / open category every other roundup omits (Open Design + Onlook), adds a ship/ownership decision lens and scorecard table, and an honest 'when not to' section. Open Design leads the agent-native category honestly without being demoted to a cheap alternative; the post is an internal-link hub into /alternatives/* and /solutions/*. English-first per the content rule for new listicle pages; localization follows once it proves out. Warm editorial cover matches the recent blog set. * feat(landing-page): localize best AI design tools listicle to 10 locales Adds zh/ja/ko/de/fr/ru/es/pt-br/it/tr i18n (title, summary, category, bodyHtml) matching the current canonical keep-set used by the latest posts. Each locale verified: 9 H2 + 6 H3 + table + 17 list items + 13 internal links with identical hrefs; astro check 0 errors. * feat(landing-page): add 3 more listicle posts with full i18n Listicle engine batch 2 (SEO action plan P0-1/B1): - bolt-new-alternatives — targets 'bolt.new alternative' cluster (1600/KD8) - design-to-code-tools — targets 'design to code tools' cluster (260/KD22), most on-brand - lovable-alternatives — targets 'lovable alternatives' cluster (480/KD17) Each: honest roundup grouped by intent, OD as the agent-native/ownership entry (never demoted to a cheap clone), scorecard table, FAQ, internal-link hub into /alternatives + /solutions, warm editorial cover, and full 10-locale i18n (zh/ja/ko/de/fr/ru/es/pt-br/it/tr) — structurally audited (h3/link/href parity per locale). astro check 0 errors. English-first keyword mapping keeps the plural-roundup listicles distinct from the 1:1 /alternatives/ pages. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
3a0ff032f4 |
feat(landing-page): batch 2 long-form tutorials + localize batch 1+2 to the keep-11 locales (#4915)
* feat(landing-page): upgrade 5 tutorials to long-form guides + real app screenshots (batch 2) Batch 2 of converting thin thumbnail+one-line tutorial entries into full, indexable, original long-form guides, each from a distinct angle so they don't cannibalize: - vs-figma (Anton Larichev): where an agent-native workspace fits next to Figma - vibe-coders (Sean Kochel): the vibe-coding build loop across 3 surfaces - skills-systems (Popular AI Tools): plugin library, discovery form, anti-slop gate - migrate-jack (Jack Roberts): migrating off Claude Design's limits, model-switching - feature-tour (硅基麻辣拌): full capability sweep — PPT, image, prototype, motion, video, pet Content only: overwrites 5 existing tutorial .md bodies (frontmatter preserved, summaries sharpened, Russian/Chinese titles rewritten to English) and adds the shared real-app screenshot set per slug. Reuses the long-form .tut-body render already on main. English-first; non-English locales keep their generic fallback. * feat(landing-page): localize batch 1 + batch 2 long-form tutorials to the keep-11 locales Adds real Agent-translated long-form bodies (title + summary + bodyHtml) for all 10 batch-1 and batch-2 tutorials into the keep-11 non-English locales (zh, ja, ko, de, fr, ru, es, pt-br, it, tr). Before this, those pages fell back to the generic English placeholder for non-English visitors; now each renders a fully localized article with hreflang already emitted by the page. Each translation preserves the English HTML structure exactly (validated by the od-video-tutorial validate-i18n.py: tag counts + image src parity per locale) and keeps brand / CLI / command names and code blocks verbatim. Because 11 articles x 10 locales would push the single i18n store past the 1 MiB CI blob guard, the store is split into per-article shards under app/_data/tutorials-longform/<slug>.ts, merged by the tutorials-longform-i18n.ts index (keeps getLocalizedTutorial's signature, so the page import is unchanged). The pilot (open-design-in-20-minutes) is relocated into a shard unchanged. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
3652fb7237 |
[codex] restore AMR wallet balance follow-ups (#4771)
* feat: show AMR wallet balance * fix: preserve AMR wallet reauth state * chore: retrigger PR validation * fix: bound AMR wallet balance fetch * chore: retrigger wallet validation * chore: bump bundled Vela CLI to 0.0.18 * chore: retrigger Vela CLI validation * chore(nix): refresh pnpm deps hash * feat(web): reposition AMR as Open Design's cloud subscription (#4684) * feat(web): reposition AMR as Open Design's cloud subscription Fold the standalone "AMR" product into Open Design's own cloud service: unify all user-facing copy, surface the signed-in account's plan + wallet balance, and add upgrade CTAs. - Copy: user-facing "AMR" / "Open Design AMR" -> "Open Design" across 19 locales, agent labels, and daemon error strings (balance/recharge wording preserved). - Account: daemon reads plan + balance via `vela billing summary` (CLI route, control-key) and injects them into the vela status; web shows plan + balance on the settings card, the model-switcher account row, and the runtime-switcher avatar row (balance field aligned with the console wallet's headline balanceUsd). - Upgrade: filled "Upgrade" CTA next to the plan on all three surfaces when the tier is below max; opens the console wallet at ?view=plans. - Runtime-switcher Open Design row restructured to carry account info inline, with a selected-state highlight. - Analytics: new amr_entry elements settings_amr_upgrade / inline_amr_upgrade / avatar_amr_upgrade / avatar_amr_agent_card. - specs/: design doc for the Open Design account/avatar direction. * fix(daemon): surface live account for env-backed auth + isolate cache per credential Address @nettee review on #4684: - applyVelaLiveAccount() now populates plan/balance even when the login status has user:null (VELA_RUNTIME_KEY / VELA_LINK_URL env auth), so env-backed Open Design sessions no longer drop the fetched billing data. - Key the live-account cache by the full credential revision (auth source + profile + userId + config mtime), not just profile, and clear it on logout — a logout / account switch can no longer surface the previous account's plan or wallet balance before the background refresh runs. - Regression tests for both in tests/integrations/vela.test.ts. Sync tests to the AMR -> Open Design copy: - web: tests/providers/sse.test.ts error-string assertions. - e2e: onboarding / logout / run-failure / login-pill specs + visual fixture. * fix(i18n): drop duplicated "Open Design" in switchBody fallback copy The AMR -> Open Design rename sweep collided with the existing brand mention in chat.amrCard.switchBody, rendering "Open Design official Open Design model service" across 13 locales (zh-TW, ja, ko, ar, es-ES, hu, id, fa, pl, tr, ru, pt-BR, uk). Remove the redundant second mention so the retry/switch card reads cleanly. Flagged by @nettee on #4684. Also start aligning InlineModelSwitcher unit tests to the new copy (agent display name AMR -> Open Design, compact error string). * fix(amr): resolve live billing before first /status; hide Upgrade until plan known Address @nettee review on #4684 (two correctness issues in the new plan/balance path): - Cold cache: the signed-in /status handler now BLOCKS the first response on fetchVelaBillingSummary() when the cache is empty, instead of returning config-only and refreshing in the background. The new account surfaces read /status once and never re-poll, so the old flow left plan/balance hidden until the user refocused. Warm cache keeps the non-blocking fast path. fake-vela gains a `billing summary` handler and vela.routes.test.ts covers the cold-cache-first-open case. - Upgrade CTA: canUpgradeVelaPlan() now treats an unknown/empty plan as NOT upgradeable, so a signed-in session whose live summary hasn't resolved no longer flashes Upgrade at top-tier users. Unit-tested. * style(amr): bold the plan/balance text in the switcher + avatar account rows The settings card already renders both bold (the plan value reuses .agent-card-amr-balance-value); align the inline switcher account row and the runtime-switcher avatar row so plan + balance read with the same emphasis everywhere. * fix(amr): single-flight cold billing fetch + surface plan/balance on its own field Address @nettee follow-up review on #4684: - Race: the cold-cache decision keyed off the refresh throttle, so a second /status arriving during the first billing fetch saw refreshAccount=false, fell through, and returned config-only — which the read-once surfaces can't recover from. Now `peekVelaLiveAccount(key) === null` is the cold signal and the billing fetch is single-flighted per credential revision: concurrent cold callers await the same in-flight promise. setVelaLiveAccount stamps the fetch time so the warm path doesn't immediately re-refresh. - Identity: applyVelaLiveAccount no longer fabricates a `{ id: '', email: '' }` user for env-backed sessions. The live billing projection now rides on a new VelaLoginStatus.account field, so `user` stays null (preserving the analytics `user.id` null signal) and plan/balance are surfaced uniformly. SettingsDialog / InlineModelSwitcher / AvatarMenu read status.account.{plan,balanceUsd}. Regression coverage updated in vela.test.ts (applyVelaLiveAccount) and vela.routes.test.ts (cold-cache first open now asserts body.account). * style(amr): match the switcher plan text color to the balance The inline switcher account row showed the balance in --text-strong but the plan in --text-muted, so "$247.51 Plus" read with two different weights of grey. Use --text-strong for the plan too so balance + plan sit at the same emphasis. * fix(amr): treat tier-less billing summary as free; register new entry sources Address @nettee review on #4684: - Free vs unknown: fetchVelaBillingSummary() returned plan:undefined when `membershipTier` was absent, but that field is omitted for free accounts. The new surfaces read status.account.plan for both display and canUpgradeVelaPlan, so a successful free-account read rendered as "unknown" — plan hidden and the Upgrade CTA suppressed for the exact users who should see it. A successful summary without a tier now normalizes to the explicit 'free' sentinel; "unknown" stays signalled by a null account (failed fetch). Regression in vela.routes.test.ts (balance, no tier → account.plan === 'free'). - Analytics: the four entry sources this PR adds (settings_amr_upgrade, inline_amr_upgrade, avatar_amr_upgrade, avatar_amr_agent_card) were in the source→page map but not in the AMR_ENTRY_SOURCES validator set, so parseAmrEntryAnalyticsPayload rejected them and /analytics-entry 400ed for the new buttons. Added them to the set; parser regression covers all four. * fix(amr): invalidate the env-backed live-account cache on config/account change Address @nettee 11:19 review (the inline comment did not post, but the flagged env-backed live-account cache path has a real leak): readVelaCredentialRevision forced configMtimeMs to null for env-backed auth, so the live-account cache key became `env|profile|1||` with nothing to distinguish accounts. Because the live billing summary is fetched with the config profile's controlKey, a config rewrite (account switch) left an env-backed (VELA_RUNTIME_KEY) session serving the previous account's plan/balance. Keep configMtimeMs for env auth too so a config/account change yields a fresh key. Regression added in vela.test.ts. * fix(amr): fingerprint the configured AMR env in the live-account cache key Address @nettee 11:35 review on #4684: configMtimeMs alone wasn't enough. The AMR env credentials (VELA_RUNTIME_KEY / VELA_LINK_URL) can come from agentCliEnv.amr in app-config, and env-backed sessions report user:null — so switching the Settings-backed credential from account A to B on the same profile, without touching ~/.amr/config.json, left the revision at `env|profile|1||<same-mtime>` and let B reuse A's cached plan/balance. readVelaCredentialRevision now adds a non-secret credentialFingerprint (sha256 of the runtime key + link url, truncated) and velaLiveAccountCacheKey includes it. Regressions: a unit test (env key differs by fingerprint) and a route test that rewrites agentCliEnv.amr's VELA_RUNTIME_KEY without touching the config and asserts the second account does not inherit the first's cached billing. * feat(amr): label + stack balance/plan in the switcher account row; fix its tests UI: the inline switcher Open Design account row rendered "$247.51 Plus" with no labels, so users couldn't tell what the two values were. Balance and plan now stack on two labelled lines ("可用余额 / Available balance" and "当前套餐 / Current plan"), with the Upgrade CTA on the plan line. The settings.amrBalance / settings.amrPlan labels are made descriptive across all 19 locales (the settings card reuses them), so the meaning is explicit everywhere. Tests: rewrite InlineModelSwitcher.test.tsx for the account-row structure — the agent radio now carries status only in its aria-label (icon-only visible), and the sign-in / signing-in / cancel affordances live on the inline-model-switcher-account-action button. Redundant within(amrButton) getByText assertions are dropped (the radio-name query already asserts status); pending/error assertions target the account row. 22/22 green. * test(amr): align AmrLoginPill tests to the Open Design copy Account-status group is labelled 'Open Design account status', the console link is 'Console', and the compact sign-in error reads 'Sign-in failed.' — update the queries to match. 29/29 green. * feat(amr): redesign the account row — tier badge + balance subtitle; short labels Iterated on the Open Design account row in both the inline model switcher and the runtime-switcher (avatar) list so the plan/balance no longer collide: - Plan tier renders as a small neutral pill right after the "Open Design" name (identity + tier read as one group, à la Claude's "name · Max"). - Balance moves to a second line below the name, labelled "余额 $247.51" (small grey label + bold value) so users know what the number is. - Upgrade stays as the trailing action, vertically centred against the two lines. Account logo bumped to 24px to balance the taller row. - Revert the amrBalance / amrPlan labels back to the short "余额 / 套餐" ("Balance" / "Plan") across all 19 locales. * test(amr): align remaining web specs to the Open Design copy + account row Update the rest of the web component specs that still asserted the pre-rename wording / old account-row shape (the `Web workspace tests` red CI @nettee flagged): - EntryShell.onboarding: "Sign in to Open Design Cloud" -> "Sign in to Open Design"; "AMR sign-in failed." -> "Sign-in failed.". - SettingsDialog.execution: AMR card queried as /^Open Design\b/ (was /^Open Design AMR\b/). - HandoffButton: agent label "Open Design"; website link "打开 Open Design 官网". - AvatarMenu: drop the two obsolete avatar console-shortcut specs (the avatar console link was removed when the row was consolidated; the upgrade entry remains covered by the daemon parser + contract). Full web suite green: 3403 passed. * test(amr): cover the avatar-row upgrade CTA (plan/balance + stamped link) Replaces the two removed avatar console-shortcut specs with focused coverage for the new runtime-switcher upgrade path (@nettee): mocks a signed-in /api/integrations/vela/status, opens the menu on the non-prod `test` profile, asserts the rendered plan badge + balance, and verifies the clicked upgrade link carries view=plans and od_entry_source=avatar_amr_upgrade attribution. * test(e2e): update avatar visual spec to the redesigned account row The Playwright visual (settings-workspace) job was red on a functional assertion, not a pixel diff: the spec queried the removed `.avatar-amr-account-link` console entry and 'AMR account' / 'Balance & recharge' copy. Rewrite it to override the signed-out status with a signed-in plan/balance, then assert the Open Design row renders the Plus badge + $247.51 and the upgrade link points at ?view=plans. * chore: re-trigger CI on updated main — needs-validation gate moved to merge_group (#4714) * test: capture Open Design account balance visuals * chore: retrigger workspace validation --------- Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> Co-authored-by: lefarcen <935902669@qq.com> Co-authored-by: a1chzt <chizblank@gmail.com> * [codex] keep AMR wallet balance stable during refresh (#4730) * fix: keep AMR wallet balance visible during refresh * fix: remove AMR wallet refresh hover tooltip * chore: retrigger validation * fix(ci): align AMR wallet branch validation * feat(web): Open Design 云账户入口 UI 优化(名牌/置顶/新 logo) (#4787) * feat(web): polish Open Design cloud account surfaces (plan badge, pin-to-top, new logo) - 模型切换器(InlineModelSwitcher): Open Design 账号卡片上位为可点选入口并置顶, 移除重复的代理行 - 头像菜单(AvatarMenu): Open Design 置顶代码代理列表; 执行模式选中态改为勾选标记(不再与代理选中态争色块) - 统一套餐名牌: 新增共享 PlanBadge 组件(全局 CSS, 跟随主题色), 替换设置页/切换器/头像菜单三处各自实现 - 设置页 CLI 卡片: 删除无用的钱包刷新按钮与"更新于…缓存"行; 余额统一为两位小数 - 全局替换 AMR logo 资产(amr.svg) * test(web): align AgentIcon AMR assertion with new logo fill --------- Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> * fix(web): preserve AMR wallet balance in switcher * fix(amr): avoid stale wallet status on refresh failures * fix(web): align avatar AMR balance row * fix(web): avoid stale AMR wallet snapshots * fix(web): keep avatar AMR console link * fix(amr): support wallet fallback for older vela cli --------- Co-authored-by: michaeltaxman911-hue <michaeltaxman911@gmail.com> Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> Co-authored-by: lefarcen <935902669@qq.com> |
||
|
|
54de349c47 |
fix: replace expired Discord invite (#4849)
Co-authored-by: koki yanlai xu <koki@kokideMacBook-Air.local> |
||
|
|
6755e938a4 |
test(platform,sidecar-proto): cover proc-tree, stamp readers, ipc-path validation (#2406)
* test(sidecar-proto): cover normalizeIpcPath validation and Windows pipe detection * test(platform): cover readFlagValue and stamp readers * test(platform): cover collectProcessTreePids BFS traversal |
||
|
|
f80ad9e2dc |
fix(plugins): add bundled Perplexity AI design-system plugin manifest (#4828) (#4833)
The Perplexity AI system ships a card on /plugins/systems/ from design-systems/perplexity/, but had no matching bundled-plugin manifest under plugins/_official/design-systems/perplexity/. As a result detailHrefForSystemSlug() found no plugin and the card fell back to the /plugins/systems/ index instead of opening a dedicated detail page. Add the bundled plugin for perplexity: - open-design.json: generated via the migrate-to-plugins design-system wrapper, then brought to parity with sibling systems (specVersion, full title_i18n/description_i18n, localized useCase query). Structure is byte-identical in shape to the other design-system manifests. - DESIGN.md: embedded copy of design-systems/perplexity/DESIGN.md. - open-design-marketplace.json: register the bundled plugin in the official registry seed (sorted insert + bundledPreinstallCount 413->414), matching how prior plugin-add commits regenerate the seed. The landing page now builds a real /plugins/design-system-perplexity/ detail page and the systems-index card links to it. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0fecb15baa |
chore(release): bump main to 0.12.1 ahead of stable 0.12.0 (#4900)
Stable shipped 0.12.0 (tag open-design-v0.12.0, 2026-06-26) but main's packaged base version stayed at 0.11.1. release-beta's metadata guard requires the packaged base version to be strictly greater than the latest stable, so the daily beta build (notify-daily-feishu, 01:00 UTC) has failed every morning since 2026-06-27 with: packaged base version 0.11.1 must be strictly greater than latest stable 0.12.0 Bump all 18 workspace package.json versions in lockstep to 0.12.1 so main leads stable again. Verified the real prepare-beta guard now resolves 0.12.1-beta.1 (EXIT 0) against the live stable/beta feeds. |
||
|
|
ec3a54f374 |
fix(daemon): detect codex installed via the standalone Codex.app bundle (#4889)
* fix(daemon): detect codex installed via the standalone Codex.app bundle The official OpenAI Codex desktop app (bundle id com.openai.codex) ships the `codex` CLI inside Codex.app/Contents/Resources/codex and does not add it to PATH unless the user runs the app's "Install command line tool" action. Agent detection only searched PATH plus the user-toolchain dirs (npm/nvm/fnm/mise/Homebrew/...), so an app-only install surfaced as "not installed" in the agent picker even though a healthy native binary exists on disk. Add a codex-specific, last-resort resolution fallback that probes the well-known macOS bundle locations (/Applications and ~/Applications), ranked below PATH so an explicit CLI install always wins, and scoped to the OD_AGENT_HOME override so sandboxed detection stays deterministic. Also cap the codex node-wrapper sniff to the first 64KB via a bounded fd read: the selected codex path can now be the ~190MB native Codex.app binary, which readFileSync would otherwise slurp whole just to check a shebang. * test(daemon): cover the no-override /Applications codex bundle branch Export codexAppBundleCandidates and assert that, with no OD_AGENT_HOME override, the system /Applications path is probed first and a distinct ~/Applications candidate follows. The existing fixtures all set OD_AGENT_HOME, so the common real-world /Applications install path was untested and a path-typo or ordering regression could silently miss it. * test(daemon): isolate codex bundle tests from ambient sandbox env resolveDetectionHome() consults OD_SANDBOX_MODE / OD_DATA_DIR before OD_AGENT_HOME, so the new Codex.app fixtures now snapshot and clear those too. Without this, a dev/CI run with sandbox mode already enabled could resolve the sandbox agent home instead of the fixture home (or throw on OD_DATA_DIR) before reaching the branch under test, making the coverage non-deterministic. --------- Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com> |
||
|
|
110774e891 |
fix(ci): merge-queue needs-validation gate skips non-PR refs, not eject clean PRs (#4898)
* fix(ci): merge-queue needs-validation gate skips non-PR refs, not eject clean PRs The merge_group needs-validation gate enumerates queued PRs from three sources; source 2 scrapes a trailing `(#N)` from each commit subject. That `(#N)` can be an ISSUE reference an author put in the PR title, not a queued PR — e.g. #4833, titled "fix(plugins): ... (#4828)", where 4828 is the fixed issue. The gate then ran `gh pr view 4828`, which fails with "Could not resolve to a PullRequest"; as a plain assignment under `set -e` that ejected a clean, label-free, approved PR from the merge queue every time it entered — permanently unmergeable. Distinguish a definitive "not a PR" (skip — the number was a spurious reference) from a transient API failure (still fail closed → block), so real needs-validation PRs are still enforced while issue references no longer block clean merges. * fix(ci): resolve merge-group needs-validation per commit, not a flat union Addresses review: skipping a non-PR `(#N)` unconditionally could, in a batched merge group, drop the only candidate that would have checked a non-tip PR — so a non-tip PR still carrying `needs-validation` could slip through (#4736 hazard). Resolve each merge-group commit to at least one real PR from its own signals (subject `(#N)`, commits/<sha>/pulls, and — for the tip — the queue ref). A `(#N)` that does not resolve to a PR (e.g. an issue reference like #4833's "(#4828)") is ignored ONLY when its commit is still covered by another candidate that resolves to a real PR; a commit that resolves to no PR fails closed. Real needs-validation PRs are still blocked; clean PRs whose title references an issue are no longer ejected. Verified with a mocked gh harness: (A) tip "(#4828) (#4833)" → ignores 4828, checks 4833, clears; (B) batched non-tip whose only number is an issue ref + carries needs-validation → fails closed; (C) tip with needs-validation → blocks. --------- Co-authored-by: lefarcen <ontf116@gmail.com> |
||
|
|
211ec5df5a |
ci: make the Nix hash check advisory on PRs, enforce it only at merge time (#4896)
* ci: make the Nix hash check advisory on PRs, enforce it only at merge time A stale nix/pnpm-deps.nix hash is the routine, self-healing consequence of any pnpm-lock.yaml change: the nix_validation job already regenerates the hash and hands it to autofix.atom.yml, which pushes the refresh back to the PR branch. Failing the job on pull_request turned that transient, auto-fixed drift into a red check that flipped the PR to BLOCKED and read as a real CI failure to the review bot — the same deadlock the needs-validation gate already documents. The contributor then waited on the autofix round-trip every time the lockfile moved. Now nix_validation stays green on pull_request (the autofix still self-heals the hash in the background) and the hash is enforced as a hard gate only at merge time: merge_group and manual full runs fail closed, so a genuinely broken Nix build can never reach main. The Validate workspace gate ignores a red Nix job on PRs (both the blanket failure scan and the required-jobs check) and keeps requiring it everywhere else. * test(e2e): cover the Nix-advisory-on-PR Validate workspace gate Extract the two jq programs the `validate` job runs (the blanket failure scan and the required-jobs scan) straight out of ci.yml and feed representative `needs` JSON through the real `jq`, so the cross-workflow gate behavior is asserted rather than reviewed by eye: - pull_request + failed nix_validation -> gate passes (advisory), - merge_group / workflow_dispatch full + failed nix_validation -> gate fails closed, - pull_request + another failed required job -> gate still fails (the PR exception is scoped to nix_validation only). A future edit that makes Nix advisory on merge_group, or stops ignoring it on PRs, now fails this test instead of slipping through YAML review. |