Commit Graph
2583 Commits
Author SHA1 Message Date
Denis RedozubovandGitHub 9cc399a0f3 fix(daemon): prefer Codex subscription imagegen (#4477)
* fix(daemon): prefer Codex subscription imagegen

* fix(daemon): normalize Codex imagegen service tier

* fix(daemon): use nested Codex permissions config

* test(daemon): add live Codex imagegen smoke
2026-06-19 12:57:56 +00:00
Marc ChanandGitHub a0412c12e6 fix(docker): add opt-in API auth disable flag (#4541)
* fix(docker): add opt-in API auth disable flag

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

* docs(docker): add .env setup to beginner guide

Generated-By: looper 0.9.10 (runner=fixer, agent=opencode)
2026-06-19 03:24:14 +00:00
42d9244ae4 test(daemon): cover OpenCode npm binary detection (#4540)
Generated-By: looper 0.9.10+codex.autoclean (runner=worker, agent=codex)

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-19 03:23:59 +00:00
YOMXXXandGitHub 169eb78a74 fix(platform): discover Windows fnm-managed Node in the toolchain bin list (#4535)
* fix(platform): discover Windows fnm-managed Node in the toolchain bin list

A GUI-launched packaged app on Windows inherits a stripped PATH and reads no
shell rc, so it relies on wellKnownUserToolchainBins to locate user toolchains.
That list only probed POSIX fnm roots (~/.fnm and ~/.local/share/fnm) with
[installation, bin] segments. fnm on Windows keeps Node under
%APPDATA%\fnm\node-versions\<version>\installation with node.exe directly in
`installation` (no POSIX-style bin subdir), so fnm-managed Node — and every
agent CLI that needs it — was silently undetected.

Probe %APPDATA%\fnm\node-versions (FNM_DIR overrides the root) with the
Windows [installation] segment on win32, alongside the existing POSIX roots.

* fix(platform): also probe %LOCALAPPDATA%\fnm and surface npm-global CLIs (#3062)

fnm on Windows can root under %LOCALAPPDATA%\fnm as well as %APPDATA%\fnm.
Probe both (FNM_DIR still overrides both). Because a globally `npm i -g`'d CLI
shim such as codex.cmd lands in the node version's `installation` dir next to
node.exe, surfacing that dir also makes those CLIs discoverable from a GUI
launch — addressing the "Codex CLI not detected from Windows shell" report.
2026-06-19 03:23:39 +00:00
PerishFireandGitHub 358a426b2b ci: rename atom workflows (#4522) 2026-06-19 03:22:43 +00:00
efbfeb38fc fix(analytics): enable GeoIP on daemon PostHog client so events carry user country (#4521)
posthog-node defaults disableGeoip:true (it assumes a datacenter deployment
whose ingestion IP is not the user's). Open Design's daemon runs on the user's
own machine, so the request IP is the user's real public IP and GeoIP is
accurate — identical to what posthog-js already sends. Leaving the default on
stripped country from every daemon-emitted event (run_created, run_finished,
*_result, crash/safety events): ~2.2M events over 30d sat at 0% event-level
country while web events were 100% enriched.

Pass disableGeoip:false on the PostHog node constructor and add a regression
assertion that the constructor receives it.

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-19 03:22:25 +00:00
Marc ChanandGitHub aa3c35b591 fix(daemon): close canceled Claude stdin earlier (#4091) (#4517)
Close stream-json run stdin as soon as cancellation starts so Claude exits promptly instead of continuing to burn tokens until the process watchdog or account limits stop it. Also add regression coverage for cancel and shutdown paths to ensure stdin closes before SIGTERM.

Generated-By: looper 0.9.10 (runner=worker, agent=opencode)
2026-06-19 03:21:58 +00:00
lefarcenandGitHub e79934b12a test(e2e): de-flake manual-edit bridge element selection (#4512)
The P0 'manual edit' UI tests intermittently time out at 30s on
`frame.locator(selector).click()` inside selectPreviewElementThroughBridge
(seen dequeuing #4497 and #4501 from the merge queue, on unrelated
landing-only / docs-only changes).

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

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

Flaky by nature, so no deterministic red spec; verified e2e typecheck and
that the wrapped assertions match the original. CI 'UI P0 (project-runtime)'
exercises the live path.
2026-06-19 03:21:48 +00:00
Leonel RivasandGitHub 9bac2e6dae fix(daemon): gate cursor-agent --trust behind the --help capability probe (#4505)
Cursor Agent's adapter passed --trust unconditionally. The flag is
build/version-dependent (headless-only, and absent from some installed
cursor-agent binaries), so CLIs that don't recognize it exit 1 with
"unknown option '--trust'", breaking the Test button and task execution.

Declare helpArgs + capabilityFlags so detection probes --help and
buildArgs only appends --trust when the installed CLI advertises it,
matching the existing claude/codebuddy capability-gating pattern.

Fixes #4461
2026-06-19 03:21:03 +00:00
Leonel RivasandGitHub 41031d7bfb fix(platform): resolve pnpm via corepack when npm_execpath is absent (#4488)
On Corepack-only setups (e.g. native Windows PowerShell where `corepack
pnpm` works but no standalone `pnpm` is installed on PATH), nested
package-manager invocations from tools-dev/tools-pack failed: the
no-`npm_execpath` fallback in createPackageManagerInvocation assumed a
global `pnpm` binary. Route those invocations through `corepack pnpm …`
instead — it runs the repo-pinned package manager out of the box, while a
bare `pnpm` only resolves with a separate global install or a
`corepack enable` shim. Applies to both POSIX and Windows.

Fixes #2438
2026-06-19 03:20:45 +00:00
Quy TruongandGitHub 2a2b3d9c43 fix asset-cache origin null preview (#4487) 2026-06-19 03:20:30 +00:00
Denis RedozubovandGitHub d335be493a Centralize reasoning provider policy enforcement (#4476)
* Add reasoning egress policy guard

* Assert reasoning denials hide API keys

* Rerun validation

* fix(daemon): reject malformed reasoning egress policy

* Fix Google reasoning allowlist canonicalization
2026-06-19 03:20:18 +00:00
f62ea6db46 fix(daemon): classify high-confidence run failures (#4478)
Co-authored-by: Siri-Ray <2667192167@qq.com>
2026-06-19 03:19:53 +00:00
dc12e0938f fix(frontmatter): a lone quote character is no longer parsed as an empty string (#4182)
* fix frontmatter parser coercing leading-zero values to numbers

The minimal YAML frontmatter parser (and its plugin-runtime mirror)
coerced any `-?\d+` token to a Number, so a leading-zero value like
`01234` (zip code, zero-padded id) silently became `1234`, and `007`
became `7`. Per YAML 1.2 a leading-zero decimal is a string — the zero is
significant. Restrict integer/float coercion to values without a redundant
leading zero (`0` alone still coerces to the number 0).

Also fix a related edge case where a value that is a single quote character
(`"`) was treated as an empty quoted string (slice(1,-1) of a 1-char
string), now requiring at least two characters before stripping quotes.

Both parser copies are kept in sync per their "mirror" contract.

Adds tests/frontmatter.test.ts for the daemon parser and extends the
existing plugin-runtime parsers test.

* fix(frontmatter): coerce leading-zero numerics per YAML 1.2 core schema

Restore numeric coercion for leading-zero scalars (01234, 007, -01, 00.5)
to match the YAML 1.2 core-schema int/float resolution, per review. The
lone-quote guard (require length >= 2 before stripping matching quotes)
stays in place. Tests updated to assert the numeric results.

Applies to both the daemon parser and the plugin-runtime mirror.

---------

Co-authored-by: Nagendhra <nagendhra405@gmail.com>
2026-06-19 03:19:19 +00:00
c87934d467 feat(landing): add "What is vibe design" blog post (18-locale, author byline, download CTA) (#4484)
* feat(landing): add "What is vibe design" blog post

New /blog/what-is-vibe-design pillar targeting the "vibe design" keyword
cluster (definitional/informational intent), fully localized across all 18
landing locales.

Also adds two backward-compatible blog primitives (existing posts unchanged):
- optional team-persona author byline (avatar + name + role) via a new
  blog-authors registry and an optional `author` frontmatter field;
- optional `ctaKind: download-app` frontmatter that points the post's
  conversion CTA at the desktop client download page (Discord stays secondary).

Illustrations are original editorial concept art (no third-party screenshots).

* fix(landing): register vibe-design cover in blog index postImages

The post committed /blog/what-is-vibe-design-cover.webp but the blog
index postImages registry was not updated, so the index card and
featured panel fell back to the generic media placeholder instead of
the editorial cover. Add the what-is-vibe-design entry so the index and
detail page share the same cover art.

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-18 08:58:21 +00:00
c1701f709a [codex] codify workflow handoff capabilities (#4503)
* codify workflow handoff capabilities

* Harden workflow marker jq lookups

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

* harden autofix head validation

* Preserve Nix hash fallback guidance

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

* Gate Nix hash fallback comments

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

* Clear stale Nix fallback comments after autofix

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

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-18 08:37:18 +00:00
netteeandGitHub ad16709385 fix(daemon): classify completed Claude startup output before exit 1 (#4501)
* fix(daemon): classify completed Claude startup runs correctly

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

* fix(daemon): reject errored Claude result completions

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

* fix(daemon): require Claude result before exit-1 override

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

* fix(daemon): require successful Claude result subtype

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

* fix(daemon): limit Claude override to late exit 1

Generated-By: looper 0.9.10 (runner=fixer, agent=codex)
2026-06-18 07:25:26 +00:00
5be5ba745c landing: merge home-refresh redesign into main (resolve conflicts) (#4497)
* landing: skill-spec restyle, upstream parity, newsletter + nav copy updates

Landing-page-only rebuild of the home-refresh branch on top of current
main (the previous branch carried unrelated apps/web changes and
conflicted with main):

- Homepage: newsletter band between CTA and FAQ (localized in all 18
  locales, client-side stub until a provider lands), AMR logo in the
  nav, hero subtitle now reads 'best open-source alternative' in every
  non-English locale, hero/nav download labels swapped.
- /plugins/: upstream hub structure (3 tiles); /plugins/templates/ +
  kind pages: breadcrumb and counter chip removed, scene chip
  active-state contrast fix, tpl-card styles with token colors.
- /agents/: design-spec pass (token spacing incl. 68px max module gap,
  font scale, 8px radius), 3-up card grid, list-indent fix; /solutions/,
  /agents/, /plugins/ unified on one 1180px centered safe area.
- /blog/: cream/terracotta leftovers replaced with token colors, 8px
  card radius.
- Header dropdowns: full 21-agent list, upstream caret/gap parity;
  neutralized the homepage section padding leak inside info pages.
- package.json stays on main's shape; cobe / matter-js / @types/
  matter-js added as exact pins (homepage globe + FallingText) with
  matching pnpm-lock entries. nix/pnpm-deps.nix hash NOT refreshed
  (no nix locally) — needs the Validate workspace gate or a follow-up.

* landing: fix CI gates while keeping the homepage refresh intact

Rebased onto current main and resolved the blocking review + red checks on
this branch without dropping the design refresh:

- Zero-client-JS gate: the cobe globe and matter-js FallingText enhancers
  used ES `import`, so Astro emitted external `/_astro/*.js` module bundles
  and tripped `Verify zero external JavaScript`. Both effects are preserved:
  index.astro now reads each library's prebuilt runtime from node_modules at
  build time and inlines it verbatim as a classic `<script is:inline>`
  (cobe's single ESM default export is rebound to `window.__cobe`; matter-js
  ships UMD), mirroring locale-switcher-script.astro. No bundled/module JS.

- Staging/preview noindex: restored the `staging-noindex-headers` Astro
  integration that appends `X-Robots-Tag: noindex, nofollow` to `_headers`
  for OD_LANDING_NOINDEX builds, so PR previews stay out of search indexes.

- Blob guard: removed 14 stray .bak/.prev/.leftpad backup files and 9
  unreferenced PNG originals, converted 12 referenced >1MB PNGs to WebP
  (each <1MB) with their refs updated, and recompressed lab-video.mp4 /
  lab-hyperframes.mp4 under 1MB. No changed tracked file now exceeds 1MB.

- Residual-JS guard: allowlisted public/community/_site-nav.js, a verbatim
  browser script for the static /community/ pages (same precedent as the
  web notifications service worker).

- Homepage-art gate: the refresh serves its hero/gallery/method art as
  optimized origin-hosted WebP instead of Cloudflare Image Resizing variants,
  so the homepage no longer emits cdn-cgi URLs. The gate now requires the
  same floor of 16 optimized WebP references (ci/staging/production) so a
  regression to raw, unoptimized art is still caught.

* landing: stop 18x-localizing the skills/systems/templates catalog

The PR preview deploy hit Cloudflare Pages' 20,000-file-per-deployment cap:
the branch added `[locale]/{skills,systems,templates}` detail/listing
generators plus per-locale plugin previews, all fanned out across the 18
LANDING_LOCALES, producing ~29,300 output files.

This is exactly the locale-explosion the branch's own `public/_redirects`
already anticipated — its "Catalog migration" section says the standalone
skills/systems/templates generators "were removed" and are 301'd to
`/plugins/*`, but the generator routes were left in the tree, and the
localized 301 rules only covered 4 of the 18 locales.

Fix, matching that stated intent and Astro's guidance for bounded static
multilingual builds (prune the prerender matrix; signal i18n via
hreflang/sitemap, which this site already does — non-default locales are
sitemap-excluded):

- Remove the localized `[locale]/{skills,systems,templates}` detail, index
  and facet generators, and the localized `[locale]/plugins/previews`
  duplicate (previews are language-agnostic visual assets).
- Extend the localized catalog 301s in `public/_redirects` from {zh,zh-tw,
  ja,ko} to every prefixed locale, and add `/<loc>/plugins/previews/*` →
  the canonical English previews. Kept-localized plugin hub/detail pages
  whose links degrade to these paths now resolve via a single 301 hop.

English catalog pages, all localized marketing pages, the localized plugins
hub, and the homepage design are unchanged. Output drops to ~19.2k files,
back under the deploy cap.

* landing: canonicalize legacy locale aliases in the header language switcher

The shared sub-page header language switcher builds its targets with
`localePath(target, Astro.url.pathname)`, and `stripLocaleFromPath` only
recognized canonical `LANDING_LOCALES`. The catch-all route still emits
legacy / alias locale pages (`app/_lib/i18n.ts` LOCALES: `/zh-CN/`, `/es-ES/`,
`/fa/`, `/hu/`, `/th/`, plus upper-cased `zh-TW`/`pt-BR`), so on those pages
the switcher produced doubled, non-existent targets like `/zh/zh-CN/blog/`.

Strip those alias prefixes too (case-insensitive, canonicalizing to the
default locale) so switching language from `/zh-CN/blog/` now lands on an
existing URL (`/blog/`, `/zh/blog/`, …). Verified against the static build:
the doubled `/<loc>/{zh-CN,es-ES,fa,hu,th}/…` targets are gone (0 matches),
and canonical `LANDING_LOCALES` pages are unchanged.

* landing: optimize homepage first-screen — fonts → subset woff2, hero → responsive webp

Resource-weight pass on the homepage, focused on the first screen.

Fonts (≈861 KB → ≈106 KB, and no longer render-blocking):
- Albert Sans regular/italic shipped as TTF (125 KB + 138 KB). Added woff2
  builds (50 KB + 55 KB) as the primary `src`, TTF kept only as a fallback.
- `remixicon.ttf` was a 598 KB icon font loaded `font-display: block` (it hid
  the icons — and text in the same paint — until the whole font downloaded).
  The site only renders 11 of its glyphs, so it's now subset to a 1.3 KB woff2.
- All faces are `font-display: swap` now, and the above-the-fold Albert Sans
  woff2 is `<link rel=preload>`ed at high priority, so text paints immediately
  in the fallback and swaps without a blocking round-trip.

Hero imagery (responsive WebP instead of one oversized file for all devices):
- The hero backdrop was a single 326 KB / 2880px PNG served to every viewport.
  Now responsive q90 WebP variants (960→33 KB, 1440→47 KB, 1920→89 KB,
  2880→110 KB); `og:image`/`twitter:image` keep the PNG since social crawlers
  don't reliably accept WebP. The LCP preload points at the WebP set with
  `imagesizes="100vw"` to match the full-bleed `<img>`.
- The hero product shot now has a responsive srcset (800/1280/1920/2508);
  the 2508px master is the pristine original (no re-encode), phones pull the
  800px (66 KB) variant.

Quality is kept high (q90) — the savings come from format + right-sizing per
viewport, not heavier compression. Build output is unchanged structurally
(zero external/module JS still verified; ~19.2k files, under the deploy cap).

* landing: include all 25 used Remix Icon glyphs in the subset

The first subset only covered the 11 codepoints declared via CSS `content:`
and missed the 15 declared as JS \u escapes in page.tsx's `RI` glyph map
(download \uec5a, github \uedcb, star \uf18b, the arrow/chevron set, …), so
the hero download / Star CTA icons and several nav arrows rendered blank.
Re-subset to the full union of 25 glyphs (still ~2KB woff2).

* landing: add the locale-switcher caret glyph to the Remix Icon subset

A full scan of the built site (18,912 HTML files, every rendered Private-Use
codepoint) surfaced one more glyph the 25-glyph subset was missing: U+EA4E
(arrow-down-s-line), the language-switcher dropdown caret in header.tsx — it's
inserted as a literal char (not via the RI map), so the source grep missed it.
Re-subset to 26 glyphs (≈2.1KB); the same scan now reports zero missing
glyphs site-wide.

* landing: convert remaining raster art to WebP site-wide

After a site-wide image audit, converted the last referenced PNG/JPG raster
art to WebP (q88, no visible quality loss — the source files are lossless so
there's no generation loss):

- `lab-stage-bg` (homepage lab section): 710KB JPG → 323KB WebP.
- Blog study plates 09–12 and 16–22 (the hero/inline art in the Figma- and
  Claude-alternative posts, referenced across every localized section):
  ~4.9MB of 1024² PNGs → ~2.6MB WebP. All `<img src>` references in the two
  blog markdown files and the blog index were repointed; the originals are
  removed.

Combined with the earlier hero/font pass, the homepage and blog now ship only
WebP raster art (PNG kept solely for the social `og:image`). Verified: build
clean, no dangling references to the removed files, zero external/module JS,
~19.2k output files (under the deploy cap).

* landing: make homepage og:image / twitter:image absolute URLs

`heroImage` is a same-origin path (`/hero-home.png?v=2`); social crawlers
(Facebook, Twitter, LinkedIn) need an absolute URL for rich link previews.
Resolve it against `Astro.site` at the metadata call site so the share card
renders as `https://open-design.ai/hero-home.png?v=2`. Per @PerishCode's
review note; non-blocking but correct.

* landing: absolute share image on sub-pages + canonical-locale plugin search.json

Two non-blocking output regressions from @PerishCode's review:

- sub-page-layout.astro wrote `og:image`/`twitter:image` from the raw
  `ogImage ?? heroImage` (origin-relative), so every sub-page's share card
  (plugins, agents, download, …) emitted `content="/hero-home.png?v=2"`.
  Resolve against `Astro.site` like the homepage already does; `new URL()`
  leaves an already-absolute `ogImage` untouched.

- [locale]/plugins/search.json.ts keyed off `_lib/i18n` PREFIXED_LOCALES
  (the legacy alias table: zh-CN, es-ES, pt-BR …), so it emitted
  `/zh-CN/plugins/search.json` whose entries linked to `/zh-CN/plugins/<slug>/`
  detail pages that don't exist, while the canonical `/zh/plugins/search.json`
  was missing. Drive it from `app/i18n` LANDING_LOCALES + localePath so each
  endpoint matches the localized plugin detail routes and its hrefs resolve.

Verified: sub-page og:image is now absolute, /<canonical-locale>/plugins/
search.json exists with resolvable hrefs (legacy /zh-CN/ variants gone),
zero external/module JS, ~19.2k files.

* landing: preserve query + hash when switching language

The locale switcher's click handler only persisted the choice and let the
anchor's bare server-rendered href ('/<locale>/<path>/') drive navigation, so
a plain left-click dropped the current query string and hash — switching
language on '/plugins/templates/?kind=deck#gallery' landed on
'/<locale>/plugins/templates/'. Intercept the plain left-click and route
through the existing selectLocale(), which carries window.location.search +
hash across the switch via targetFor(); modified-click / non-left-button /
right-click still fall through to the real <a> (open-in-new-tab, etc.).

Per @PerishCode's review note. Verified: build clean, homepage still ships no
external/module JS, typecheck 0 errors.

* landing: handle legacy locale aliases in the switcher's path recompute

The previous commit routed plain locale-switch clicks through selectLocale(),
which recomputes the target via basePathFromCurrent(). That helper only treated
canonical LANDING_LOCALES as a strippable first segment, so on a legacy alias
page (/zh-CN/, /es-ES/, /fa/, /hu/, /th/ — still emitted by the catch-all)
clicking a language built a nested, non-existent URL like /zh/zh-CN/blog/.

Teach the switcher the same legacy-alias set as stripLocaleFromPath in
app/i18n.ts (zh-cn, es-es, fa, hu, th) via an isLocaleSegment() helper, so the
alias prefix is stripped before the target is rebuilt: /zh-CN/blog/ → ja now
yields /ja/blog/ (+ preserved query/hash), not /ja/zh-CN/blog/.

Per @PerishCode. Verified: build clean, switcher script carries the alias
handling, homepage still ships no external/module JS, typecheck 0 errors.

* landing: make plugin detail canonical-only + guard the deploy file count

The localized plugin detail wrappers (`[locale]/plugins/[...slug].astro` and
`[locale]/plugins/[slug]/index.astro`) regenerated the full ~450-plugin detail
set across all 17 non-default LANDING_LOCALES, so `build:static` emitted 19,234
files with `public/previews` empty — only ~766 below Cloudflare Pages' 20k-file
deploy cap, which the CI-generated preview thumbnails would erode further. This
is the same locale-explosion the PR set out to fix, left in the plugin subtree.

- Remove both localized plugin detail generators; plugin detail stays canonical
  (English). Output drops 19,234 → 4,287 files (huge headroom).
- Add `/<loc>/plugins/* -> /plugins/:splat` 301s for every prefixed locale so
  localized plugin links (still emitted by the kept localized hub pages) resolve
  to the canonical detail page. Kept hub pages (/<loc>/plugins/,
  /<loc>/plugins/{skills,systems,templates}/) have static files and win over
  the redirect (static assets take precedence over _redirects on CF Pages).
- Add a post-build "deploy file count under Cloudflare Pages cap" step to the
  ci / staging / production landing workflows (fail at >=19,000) so this limit
  can never regress silently again.

Per @PerishCode. Verified: 4,287 files, localized hubs + canonical detail
intact, homepage zero external/module JS, typecheck 0 errors.

* landing: one canonical plugin detail route (drop namespace catch-all)

`plugins/[...slug].astro` keyed getStaticPaths off `plugin.slug`, which keeps
the registry namespace (`open-design/<name>`), so it emitted nested pages like
/plugins/open-design/<name>/ and self-canonicalized them via Astro.url.pathname.
But catalog cards and the search JSON link to `plugin.detailHref`
(/plugins/<last-segment>/), which the sibling `plugins/[slug]/index.astro`
already generates from `detailSlug`. The catch-all therefore produced ~440
orphan, indexable duplicate URLs that no surface links to — extra sitemap
entries and extra files against the Cloudflare Pages cap.

Delete the catch-all; `[slug]/index.astro` remains the single canonical detail
route at the exact `detailHref` URL the catalog/search already target. These
namespace URLs are net-new to this branch (never shipped/indexed), so no
redirect is needed. Output drops 4,287 → 3,848 files; canonical detail pages
(445) and the templates/[kind] hubs are intact.

Per @PerishCode. Verified: /plugins/open-design/* gone, canonical detail
renders, file-count guard passes, homepage zero external/module JS, typecheck
0 errors.

* landing: fix dead locale-prefixed links to canonical detail pages and migrated catalogs

Plugin/skill/template detail pages are canonical-only since the catalog
migration, but the card components still ran detailHref through
localizedHref, 404ing every card click on all 17 non-default locales
(430+ links per locale). The homepage lab dock, the design-systems stat
card, and the html-video CTA also still pointed at the legacy /skills
and /systems paths. Cards now link detail pages canonically; homepage
and html-video links target the /plugins/* catalogs and kind facets.

* landing: anchor the community dropdown into the hub sections again

Contributors / Ambassadors / Moderators in the header dropdown linked
straight to the standalone static pages, surfacing them on a plain
menu click. Restore upstream main's destinations — /community/#... hub
anchors — so the dropdown scrolls the hub; the standalone pages stay
reachable from the hub cards only.

* landing: giant two-tone wordmark sign-off under the footer columns

A masthead-style "Open Design." wordmark (ink + brand green via the
--ink / --coral tokens, Albert Sans 800, container-filling clamp size)
closes both footers — the homepage one in page.tsx and site-footer.astro
share the .foot-masthead class contract. Mobile gets extra bottom
padding so the wordmark clears the page-bottom GradualBlur band.

* landing: mobile responsive polish + nav liquid-glass caustic fixes

Mobile / responsive:
- nav menu panel: solid white surface (no backdrop blur), full capsule
  width, and hide the page-level bottom GradualBlur band while open
- unify section rhythm to a consistent 112px gap (56px block padding)
  across the home page and the info-page family (solutions / agents /
  compare) at <=880px
- final CTA stacks as copy -> tag -> buttons -> image
- design-system cards: one per row on phones, and stop short brand names
  wrapping mid-word
- template registry search: submit button only activates and the clear
  (x) only appears once there is a query
- solution-step cards: even padding on all four sides (drop min-height +
  row stretch)
- about-tab switch no longer scroll-jumps on mobile (the pin-scroll only
  runs while the section is actually pinned on desktop)

Nav "liquid glass" caustic:
- center the displacement map: opaque (#000) gradient stops instead of
  transparent (#0000), so the R/B channels ramp linearly and the neutral
  point sits at 50% instead of ~29% (was biased to one side)
- halve the refraction displacement (feDisplacementMap scale -100/-94/-88
  -> -50/-47/-44) so content behind the bar distorts less

Icon font:
- re-subset remixicon.subset.woff2 from the full TTF so every glyph stays
  centered in its advance box (the old subset left-aligned outlines to
  x=0, pushing icons like the Labs dock "video" tile off-center)

Note: globals.css, sub-pages.css and plugins/templates/index.astro also
carry in-progress working-copy edits that are interleaved with these
changes in the same blocks and could not be split out cleanly.

* landing: restore PostHog analytics + localize templates search

Address review on #4497:
- Restore <PostHogAnalytics /> in index.astro and sub-page-layout.astro;
  the merge had dropped it, silently disabling download/share/locale/FAQ/
  page_view tracking on every landing page (helper tests pass in isolation).
- Route the redesigned templates search widget labels through pcopy
  (searchLabel/searchClear added to PluginsCopy + en/zh-CN/zh-TW); they were
  hardcoded English on localized /<locale>/plugins/templates/ pages.

* landing: wrap the contributors heading on mobile

The testimonial heading keeps each <br>-split line on a single line via
`.testimonial-copy h2 { white-space: nowrap }` (+ the `.testi-post` span),
which is fine on the content-sized desktop two-column track but overflows a
phone — the heading was clipped at the right edge ("…329 co", "…toget").

On <=880px let both lines wrap (white-space: normal) and give the copy
column min-width:0 so the nowrap content can't blow the single grid track
wider than the viewport.

---------

Co-authored-by: wangchenglong <879618852@qq.com>
Co-authored-by: lefarcen <ontf116@gmail.com>
Co-authored-by: wangchenglong <honam884844@gmail.com>
2026-06-18 07:00:19 +00:00
Carson YangandGitHub 11fb1ad6f0 docs: add Sealos deployment option (#4472)
* docs: add Sealos deployment option

* docs: update Sealos deploy slug

* docs: point Sealos badge to app store page

* docs: add Sealos deploy section to localized READMEs

* docs: clarify Sealos authentication guidance
2026-06-18 06:38:10 +00:00
48da58f751 chore(landing-page): unify official X account to @OpenDesignHQ (#4480)
audit of all official Twitter/X account entry points across the landing page:
- profile links (header / footer / home / community nav): x.com/nexudotio -> x.com/OpenDesignHQ (4)
- share-tweet @mentions (plugins/templates/skills, all locales): @opendesignai -> @OpenDesignHQ (55)
two handles were inconsistent (nexudotio vs opendesignai); now unified. links like x.com/compose
(share intent) and x.com/cursor_ai (Cursor reference in content) left untouched.

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-18 00:54:50 +00:00
Vitor Cepeda LopesandGitHub ecb1f3ac00 fix(desktop): treat payload updates as in-app installs (#4471) 2026-06-17 12:33:12 +00:00
95bc320320 fix: surface crystallize proposal refresh failures (#4323)
Generated-By: looper 0.9.10+codex.2ebc216 (runner=worker, agent=codex)

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-17 12:33:03 +00:00
PerishFireandGitHub c782aeb3bb ci: stop duplicate post-merge validation (#4469) 2026-06-17 10:04:03 +00:00
PerishFireandGitHub b49c9b7932 Refine CI hot and full validation modes (#4466) 2026-06-17 09:32:29 +00:00
AmyandGitHub 73d07d8dfb test(e2e): stabilize AMR onboarding assertions (#4462) 2026-06-17 09:08:09 +00:00
b02d20e6b9 fix: unify Discord invite links (#4452)
Co-authored-by: koki yanlai xu <koki@kokideMacBook-Air.local>
2026-06-17 08:25:16 +00:00
PerishFireandGitHub 15d3759834 [codex] Optimize CI topology and Playwright suites (#4460)
* Consolidate PR validation into ci

* Tune absorbed CI runner tiers

* Fold visual validation into CI Playwright shards

* Run PR shards during manual CI dispatch

* Optimize CI topology and scopes

* Increase UI P0 Playwright workers

* Relax visual Playwright timeout
2026-06-17 08:24:52 +00:00
858486442b Fix AMR agent card label wrapping (#4419)
* Fix AMR agent card label wrapping

* Tighten AMR card account actions

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-06-17 16:13:31 +08:00
NeOMakinGandGitHub a7733f32e2 fix(web): detect decks with slide-prefixed classes (#4341)
Signed-off-by: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
2026-06-17 16:13:09 +08:00
CaprikaandGitHub fdb1638183 [codex] Refresh local CLI auth state after API key switches (#4453)
* Refresh Codex auth status after CLI changes

* Probe Claude Code auth status

* Stabilize project route during agent refresh

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

* test(e2e): expand critical flow coverage

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

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

* ci: gate packaged onboarding smoke to nightly

* fix(web): repair artifact replay type narrowing

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

* fix(ci): repair preflight smoke coverage checks

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

* fix(web): tighten artifact recovery polling

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

* fix(web): keep error recovery retries alive

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

* fix(e2e): relax brittle UI P0 assertions

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

* fix(web): recover pointer artifact outputs

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

* fix(e2e): stabilize manual edit reload smoke

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

* fix(e2e): avoid noisy win onboarding cleanup

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

* fix(web): stop failed artifact recovery polling

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

* fix(daemon): isolate startup smoke data root

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

* fix(web): recover standalone html artifacts

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

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

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

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

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

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

* fix(ci): keep PR visual capture complete

* fix(web): keep reload artifact recovery retryable

* fix(ci): clarify PR visual gate layering

* fix(e2e): stabilize visual home P2 capture

* fix(e2e): align visual gallery detail clicks

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

* fix(ci): shard PR visual capture

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

* fix(ci): keep visual capture screenshots flat

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

* fix(ci): stabilize PR P0 recovery gate

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

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

* ci: run critical UI P0 subset on PRs

* ci: combine PR UI P0 critical shards

* ci: combine PR visual capture shards

* ci: preserve visual capture shard manifests

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

* test(e2e): harden onboarding connect gate coverage

* test(e2e): align AMR auth recovery and visual catalog timeout
2026-06-17 16:01:53 +08:00
lefarcenandGitHub e1b8d9921e Merge pull request #4421 from nexu-io/release/v0.11.0
release: Open Design 0.11.0 — The Bazaar
2026-06-17 15:27:29 +08:00
681dacde18 feat(landing): DESIGN.md systems hub + design-token spec sheet + scenario mocks on design-system pages (#4420)
* feat(landing): systems-page DESIGN.md/FAQ copy + design-token loader

* feat(landing): DESIGN.md+FAQ sections on systems hub, token spec sheet on detail

* feat(landing): detail-page TOC nav, token visuals, tighter spacing, unified related cards

* feat(landing): multi-scenario themed previews (web/app/slides/poster) on design-system detail

* feat(landing): localized routes for design-system detail pages (chrome i18n, DESIGN.md body stays en)

* feat(landing): theme scenario mocks from real design tokens; phone app, 16:9 slide, refined poster

* feat(landing): redesign slide mock (two-zone), sticky schema nav, contribute moved to top

* feat(landing): right-rail section nav + 2-up related cards on design-system detail

* fix(landing): localize design-system detail title suffix + keyword-rich meta description + keywords meta

* feat(landing): declutter detail header — icon-only share, move contribute callout to page bottom

* fix(landing): cancel homepage 130px section padding on detail-block (killed huge inter-section gaps)

* i18n(landing): localize design-system detail + systems-hub chrome across 17 locales

* feat(landing): locale-aware DESIGN.md body loading (DESIGN-<locale>.md) with English fallback

* i18n(design-systems): localize apple DESIGN.md body into 17 locales

* i18n(design-systems): localize stripe DESIGN.md body into 17 locales

* i18n(design-systems): localize vercel DESIGN.md body into 17 locales

* i18n(design-systems): localize notion DESIGN.md body into 17 locales

* i18n(design-systems): localize github DESIGN.md body into 17 locales

* i18n(design-systems): localize airtable DESIGN.md body into 17 locales

* i18n(design-systems): localize figma DESIGN.md body into 17 locales

* i18n(design-systems): localize openai DESIGN.md body into 17 locales

* i18n(design-systems): localize slack DESIGN.md body into 17 locales

* i18n(design-systems): localize discord DESIGN.md body into 17 locales

* i18n(design-systems): localize webflow DESIGN.md body into 17 locales

* i18n(design-systems): localize cohere DESIGN.md body into 17 locales

* i18n(design-systems): localize duolingo DESIGN.md body into 17 locales

* i18n(design-systems): localize spotify DESIGN.md body into 17 locales

* i18n(design-systems): localize shopify DESIGN.md body into 17 locales

* i18n(design-systems): localize nvidia DESIGN.md body into 17 locales

* i18n(design-systems): localize pinterest DESIGN.md body into 17 locales

* i18n(design-systems): localize uber DESIGN.md body into 17 locales

* i18n(design-systems): localize nike DESIGN.md body into 17 locales

* i18n(design-systems): localize airbnb DESIGN.md body into 17 locales

* i18n(design-systems): localize ibm DESIGN.md body into 17 locales

* i18n(design-systems): localize playstation DESIGN.md body into 17 locales

* i18n(design-systems): localize starbucks DESIGN.md body into 17 locales

* i18n(landing): localize detailSystemLabel (design-system H1/title noun) across 17 locales

* i18n(landing): localize plugins chrome (contribute callout, card CTA, search, about) across 15 remaining locales

* i18n(landing): localized card taglines + category labels for design systems (149 systems x 17 locales)

* fix(landing): suppress on-load locale auto-redirect on design-system detail pages (keep localized routes + hreflang)

* fix(landing): localize SystemCard detail link so cards on /<locale>/ stay in-locale

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-17 15:24:58 +08:00
efc0a85e9d chore(plugin-previews): refresh baked preview manifest (#4442)
Co-authored-by: open-design-bot <bot@open-design.ai>
2026-06-17 15:22:07 +08:00
Chris SeifertandGitHub 526c493c57 fix(web): hide the jump-to-latest button while the conv-history dropdown is open (#4371)
The floating jump button is absolutely positioned at z-index 6 in its own stacking context, and the conversation-history dropdown is z-index 30 in a separate stack, so z-index can't keep the button behind it and it bleeds through the open dropdown. Gate the active class, aria-hidden, and tabIndex on !showConvList so the button hides while the dropdown is open and returns when it closes.

This was originally bundled in #4238; the other half of that PR (a workspace-tab tooltip change) is now obsolete after the entry topbar tooltip-unification, so this lands the still-valid fix on its own.

Fixes #4123
2026-06-17 14:32:47 +08:00
d0d1df8e60 fix(web): portal New Project design-system dropdown so it isn't clipped (#4346)
* test(e2e): red-spec reproducing #4303 design-system dropdown clipping

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

https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6

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

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

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

https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6

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

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

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

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

https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-17 14:32:28 +08:00
fc6994cc93 fix(web): balance finished chat transcripts (#4328)
Generated-By: looper 0.9.10+codex.2ebc216 (runner=worker, agent=codex)

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-17 14:31:55 +08:00
811ad9d118 Show boot stage progress on the desktop splash screen (#4223)
* Show boot stage progress on the desktop splash screen

The splash video plays ~1.7s and then freezes on its final frame while
the packaged cold boot (daemon, web sidecar, Next.js standalone server,
web mount) can take many seconds on slow machines, reading as a hang.

Add a muted status line under the logo with continuously pulsing dots
and stage labels that advance through the real boot phases:

- Starting Open Design (baked into the splash HTML)
- Starting the local engine (daemon sidecar spawn)
- Preparing the interface (web sidecar spawn)
- Opening your workspace (hidden main window loading + mount gate)

Stage transitions follow the repo animation philosophy (140ms ease-out
exit, 200ms ease-out enter). The packaged entry forwards phases through
a new optional onPhase hook on startPackagedSidecars; the runtime
re-asserts the final stage at its reveal gate so the tools-dev splash
path is covered too. setSplashStage is safe on destroyed windows and
idempotent per label.

https://claude.ai/code/session_01MHt6dRc7GMAcu9Npo5Bgdx

* Guard splash stage updates against the page-load race

The first boot-stage update (the daemon phase) is fired from the
packaged entry immediately after the splash window is created, which
can be before the splash data-URL has finished loading and defined
window.__odSplashSetStage. The previous setSplashStage ran the update
unconditionally, so on a fast-spawning cold boot the renderer had no
setter yet and the 'Starting the local engine' label was silently
dropped — on exactly the slow-PC path this feature targets.

Track per-splash load readiness: registerSplashStageTracking arms a
did-finish-load listener before loadURL, and stage updates that arrive
before load are stashed (latest wins) and replayed once the page
reports it has loaded. Updates after load apply immediately as before.

setSplashStage / registerSplashStageTracking now take a narrow
SplashStageSurface so the replay logic is unit-testable without a live
Electron renderer; BrowserWindow satisfies it structurally.

Red spec: tests/main/splash-stage-replay.test.ts — fails when the
deferral is removed (update fires before load), green with the guard.

https://claude.ai/code/session_01MHt6dRc7GMAcu9Npo5Bgdx

* desktop(splash): granular boot stages with step counter and progress bar

The first-run cold boot on a slow machine sat on the brand splash with only
four coarse status labels and no sense of how far along it was, so the wait
read as a possible hang.

Make the boot progress finer-grained and quantified:
- Expand the splash stage set from 4 to 7, marking both the "starting X" and
  "X ready" edges of the two long native waits (local engine online, web
  interface online) plus a final "Almost ready" step, so the status visibly
  advances right after each long wait clears.
- Show a "N/total" step counter and a thin progress bar under the logo that
  fills as stages advance; the bar is monotonic so an idempotent re-asserted
  stage cannot make it jump backwards.
- Emit the daemon-ready / web-ready edges from the packaged sidecar bring-up
  via the onPhase hook so the new stages map to real boot transitions, and
  assert the final "finishing" stage once the web bundle reports it mounted.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: 박세원 <s-w.park@samsung.com>
2026-06-17 14:31:30 +08:00
Kushaal KankaneandGitHub 2139b8c59d feat: enforce 220px minimum width for workspace hover previews (#4021)
* feat: enforce 220px minimum width for workspace hover previews

* test: update hover preview spec for 220px min-width floor
2026-06-17 14:31:16 +08:00
Vitor Cepeda LopesandGitHub 6b034db921 Add Projects refresh control (#3993)
* Add projects refresh control

* Handle projects refresh failures

* fix(web): stabilize projects auto refresh

* fix(web): preserve projects on refresh failure
2026-06-17 14:30:45 +08:00
lefarcenandGitHub 1e2f47fb8d fix(amr): surface vela login URL/code so sign-in survives a failed browser handoff (#4402)
* fix(amr): surface vela login URL/code so sign-in survives a failed browser handoff

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

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

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

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

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

* fix(amr): polish inline auth retry layout

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

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

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

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

* fix(amr): clear stale login activation details

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

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

* fix(amr): tighten inline auth retry state

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

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

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

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

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

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

Addresses review feedback on #4402.

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

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

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

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

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

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

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

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

* Tune absorbed CI runner tiers

* Fold visual validation into CI Playwright shards

* Run PR shards during manual CI dispatch
2026-06-17 14:21:04 +08:00
40056a9ae6 landing: mobile responsive fixes across the home page (#4416)
* landing: mobile responsive fixes for home modules

Rebased onto current main; drops items main already shipped independently
(hero nav clearance, testimonial 238px safe area, mobile nav scroll,
hamburger toggle, live GitHub counts). Remaining unique fixes:

- testimonial: collapse copy/globe to a single column ≤1400px so the
  headline isn't squeezed by the globe at mid widths
- capabilities: flatten head+row (display:contents) into a grid so the
  steps lay out two-up with the DONE mark beside them on mobile
- coding-agent steps: switch the active frame by tap on mobile (the
  scroll-driven reel left every frame stacked when unpinned)
- CTA: put the product window in flow below the buttons with a responsive
  gap so they never overlap (was a fixed 46% that collided with the
  two-line heading)
- footer: lay link sections out as horizontal rows on mobile

* landing: move DONE mark out of <h2> so the capabilities grid binds

The capabilities-head CSS (desktop flex rules at globals.css:2222-2224 and
the mobile grid at 2407-2415) was authored expecting .cap-head-icon to be a
direct child of .capabilities-head. In the markup it was still nested inside
the <h2>, so display:contents flattened only .capabilities-head/.cap-row but
never the heading — grid-area:icon never applied and the DONE mark stayed in
the title row on mobile. Promoting the <img> to a sibling of the <h2> makes
both layouts bind as authored: a flex item beside the heading on desktop
(20px column-gap, margin-left:0) and a grid item beside the two-up steps on
mobile. Verified at 414px: grid-area resolves to icon and the mark renders to
the right of the 01/02 + 03/04 steps.

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-06-17 14:19:45 +08:00
1b149ebe68 fix(web): show sending state on home composer submit (#4111)
* fix(web): show sending state on home composer submit

The Home composer's Send click kicks off an async project/conversation
creation roundtrip, but the button stayed in its idle state until
navigation unmounted the screen — no spinner, no disabled feedback, and
repeat clicks could fire duplicate creations (#4082).

EntryShell now forwards onCreateProject's result through the submit
handler, HomeView holds a sending flag for the whole async tail (a
pending plugin apply and the creation roundtrip — both re-entrable
windows before this change), and HomeHero renders it: the send button
disables itself, swaps its label to the existing chat.comments.sending
string, and folds the flag into canSubmit so the Enter-to-send path is
gated by the same window. A rejected creation — or a submit handler
that throws — re-enables the composer with a visible error and keeps
the staged contexts so the retry sends the same payload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(web): defer spending the example-prompt marker until create is accepted

A rejected create keeps the Home composer retryable, but the one-shot
od:example-prompt-used marker was written while building the onSubmit
payload — before the create's accepted result was known. A failed
attempt therefore spent the marker, so the retry dropped
examplePromptContext and the user lost the example flow they selected.

Decide whether to send examplePromptContext before the await, but only
localStorage.setItem the marker after accepted !== false; reject/throw
paths leave it unspent so the retry resends it. Adds a regression spec.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-17 14:04:56 +08:00
PerishFireandGitHub 891981d460 [codex] Optimize CI runtime topology (#4450)
* Optimize e2e tools-dev runtime parallelism

* Remove visual networkidle wait

* Optimize e2e vitest parallelism

* Optimize Nix flake caching

* Test CI on Blacksmith runners

* Allow parallel manual CI runs

* Tier CI runner sizes

* Temporarily narrow CI debug scope

* Instrument watcher CI timeouts

* Instrument watcher event diagnostics

* Avoid default polling in watcher tests

* Skip runtime trace during watcher debug

* Probe ARM runner tiers for CI

* Focus CI runner probe on x64 browser

* Probe browser workers by runner size

* Probe Playwright file parallelism

* Probe Playwright worker scaling on 8v

* Reshape CI topology

* Fix split E2E Vitest CI lane

* Simplify daemon CI topology

* Optimize Windows payload CI setup

* Revert "Optimize Windows payload CI setup"

This reverts commit 5cbc48c0af.

* Cache better-sqlite3 Nix binding separately

* Revert "Cache better-sqlite3 Nix binding separately"

This reverts commit 0384e3787e.

* Remove unused Nix cache setup from CI

* Use Blacksmith ARM for lightweight CI jobs
2026-06-17 12:53:06 +08:00
87d03692a1 [codex] Load tools-dev env files (#4430)
* Load tools-dev env files

* fix(tools-dev): preserve global help fallback

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

* Make tools-dev env files override shell

* Fix tools-dev env-file option parsing

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

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-17 12:26:00 +08:00
Marc ChanandGitHub 7abb7888df fix(deploy): align Docker defaults with GHCR releases (#4327)
* fix(deploy): align Docker defaults with GHCR releases

Generated-By: looper 0.9.9 (runner=worker, agent=opencode)

* fix(ci): publish stable Docker tags from release workflow

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

* fix(ci): fold reusable workflow guard expression

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

* fix(ci): gate Docker release publish

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

* fix(ci): publish stable Docker tags after release

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

* fix(ci): guard Docker latest tag enable expression

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

* fix(deploy): update Helm chart GHCR defaults

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

* fix(ci): publish latest from release workflow inputs

Generated-By: looper 0.9.9 (runner=fixer, agent=opencode)
2026-06-17 12:25:18 +08:00
yinjialuandGitHub 3c2c3e2cec Fix Langfuse PostHog report closure (#4315) 2026-06-17 12:24:14 +08:00
Christopher BeaulieuandGitHub 7138ec1f35 fix(daemon): normalize stale Codex service_tier=priority before launch (#4276) (#4299)
* fix(daemon): normalize stale service_tier=priority in ~/.codex/config.toml before Codex launch

Codex CLI renamed service_tier="priority" to "fast" in a recent release.
The Codex app's own fast-mode toggle still writes the old value on some
installations, causing the CLI to exit with:

  Error loading config.toml: unknown variant 'priority', expected 'fast'
  or 'flex' in `service_tier`

The CLI parses config.toml before processing any -c overrides, so the
only fix is to patch the file on disk. Before spawning the Codex agent,
the daemon now calls normalizeCodexConfigFile() which replaces any stale
service_tier="priority" with service_tier="fast" in-place, leaving all
other config content intact. Errors (missing file, permission denied) are
silently swallowed so a read-only or absent config.toml never blocks
a launch.

fixes #4276

* fix(codex-config-normalize): line-anchor regex + atomic write + logged errors

Fixes two code-review blockers on the #4276 normalization module:

BLOCKER 1 — regex not line-anchored (data corruption):
Replace the global /\bservice_tier\s*=.../ pattern with a multiline-anchored
pattern /^(\s*)service_tier(\s*=\s*)(["'])priority\3(\s*(?:#.*)?)$/gm.
The new pattern only matches a standalone key line at the start of a line,
so "priority" appearing inside another key's value or inside a comment is
never rewritten. Indentation, original = spacing, and trailing inline comments
are preserved via capture groups.

BLOCKER 2 — unsafe in-place overwrite + swallowed errors:
Replace direct writeFile(configPath) with atomic temp-file + rename:
  writeFile(configPath.<hex>.tmp) → rename(tmp, configPath)
Same-directory temp ensures same filesystem so rename is atomic. Write/rename
failures are now logged via console.warn (matching the daemon pattern) instead
of a bare catch {}. An injectable CodexConfigIO interface is exported so tests
can stub the rename to exercise the failure path without filesystem tricks.
Temp file cleanup is attempted on failure; secondary cleanup errors are ignored.

Tests: 11 new regression cases added to codex-config-normalize.test.ts:
- BLOCKER 1: priority in unrelated value/comment NOT rewritten; trailing
  inline comment preserved; indentation preserved; flex/fast untouched;
  real key coerced even when priority appears elsewhere in the file.
- BLOCKER 2: no temp-file litter on success; full content correct after
  atomic write; rename failure logged and does not throw; unlink attempted.

* fix(codex): pass merged spawn env to normalizeCodexConfigFile (#4276)

The call site in server.ts was passing bare `process.env` to
`normalizeCodexConfigFile`. If a user configured CODEX_HOME via
Open Design's agentCliEnv.codex, the normalizer resolved the wrong
path (~/.codex/config.toml) and left the real config at the user's
CODEX_HOME with a stale service_tier="priority" value untouched.

Fix: pass the same merged env the Codex child launches with —
`{...process.env, ...(def.env||{}), ...configuredAgentEnv}` — so
resolveCodexConfigPath sees the same CODEX_HOME the child will see.

Also adds:
- FIX 1 regression tests: positive case (CODEX_HOME in merged env is
  used) and negative case (without CODEX_HOME, default path is used)
- FIX 2 CRLF regression test: config.toml with CRLF line endings has
  service_tier coerced to "fast" with all \r\n sequences preserved

FIX 3 (logging): console.warn at codex-config-normalize.ts:138 is
left as-is — no structured logger is trivially in scope at the call
site without extending the CodexConfigIO injection pattern, and the
reviewer confirmed console.warn already matches daemon conventions.

* fix(codex): expand tilde in CODEX_HOME before normalizing config path (#4276)

resolveCodexConfigPath now calls expandHomePath on the CODEX_HOME env value
before passing it to path.join. Without this, a user-configured
CODEX_HOME="~/.codex-alt" resolved to the literal path
"~/.codex-alt/config.toml" in the normalizer while the Codex child process
(via spawnEnvForAgent → expandConfiguredEnv) resolved it to the absolute
"<homedir>/.codex-alt/config.toml". The stale service_tier="priority" config
at the real expanded path was therefore never found and never patched.

Also routes the server.ts normalizer call through spawnEnvForAgent('codex', …)
instead of a hand-rolled env merge, mirroring the diagnostics-export.ts
`envFor('codex')` pattern to permanently eliminate drift between the env the
normalizer sees and the env the Codex child actually receives.

Adds two regression tests for the tilde case (RED before this fix, GREEN
after): one unit-level assertion that resolveCodexConfigPath expands "~/" to
an absolute path, and one end-to-end assertion that a stale config at the
expanded location is patched when CODEX_HOME contains a tilde prefix.

Refs #4276
2026-06-17 12:22:11 +08:00
Marc ChanandGitHub 4b232247b3 refactor(daemon): split server route registrars (#4391)
* refactor(daemon): split server route registrars

* Move media routes into daemon routes

* test(daemon): cover extracted design-system routes

Generated-By: looper 0.9.10 (runner=fixer, agent=codex)
2026-06-17 12:21:35 +08:00