Commit Graph
2508 Commits
Author SHA1 Message Date
lefarcenandGitHub c0b5db2cd4 [codex] Bump bundled Vela CLI to 0.0.19 (#4888)
* chore: bump bundled vela cli to 0.0.19

* chore: refresh nix pnpm deps hash
2026-06-29 12:08:42 +00:00
fc4e51871c [codex] Keep prefetched brand pages previewable (#4530)
* Keep prefetched brand pages previewable

* Scope brand reconcile to extraction conversation

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

* Stabilize BrandsTab polling test

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

* Stabilize conversation run status ordering

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

* Preserve stale ready brand terminal failures

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

* Scope brand reconciliation to extraction run

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-29 09:56:58 +00:00
12ee8d05eb [codex] Track trace touched files for reopen flows (#4432)
* Track touched files for trace object uploads

* Fix trace touched-file cleanup and aliases

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

* Scope trace touched files per run

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

* Fix reattach trace telemetry finalization

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

* Fix full replay trace object files

Use replayed reattach events when reconstructing touched trace object files during full replay, and cover the finalized save path with a focused regression.

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

* Scope pending write tracking per run

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

* Guard trace touched-file path matching

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

* Retrigger workspace validation

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-29 09:52:53 +00:00
81be4f6bb5 feat(landing-page): upgrade 5 tutorials to long-form guides + real app screenshots (batch 1) (#4807)
* feat(landing-page): upgrade 5 tutorials to long-form guides with real app screenshots (batch 1)

Following the 20-minute pilot, upgrade five thin catalogue entries into full,
original, English long-form tutorials, each based on a community creator's video
(credited + embedded), fact-corrected against the current release:

- install-demo (Chase AI) — install + demo + design systems verdict
- local-setup-ollama (AI Automation Station) — fully-local, BYO local agent
- setup-gemini-cli (Sandeep Singh) — Gemini CLI as the driving agent
- windows-wsl (AI Automation) — Windows 11 via WSL
- overview (WorldofAI) — concept + capabilities overview

Each uses real in-app Open Design screenshots (workspace / design-system picker /
templates), the current install commands (dynamic port, no hardcoded URL), OD's
own narrative, and no hardcoded catalog counts. English-first; localization to
the keep-11 locales follows for the winners (non-English falls back to the
existing placeholder, unchanged).

* fix(landing-page): use working 'od mcp install' for agent install in batch-1 tutorials

The curl https://open-design.ai/install.sh pipe 404s. Replace it across all five
tutorials with the documented working path: 'od mcp install <agent>' (README
Platform Compatibility), which wires OD's MCP server into the chosen agent once
Open Design is installed.

* docs(landing-page): clarify that the od CLI ships with Open Design in agent-install note

* fix(landing-page): correct WSL setup in windows-wsl tutorial (nvm bootstrap + od wrapper)

Per docs/wsl-setup.md, fix two steps a fresh reader would hit:
- Install nvm before 'nvm install 24' (a clean Ubuntu has no nvm command).
- Add the WSL od wrapper in ~/.local/bin before 'od mcp install', since
  /usr/bin/od (octal dump) otherwise shadows Open Design's od on Linux/WSL.

* fix(landing-page): make WSL clone path explicit so the od wrapper matches

nettee flagged that the od wrapper hardcodes $HOME/open-design while Option B
only said 'git clone … && cd open-design' (lands in the current dir). Clone
explicitly into ~/open-design so the wrapper's repo path always matches a
copy-paste WSL flow.

* chore(landing-page): re-trigger CI on latest head (no-op)

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-29 09:47:16 +00:00
8fa6c5e198 [codex] Add run lifecycle tracing (#4431)
* Add run lifecycle tracing fields

* Fix lifecycle artifact and stdin timing

* chore: retrigger workspace validation

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

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
Co-authored-by: a1chzt <chizblank@gmail.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-29 09:37:39 +00:00
lefarcenandGitHub cbf3882e7e [codex] Reset PR inactivity window on human activity (#4882)
* fix: reset PR inactivity window on human activity

* fix: handle commit and failed CI blocker detection
2026-06-29 07:30:11 +00:00
open-design-bot[bot]GitHubopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
dbd280610e docs(readme): refresh contributors wall (#4832)
Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
2026-06-29 07:16:33 +00:00
cadd296ef2 feat(landing): add 0.11.0 and 0.12.0 release blog posts (#4860)
* feat(landing): add 0.11.0 and 0.12.0 release blog posts

Add two release-recap posts mirroring the existing 0.8/0.9/0.10 format:
- 0.11.0 "the Bazaar": live-preview plugin gallery, bring-your-own coding
  agent, guided welcome, the biggest stability pass yet.
- 0.12.0 "your brand is a design system": brand-to-reusable-design-system
  pipeline, named failure causes, browser-handoff sign-in fix.

Each post ships English source plus 10 Agent-translated locales
(zh/ja/ko/de/fr/ru/es/pt-br/it/tr) matching the blog's canonical locale set,
a cover plus two inline figures in the warm editorial illustration style of
the vibe-design cluster, and a postImages entry on the blog index.

astro check: 0 errors. build:static: 3977 pages.

* fix(landing): localize internal links in translated blog bodyHtml

Related-post anchors inside a post's localized bodyHtml were hard-coded to the
root /blog/... routes, so on a non-English page they dropped the reader back
onto the English posts. Rewrite root-relative <a href> links through
localizedHref(locale) after TOC injection, so a localized post keeps its
cross-links inside the reader's locale. Image src stays root (assets are not
localized); external, mailto/tel, and #anchor links are untouched; default
locale is a no-op. Fixes it uniformly for every localized post, not just the
two new ones.

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-29 04:22:17 +00:00
Vitor Cepeda LopesandGitHub 687b651ebc fix(web): space built-in skill edit warning (#4230)
* fix(web): space built-in skill edit warning

* chore: preserve plugin inputs eof spacing

* fix(web): align built-in skill warning spacing
2026-06-29 04:05:20 +00:00
CaipingPengandGitHub 26fe57af45 Fix chat splitter scrollbar hit area (#4583) 2026-06-29 04:05:17 +00:00
lefarcenandGitHub db402294d7 docs: add agent CLI contract registry spec (#4841) 2026-06-29 04:05:08 +00:00
AmyandGitHub b55376554b test(e2e): expand onboarding, AMR, automation, and home coverage (#4759)
* test(e2e): cover onboarding and automation flows

* test(e2e): stabilize AMR project runtime P0 group

* test(e2e): cover updated home creation surface

* test(e2e): align onboarding coverage with build step

Generated-By: looper 0.9.11 (runner=fixer, agent=codex)
2026-06-29 03:56:19 +00:00
22c1e3aff4 feat(web,landing): Workspace-for-Teams entry chip + enterprise lead page (#4737)
* feat(web,landing): Workspace-for-Teams entry chip + enterprise lead page

Validate demand for a team/workspace edition.

web (apps/web):
- Add a neutral "Teams" chip to the Home top-right toolbar that opens the
  enterprise landing page in the external browser. The URL carries the
  client's active locale so the page opens in the same language (falls back
  to English for locales the landing site doesn't ship). Dev points at the
  local landing dev server; prod at open-design.ai.
- New analytics element `workspace_teams` on home toolbar clicks.
- i18n key `entry.workspaceTeams*` across all 19 locales.

landing (apps/landing-page):
- New /enterprise/ (+ localized [locale]/enterprise/) contact-sales page in
  the light Atelier Zero style: pitch + perks, a wordmark social-proof wall,
  and a lead form (name, work email, company, team size, multi-select use
  cases, role, message). Custom inline validation (no native browser
  bubbles). Page is intentionally outside every top-nav tab.
- contact-sales Pages Function validates leads and fans them out to a Feishu
  custom-bot webhook with a Workers KV backup.

contracts:
- Add `workspace_teams` to HomeToolbarClickProps.

* feat(landing): flesh out Workspace-for-Teams enterprise page

- Real brand logo wall via Simple Icons CDN (denser 12-logo grid)
- Custom styled Team size / Monthly budget dropdowns (no native popup)
- Monthly budget question (USD ranges) wired into the lead payload
- Early-access incentive callout
- Use-case demo reuses the homepage Labs stage (magnifying dock, auto-cycle, video)
- Discord community invite card in the left column (link, not a form field)
- contact-sales: validate budget, drop joinDiscord, no-store header

* feat(landing): instrument Workspace-for-Teams page with PostHog events

Reuses the shared __odTrack delegate (sub-page-layout). page_view and the
Discord-card join_discord click are already auto-captured; this adds the
lead-funnel events the delegate can't see:

- lead_submit_attempt / lead_submit_success / lead_submit_failed
- lead_submit_invalid (with the missing field list) on validation block
- demo_click when a user picks a Labs demo tile
- data-od-id on the page/demos sections so ui_click area resolves correctly

* fix(web,i18n): localize Workspace-for-Teams chip label and tooltip for zh

The Teams chip label key was hardcoded to "Teams" in every locale, so the
button never localized. Chinese now reads 团队版 (zh-TW 團隊版). Also reword the
tooltip/aria away from the awkward "Workspace 团队版 — …告诉…诉求" mixed copy to
"团队版工作区 — 告诉我们你的团队需求" (zh-TW 團隊版工作區 — …需求).

* feat(landing): localize Feishu lead card to Chinese + require a business email

The enterprise lead card now renders Chinese labels/values for the internal
sales group, and the Cloudflare Function rejects free/personal mailboxes
(Gmail/QQ/163/...) with error "personal_email" so every lead carries a
company domain.

* feat(landing): block personal mailboxes in the enterprise form client-side

Mirrors the Function's business-email rule in the inline validator so a
personal mailbox is caught before submit, and reworks the localized email
error copy (en/zh/zh-tw) to explain why a work email is required.

* chore(preview): redeploy to pick up corrected staging Feishu webhook

* revert(landing): drop the business-email requirement — accept any valid email

Per product: the enterprise lead form should accept ANY valid email, not just
company domains. Removes the personal-mailbox blocklist + checks from both the
Function and the client validator, and restores the original email error copy.
The Chinese Feishu card localization is kept.

* fix(web): keep the Teams entry reachable on narrow screens

The topbar chip group is hidden under 900px, so the Workspace-for-Teams
chip had no narrow-screen fallback (unlike Discord/X which live in the
settings menu). Adds a Teams item to EntrySettingsMenu, extracts the
enterpriseUrl helper into a shared module so both surfaces share one
source, and allows element=workspace_teams on settings_popover tracking.

Addresses review feedback on #4737.

* fix(web): limit enterprise locale URLs

---------

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-29 03:34:31 +00:00
Tom HuangandGitHub a915da2c66 feat(plugins): duplicate examples into projects (#4861)
* feat(plugins): duplicate examples as projects

* fix(plugins): gate duplicate projects by HTML support

* fix(plugins): preserve duplicate entry navigation
2026-06-29 01:44:38 +00:00
23704a9d54 feat(landing-page): add 5 design-agent alternative comparison pages (Stitch, Genspark, Figma Make, Qoder, Trae) (#4853)
* feat(landing-page): add 5 design-agent alternative comparison pages

Add /alternatives/{stitch,genspark,figma-make,qoder,trae}/ pages comparing
Open Design with five AI design/coding tools. Each page carries deeply
researched, fact-specific copy (pricing, usage limits, lock-in, honest
trade-offs), real competitor screenshots plus current Open Design product
screenshots, a feature table, and a decision matrix.

Rebuild the shared alternative-detail renderer onto an editorial band layout
(full-width alternating bands, one unified content column, dark closing CTA
band) so every /alternatives/ page is visually consistent. Render list and
table block text through set:html so inline <b> emphasis works.

Localise all five pages into the 11 landing locales (machine-translated then
native-audited) and re-shard into alternatives-i18n.part-*. Wire the new slugs
into the /compare/ hub and the footer. Save the reusable current Open Design
UI screenshots under docs/screenshots/current-2026-06/.

* fix(landing-page): address review on alternatives layout

- clip page-level horizontal overflow on .v4 pages so the 100vw full-bleed
  shell no longer jitters when a vertical scrollbar is present
- port the FAQ accordion refinements (border, padding, type scale) under .v4
  using the landing token set, since the rich wrapper moved off .solution-page

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-28 13:17:43 +00:00
b784c86507 feat(landing): first-touch attribution cookie for source→payment (#4820)
* feat(landing): first-touch attribution cookie for source->payment

Capture utm_* + external referrer on landing into a first-touch od_attr
cookie on the open-design.ai domain, so the same-origin vela checkout page
(open-design.ai/cloud/*) can read it back and attribute payment to the
originating traffic source. Forward-only; first-touch wins; sets nothing for
true direct traffic. Companion vela PR reads it into billing_payment_result.

* fix(landing): mount attribution cookie on bespoke marketing heads

blog/{index,[slug]}, tutorials/{index,[slug]}, stories/{index,ikigai-one}
have standalone <head> blocks that don't use sub-page-layout, so they only
had GoogleAnalytics. Add AttributionCookie to each so utm/referrer landing on
those marketing entry points (e.g. /blog/...?utm_source=) is captured instead
of resolving to direct at checkout. Addresses PR review coverage gap.

* refactor(landing): bundle head analytics into shared SiteAnalytics

Replace the per-page GoogleAnalytics / PostHogAnalytics / AttributionCookie
wiring with a single <SiteAnalytics /> mount used by every landing template
(sub-page-layout, home, and the bespoke blog/tutorials/stories heads). This
makes it structurally impossible for a marketing entry point to silently miss
a tracker — the cause of the attribution-cookie coverage gap.

Intentional coverage change: the bespoke blog/tutorials/stories pages
previously had ONLY GoogleAnalytics; they now also get PostHog (they were
already missing it). Supersedes the per-page cookie mounts from the previous
commit.

---------

Co-authored-by: Scarlett Huang <scarletthuang@Scarletts-MacBook-Air.local>
2026-06-26 14:05:59 +00:00
lefarcenGitHubopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
fbce1ddfa5 feat(daemon): native session resume across turns (codex / opencode / pi / AMR) (#4629)
* feat(daemon): codex native session resume (capture-style)

Codex follow-up turns re-pay the whole conversation as cache-cold input:
the daemon flattens history into a fresh user message every turn and starts
`codex exec` from scratch, so codex rebuilds its own structure and the
upstream prefix cache from the previous turn no longer matches. Measured on
real codex (consecutive turns): resume reuses 96% of the prefix vs 39% for
flattened-resend — ~15x fewer recomputed tokens.

Generalize the claude-style `resumesSessionViaCli` path to codex, which is
"capture-style": codex mints its OWN thread id and reports it on the first
stream event `thread.started`, so the daemon must capture that id and replay
it rather than specifying one (claude `--session-id`).

- types: add `capturesSessionIdFromStream` to distinguish capture-style from
  specify-style resume adapters.
- codex def: `resumesSessionViaCli` + `capturesSessionIdFromStream`; buildArgs
  emits `exec resume <thread_id>` when a stored handle exists, else `exec`.
  `exec resume` rejects `--sandbox`, so the sandbox is passed as
  `-c sandbox_mode=...` so the per-turn context block byte-matches the create
  turn and does not break the prefix.
- json-event-stream: capture `thread.started.thread_id` onto the status
  event's `sessionId`.
- server: capture the reported id and persist THAT (not the unused minted
  `newSessionId`) on a create turn; skip the transcript resend on resume.
- resume-missing fallback: detect codex `no rollout found for thread id`
  (generalized `isAgentResumeFailure` dispatch), clear the stale handle, and
  surface a retryable error so the next turn re-seeds the full transcript —
  one cold turn, never a broken conversation. The check runs BEFORE the
  generic stream-error short-circuit so a stale handle is always cleared.

Tests: codex buildArgs create/resume shapes; thread.started capture (+ null
case); codex resume-failure detection + dispatch; and an end-to-end real-
daemon spec (capture -> resume without history resend; dead-thread fallback ->
fresh exec next turn).

* feat(daemon): opencode native session resume (capture-style)

Extend the capture-style resume infra (codex) to OpenCode direct (~16% of
users). Same shape: OpenCode mints its own session id and stamps it on every
stream event as `sessionID` (e.g. `ses_...`); the daemon captures it and
continues the session with `opencode run -s <id>` on the next turn instead of
re-flattening the transcript, so the first upstream call reuses the warm prefix
cache. Measured on real OpenCode: turn-2 resume = input 162 + cache_read 8192
(~98% reused) vs cache_read 0 cold.

- opencode def: thread `runtimeContext` through buildArgs; emit `-s <id>` on a
  resume turn, plain `run` on create; `resumesSessionViaCli` +
  `capturesSessionIdFromStream`.
- json-event-stream: capture `step_start.sessionID` onto the status event's
  `sessionId` (OpenCode stamps it on every event; step_start is the opener).
- resume-missing fallback: `isOpencodeResumeFailure` (`Session not found` /
  `NotFoundError`) wired into `isAgentResumeFailure`. Verified against the real
  CLI: `run -s <missing>` prints `Error: Session not found` to stderr and exits
  0 — the hoisted fallback clears the stale handle regardless of exit code, so
  the next turn re-seeds the full transcript (one cold turn, never broken).

Tests: opencode buildArgs create/resume shapes; step_start session capture (+
null case); session-not-found detection + dispatch; and an end-to-end real-
daemon spec (capture -> resume without history resend; dead-session
fallback -> fresh run next turn, exercising the exit-0 failure path).

* fix(daemon): gate codex `-C`/`--add-dir` to create turns (rejected by exec resume)

`codex exec resume` rejects the create-only `-C <cwd>` and `--add-dir <dir>`
flags (`error: unexpected argument '-C' found`), so the resume branch falling
through the shared appends would make every follow-up Codex turn die before the
first event. The daemon already spawns the child with `cwd: effectiveCwd`, and
resuming by explicit SESSION_ID does not use codex's cwd-based session
filtering (verified: resume by UUID succeeds from any cwd), so the resumed turn
runs in the right workspace without `-C`; the extra writable dirs were granted
when the session was created and ride along with the resumed session.

- codex def: gate `-C` / `--add-dir` to `!resumeSessionId`.
- unit: resume argv excludes `-C` / `--add-dir` even when cwd + extra dirs are
  supplied; create argv still includes both.
- e2e: the fake codex now rejects `-C` / `--add-dir` on resume exactly like the
  real binary, so the regression is caught end-to-end; chat-turn filtering keys
  off the spawn cwd (no `-C` to match on resume turns).

Reported by @nettee on #4629.

* fix(daemon): resume identity guard — reseed on intervening turns / model / cwd

Setting `resumesSessionViaCli` for codex/opencode widened the transcript-skip
path, but `agent_sessions` only keyed on (conversation_id, agent_id). A
conversation like `Codex -> other agent -> Codex` would resume the stale codex
session and skip the intervening turns, so the resumed agent silently lost
visible conversation state (reported by @nettee on #4629). The keying also did
not encode model/cwd, so a model/cwd switch could keep resuming a session built
under different parameters (raised by @PerishCode on #4627).

Persist a resume identity with each session row and only resume when it still
matches:
- `model` / `cwd` — the runtime identity the upstream session was created with;
  a change forces a fresh session.
- `last_message_id` — the assistant message the session last produced. At the
  next turn's resolve time the latest completed assistant message (excluding the
  current run's in-flight placeholder) must still be that id; otherwise another
  agent ran in between (or it was edited away) and the session is behind.

On any mismatch `resolveAgentResumeContext` returns `isResuming: false` (with an
`invalidationReason`), so the daemon starts a fresh session reseeded with the
full transcript — worst case one cold turn, never amnesia. A null cursor (legacy
row) is treated as unverifiable and reseeded once. The cursor is advanced on
every successful create AND resume turn so back-to-back same-agent turns keep
resuming.

Tests: resolveAgentResumeContext invalidation matrix (in-sync resume, current
placeholder excluded, model_changed, cwd_changed, conversation_advanced,
missing_cursor); agent_sessions identity round-trip; and an end-to-end
`codex -> claude -> codex` spec asserting codex reseeds (fresh `exec`, no
resume) after the intervening turn.

* fix(daemon): persist resume identity on the pi capture path too

The identity guard routes pi-rpc through resolveAgentResumeContext, but pi
persists via persistCapturedAgentSession() which only wrote session_id +
stable_prompt_hash. After one successful pi turn the row came back with
model/cwd/last_message_id = null, so the guard returned `missing_cursor` and
reseeded every turn — silently disabling pi's existing follow-up-session path
(reported by @nettee on #4629).

Extend persistCapturedAgentSession to store model/cwd/last_message_id and pass
them from the pi-rpc call site (run.model / effectiveCwd / run.assistantMessageId),
so a successful pi turn keeps a verifiable identity and resumes next turn.
Regression test: a stored pi session with the identity resumes; the existing
clear-on-no-capture path is unchanged.

* fix(daemon): scan only the CLI failure channel for resume-miss, not assistant stdout

The resume-miss fallback fed both agentStderrTail AND agentStdoutTail into
isAgentResumeFailure(). agentStdoutTail holds ordinary assistant text, so the
OpenCode matcher (generic /session not found/i) could fire on a SUCCESSFUL turn
whose model output merely mentioned the phrase — clearing the stored session
and failing the turn (reported by @nettee on #4629).

Detect resume-miss only from each CLI's failure channel: codex/opencode match
stderr only; Claude matches prose on stderr and its structured stream-json
result event on stdout (never the prose against stdout). Regression test: a
generic phrase in successful assistant stdout does not trigger a resume miss.

* fix(daemon): resume cursor counts only succeeded assistant turns

latestCompletedAssistantMessageId is documented and consumed as the latest
COMPLETED assistant turn for the resume-identity guard, but the query matched
any assistant message regardless of run_status. A sequence like
`codex success -> other agent fails/cancels before output -> codex again` read
the failed/canceled placeholder as conversation advancement, returned
`conversation_advanced`, and forced a needless cold reseed — silently disabling
the resume perf path even though no completed turn was added after the stored
session.

Filter the cursor to `run_status = 'succeeded'` (a run stamps its terminal
status on finish; in-flight placeholders are null and were already excluded).

Adds a red-spec (db-agent-sessions: intervening failed/canceled run does not
advance the cursor) and makes the resolveAgentResumeContext fixtures faithful
by stamping completed assistant turns 'succeeded' and placeholders null.

Reported by @nettee on #4629.

* fix(daemon): resume cursor admits the session own failed turn (resume-on-failure)

The run_status='succeeded' cursor filter regressed the resume-on-failure path:
a transiently-failed-but-resumable turn persists a session pointing at its own
FAILED assistant message, but that message was then excluded from the cursor, so
resolveAgentResumeContext returned conversation_advanced and the next turn cold-
restarted instead of --resume (broke run-resume-on-failure.test.ts).

Admit the stored session's own lastMessageId through the filter via a new
`resumableMessageId` arg: the session it owns still matches its cursor, while a
DIFFERENT later failed/canceled turn stays excluded and a later succeeded turn
is still detected as genuine advancement.

Adds two guard tests: a stored failed cursor still resumes, and a later
succeeded turn after the stored failed turn still reseeds.

Reported by @nettee on #4629.

* feat(daemon): AMR (ACP) session resume — capture durable handle + session/load + resume_failed

Wire the AMR/vela runtime into session resume, mirroring the pi-rpc capture
pattern (the handle comes from the ACP result, not a --session-id flag or a
stream status event):
- acp.ts: attachAcpSession accepts resumeSessionId and drives `session/load`
  (instead of session/new) to resume the prior upstream session; captures the
  durable `openCodeSessionId` from the result and exposes getDurableSessionId().
- new def flag resumesSessionViaAcpLoad (set on amr.ts) opts AMR into resume
  without colliding with resumesSessionViaCli / capturesSessionIdFromStream.
- server.ts: agentSupportsSessionResume includes it; pass the stored handle as
  resumeSessionId on a resume turn (guarded by the resume-identity check);
  persist the captured durable handle on success via persistCapturedAgentSession
  (with model/cwd/lastMessageId); extend the resume-failure reseed gate.
- agent-session-resume.ts: isAmrResumeFailure matches vela's structured
  {"kind":"resume_failed"} on stdout (the ACP channel), and isAgentResumeFailure
  dispatches 'amr' to it. skipTranscript already follows isResuming.

Tests: session/load drive + durable-handle capture (acp.test); isAmrResumeFailure
structured match (stdout only, not bare prose). Daemon typecheck + guard +
existing AMR integration / resume suites green.

* test(daemon): AMR resume integration — session/load drive, durable handle, resume_failed

Extend fake-vela.mjs with openCodeSessionId on session/new, a session/load
handler that echoes the durable handle, and FAKE_VELA_RESUME_FAILED to emit the
structured resume_failed on prompt. Integration tests: a resume turn drives
session/load and captures the handle; a missing resumed session surfaces
resume_failed and does not complete.

* fix(daemon): clear AMR resume handle on resume_failed before fatal short-circuit

vela reports a missing/expired upstream OpenCode session as a structured
`resume_failed` JSON-RPC error on session/prompt, which the ACP bridge turns
into a fatal. The server close handler's `hasFatalError()` short-circuit ran
BEFORE the resume-failure reseed block, so for AMR (resumesSessionViaAcpLoad)
the dead durable handle was never cleared — every later turn re-issued
session/load against the same dead session and failed forever (#4275 class).

Hoist the resume-failure recovery (clear stale handle + retryable reseed error)
above the fatal/stream-error short-circuits so it fires for both the codex
stream-error shape and the AMR structured-fatal shape.

Add server-level coverage (amr-session-resume.test.ts) driving the FULL close
handler through startServer + fake-vela: happy session/load resume, the
dead-resume -> reseed cycle (red without this fix), null durable handle ->
fresh session, and model-change -> fresh session. fake-vela gains a didLoad
gate (resume_failed fires only on a resumed turn), an invocation log, a
--version handler, and an omit-handle knob.

* fix(daemon): resume guard keys off the concrete launched model

The resume-identity guard compared the raw request model (`run.model`, often
`default`/null) and persisted that into `agent_sessions.model`, but the model
actually launched is `safeModel` — for AMR the preflight rewrites a `default`
request to the live catalog's first entry. So a conversation that ran under an
implicit default stored `null`/`default`; changing the effective default
between turns would still pass the guard and resume the old upstream session
under the wrong model (skipping transcript reseeding).

Hoist model resolution above the resume guard so it (and every
`agent_sessions.model` write) keys off the concrete launched model. The AMR
default->live-catalog rewrite is mirrored before the guard (read-only, cached);
the existing preflight stays authoritative for auth/availability.

Adds a red-spec: a default turn followed by an equivalent explicit model now
resumes (was a needless cold reseed). Reported by @nettee on #4704.

* chore(pack): bump bundled @powerformer/vela-cli to 0.0.18-test.0

Pulls the AMR OpenCode session-reuse changes (powerformer/vela#434, built from
its feature branch via the vela-cli test channel) into the packaged bundle so a
beta build can validate AMR session resume end-to-end. Reverts to a stable
@powerformer/vela-cli pin once #434 ships to vela main.

* chore(nix): refresh pnpm deps hash

* feat(daemon): transparently auto-reseed when a resumed session is gone

When a resume-capable agent (claude/codex/opencode/AMR) tries to resume an
upstream CLI session that has expired/pruned, the daemon previously surfaced a
retryable "previous session could not be resumed — resend" error and made the
user re-send. That is a visible blemish on what is meant to be an invisible
optimization.

Now the daemon recovers transparently: it clears the dead handle and re-runs the
SAME turn once with a fresh session + the full transcript rebuilt from the DB —
exactly the pre-session-reuse path. The user sees one (slightly slower) turn,
never an error. Reuses the existing same-run retry machinery (scheduleRetryRestart);
the re-spawn resolves isResuming=false so it cannot resume-fail again, and a
`resumeAutoReseeded` guard is belt-and-suspenders against any loop.

Observability: emits an `agent_resume_auto_reseed` diagnostic into the per-run
events.jsonl (bundled by the help → diagnostics export, so the full resume →
fail → reseed chain is visible in a support bundle with no user-facing signal),
and adds a `resume_auto_reseeded` field to the run_finished analytics so the
fallback frequency can be monitored (should be rare).

Updates the AMR/codex/opencode dead-session server tests to assert the turn now
succeeds transparently, and adds run-diagnostics coverage for the new flag.

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

* chore(pack): bump bundled @powerformer/vela-cli to 0.0.18-test.1

Pulls the OpenCode interactive-question-tool fix (powerformer/vela#434:
OPENCODE_CLIENT=acp withholds the question tool over the ACP bridge, which was
crashing AMR turns with an empty-output failure) into the packaged bundle for
the QA beta.

* chore(nix): refresh pnpm deps hash

* fix(daemon): keep AMR same-turn resume reseed invisible (suppress resume_failed error)

When an AMR (vela) run resumes an upstream session via session/load and that
session is gone, the ACP bridge calls fail() -> send('error') for the failed
load BEFORE the child-close handler clears the stale handle and re-runs the turn
fresh. The forwarded error flashed a client-visible execution failure — and
tripped any client treating an SSE `error` as terminal — a beat before the
recovery that is supposed to be invisible.

Hold the error back in the ACP send wrapper when this run is resuming via
session/load and the agent reports resume_failed: emit a non-user-visible
`agent_resume_failed_suppressed` diagnostic instead of forwarding the error. The
close handler stays the sole authority on whether the turn ends in an error or a
transparent reseed; the resumeAutoReseeded guard still lets a second resume
failure fall through to the explicit "resend your message" affordance.

Red spec: amr-session-resume.test.ts asserts the run event log carries no
client-visible `error` event during the transparent reseed (only the
suppression diagnostic), going red on the pre-fix code (an `error` event with
kind=resume_failed) and green after.

* test(daemon): cover resume reseed event invariants

---------

Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
2026-06-26 14:05:37 +00:00
OrbisAI SecurityandGitHub 1943131ced fix: multiple subprocess calls accept user-controlle... in index.ts (#4754)
* fix: V-001 security vulnerability

Automated security fix generated by OrbisAI Security

* fix: multiple subprocess calls accept user-controlle... in index.ts

Multiple subprocess calls accept user-controlled arguments without proper validation or sanitization, allowing attackers to inject shell metacharacters and execute arbitrary commands on the host system

* Apply code changes: Hey @orbisai0security — @PerishCode's blocking rev...
2026-06-26 13:56:50 +00:00
open-design-bot[bot]GitHubopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
59214704f6 docs(readme): refresh contributors wall (#4719)
Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
2026-06-26 13:55:47 +00:00
Hashim KarimandGitHub d262f79fb6 fix develop menu shortcut fallback (#4642) 2026-06-26 13:54:29 +00:00
aad9771a6f fix(e2e): reduce noisy visual regression diffs (#4744)
* fix(e2e): reduce noisy visual regression diffs

* fix(e2e): keep visual captures full viewport

* test(e2e): add entry popover visual targets

* test(e2e): tighten model dropdown visual targets

* Revert "test(e2e): tighten model dropdown visual targets"

This reverts commit 52172f05591e1a5c2bed7b6fc12d05d364d5b27d.

* fix(e2e): relax visual report diff ratio threshold

* fix(e2e): render visual report comparisons horizontally

* fix(e2e): tighten accepted visual diff ratio

* fix(e2e): surface missing visual baselines as new cases

* fix(e2e): render new visual baselines in a grid

* fix(e2e): compact visual report case layout

* fix(e2e): keep large visual diffs surfaced

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

* fix(e2e): seed privacy consent in project-runtime tests

* fix(e2e): harden project-runtime settings mocks

* fix(e2e): stabilize project-runtime follow-ups

---------

Co-authored-by: mrcfps <mrc@powerformer.com>
2026-06-26 10:30:22 +00:00
1319bcef2e chore: prune curated official example plugins (#4815)
Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-26 10:01:44 +00:00
fd408c533f [codex] Clean up onboarding brand UI (#4813)
* fix(web): clean release onboarding brand UI

* fix(web): clear stale loading shell after mount

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

* test(e2e): align home composer router coverage

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-26 09:58:30 +00:00
c26201437f landing: polish the Ikigai One story — real logo, ikigai.one link, social share card (#4809)
* landing: link Ikigai One name to ikigai.one in customer story

Hyperlink the "Ikigai One" company name in the story's snapshot/identity
card through to the customer's own site (https://ikigai.one/), across the
English page and all 17 localized variants. Gives the featured customer
outbound exposure and a dofollow backlink, and makes the story read as a
real, linkable case study rather than an anonymous reference. Opens in a
new tab so readers stay on the OD story; card typography is unchanged
(underline on hover only).

* landing: use Ikigai One's real logo in the customer story card

Replace the placeholder "I" letter mark with Ikigai One's actual brand
icon in the story's snapshot card, across the English page and all 17
localized variants. Adds the logo asset (128px PNG from their square app
icon) and switches .v4snap-logo from a styled letter to an image slot.

* landing: dedicated social share card for the Ikigai One story

Point the story's og:image / twitter:image at a new standalone share card
(the "Open Design = Unfair Advantage" user-story header) instead of reusing
the in-article cover, so the X/social link preview can change without
touching any image in the article body. Adds ikigai-one-og.jpg (1200x675);
all 18 locale variants render the canonical page so they share the new card.

---------

Co-authored-by: ScarletttMoon <scarletttmooon@gmail.com>
2026-06-26 08:59:20 +00:00
3a92f8a011 Add web effect extractor scenario (#4811)
Co-authored-by: tuolaji <tuola@tuolajideMacBook-Air.local>
2026-06-26 07:15:53 +00:00
488e3d6a6d [codex] Refine rich design-system chip previews (#4806)
* fix(web): refine design system chip preview

* fix(e2e): extend home catalog visual capture budget

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

* fix(web): restore home ask mode toggle

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

* fix(e2e): dismiss consent before settings menu click

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

* fix(web): remove Hyundai preset brand

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-26 06:37:25 +00:00
41f11f478f feat(analytics): split project_kind by Home task card (wireframe/mobile/document) (#4769)
* feat(analytics): split project_kind by Home task card

The created-project analytics `project_kind` collapsed several Home task
cards into coarse buckets: Wireframe / Mobile / Live artifact all reported
`prototype`, and Document reported `other`, so a created project's kind no
longer matched the `task_chip` the user picked.

Extend `TrackingProjectKind` with `wireframe` / `mobile` / `document`
(`live_artifact` / `hyperframes` already existed) and derive the finer kind
from the persisted project metadata — `projectKindToTracking` now reads
`fidelity` / `intent` / `platform`/`platformTargets` (precedence
live_artifact > wireframe > mobile), and `other` + `intent: 'document'`
becomes `document`. A new `projectKindFromMetadataToTracking` helper threads
this at every call site (web project_create_result / recent-projects /
designs / in-project runs, daemon run_created / run_finished).

Product behavior is unchanged: `metadata.kind` stays `prototype`/`other`
(cards keep reusing the web-prototype seed); only the analytics dimension
splits out. `intent: 'document'` is an analytics-only tag no product logic
keys off. HyperFrames already resolved correctly via
`videoModel === 'hyperframes-html'` and is preserved.

Verified end-to-end against a live daemon: created one project per card via
the real API, read back the persisted metadata, and confirmed each derives
its expected fine kind (hyperframes/wireframe/mobile/document/live_artifact).

* fix(analytics): keep design-system-apply target kind coarse

Review catch: ProjectView's in-project design_system_apply_result emits
`target_project_kind`, typed `TrackingDesignSystemApplyTargetKind` — a
narrower enum without the prototype subtypes (wireframe/mobile) or document.
Switching that site to the widened metadata helper let a Home-created
Wireframe/Mobile/Document project emit a value outside the field schema
(the `as` cast hid it). Derive the coarse kind here instead, so subtypes
collapse back to `prototype`; the fine split stays on `project_kind` only.

---------

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
2026-06-26 04:55:38 +00:00
PerishFireandGitHub 514ddba8ed ci: consolidate runner selection contract (#4803)
* ci: consolidate runner selection contract

* test: stabilize connector settings privacy state
2026-06-26 04:33:11 +00:00
a06ebdee09 fix(landing-page): make Product/Resources nav items pure dropdown toggles (#4784)
* fix(landing-page): make Product/Resources nav items pure dropdown toggles

The Product and Resources top-level nav items were <a> links: Product
navigated to the homepage and Resources to /blog/, which is confusing (they
are category labels, not pages) and meant that on touch devices with no
hover — touch laptops / tablets at desktop width — tapping them navigated
away before their dropdown could open, leaving the dropdown children
unreachable.

Render both as <button data-nav-dropdown-toggle> disclosure controls that
open their own dropdown instead of navigating. Hover still opens them on
pointer devices (CSS); click/tap now toggles an .is-open class that reveals
the dropdown, so touch users can reach the children. The four hub items
(Solution/Agent/Plugins/Community) stay as links to their real hub pages.
No crawlable links are lost: the homepage is still linked from the brand
logo and the Product dropdown's 'Open Design' item, and /blog/ from the
Resources dropdown's 'Blog' item.

The homepage (index.astro) inlines its own copy of the header enhancer
script rather than using header-enhancer.astro, so the toggle wiring is
added in both places.

* fix(landing-page): close click-pinned nav dropdown when another item activates

Address review: clicking Product/Resources pinned that li in .is-open until
an outside click, but the other header items still open on pure CSS :hover /
:focus-within, so click Product -> hover Solution rendered both flyouts at
once. Close any click-pinned dropdown on sibling mouseenter / focusin so a
pinned panel and a hovered panel can never show together. Mirrored in the
homepage's inline enhancer copy (index.astro) and the shared
header-enhancer.astro.

* fix(landing-page): drive Product/Resources dropdowns solely by .is-open

Address review: clicking a toggle a second time or pressing Escape cleared
.is-open and set aria-expanded=false, but the panel stayed visible because
CSS still revealed it on :hover / :focus-within while the clicked trigger
kept focus — visual and ARIA state diverged. Mark the two disclosure menus
with .has-dropdown-click and exclude that class from the :hover /
:focus-within reveal (caret, panel, and frosted backdrop), so an explicit
close always wins. The four hub menus keep their hover/focus-within flyout
behaviour. Product/Resources now open on click/tap/Enter only — correct
disclosure-button semantics. Mirrored across header.tsx markup and the
shared globals.css; the JS toggle in header-enhancer.astro and index.astro
is unchanged.

* fix(landing-page): treat Product/Resources as section headers on mobile

Address review: at <=1080px the hamburger menu flattens every dropdown to
always-visible, but the new disclosure buttons kept aria-expanded="false"
and only flipped ARIA on click — so on phones the control announced
'collapsed' over already-visible links and tapping produced no visible
change. Make the contract breakpoint-aware: on the flattened mobile menu the
triggers drop their disclosure ARIA (aria-expanded / aria-haspopup) and the
click is a no-op, i.e. they are plain section headers; on desktop they stay
.is-open-driven disclosures. A matchMedia listener re-syncs the mode when the
breakpoint is crossed. Mirrored in header-enhancer.astro and index.astro.

* fix(landing-page): make Product/Resources real disclosures on mobile too

Address review: the prior mobile path stripped aria-expanded/aria-haspopup
and no-op'd the click in JS, but the SSR markup still shipped focusable
<button> disclosures with stale ARIA over already-visible links — dead
controls before/without JS. Make the mobile contract truthful end-to-end in
CSS instead: at <=1080px the .has-dropdown-click panels are collapsed
(display:none) until .is-open and their caret is shown as the expand
affordance, so they are genuine accordions whose aria-expanded matches
visibility even in SSR. The four hub menus stay flattened-visible. The JS is
now a single .is-open toggle at every breakpoint (no breakpoint special-case).

* fix(landing-page): reveal Product/Resources via pure CSS, no JS

Address review: excluding the click-toggle menus from :hover / :focus-within
left JS as their only open path, regressing the static-export/no-JS behavior
the header relied on (dead buttons on first paint or script failure). Drop
the JS .is-open disclosure layer entirely: Product/Resources are plain
<button class="nav-trigger"> triggers (so they never navigate) whose
dropdown is revealed by the exact same pure-CSS :hover / :focus-within rule
as the four hub menus. This works with no JS, on first paint, and on touch
(tapping the button focuses it, so :focus-within reveals the panel), and it
removes the entire class of state-divergence bugs the JS layer introduced
(pinned-vs-hover overlap, close-vs-focus-within, mobile aria). header.tsx
markup + globals.css; the toggle JS in header-enhancer.astro and index.astro
is removed.

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-26 03:18:02 +00:00
ScarlettandGitHub 2f75200a84 chore(readme): add UTM attribution to open-design.ai links (#4792) 2026-06-26 03:15:40 +00:00
d54f3e9759 feat(landing): upgrade 20-minute tutorial to long-form localized guide (#4693)
* feat(landing): upgrade 20-minute tutorial to long-form localized guide

Turn the CodingMenace catalogue entry into a full original getting-started
tutorial (install paths, first-run setup, workspace tour, first prototype, FAQ),
rewritten in OD's voice and corrected against the current README (e.g. install is
`pnpm tools-dev run web`), crediting and linking the original video. Figures are
clean screenshots re-captured from the live site, not the creator's frames.

Render: add long-form .tut-body rules (inline images + captions, code blocks,
tables, hr) and a per-slug/locale long-form store
(app/_data/tutorials-longform-i18n.ts). Non-English detail pages prefer this
store and fall back to the existing generic placeholder, so the ~40 short
catalogue entries are unchanged.

i18n: localize to the priority languages from the SEO action plan — English
source plus es (Tier A) and fr/de/ja/it/ru/pt-br/tr (Tier B). Lower-tier locales
intentionally keep the placeholder rather than mass-generating machine
translations on a low-authority site.

* fix(landing-page): drop hardcoded catalog counts from 20-minute tutorial

AGENTS.md forbids hardcoded visible "X skills / Y systems" claims because
content edits can publish contradictory totals against getCatalogCounts().
Replace the fixed "129 design systems and 100+ skills" line with a
count-free phrasing across the English source and all 8 localized bodies
(de/fr/es/pt-br/it/ja/ru/tr).

* feat(landing-page): add zh + ko long-form bodies for 20-minute tutorial

Extends the pilot tutorial's localized coverage to the full keep-11 locale
set (en + de/es/fr/it/ja/ko/pt-br/ru/tr/zh). zh and ko were the two
canonical languages still missing a long-form body; both are
quality-translated (brand names, commands, URLs, and file names kept
verbatim; count-free library phrasing preserved).

* feat(landing-page): use real in-app screenshots + address review nits on 20-min tutorial

- Replace the three marketing-site captures with real Open Design app
  screenshots (workspace home, design-system picker, template picker) so the
  how-to figures match what users actually see in the product.
- Drop the hardcoded http://localhost:7456 web-UI address from the English
  source and all localized bodies; tools-dev now resolves a dynamic port.
- Narrow the caption CSS selector to p:has(> img) + p > em:only-child so it
  only styles image captions, not every em-only paragraph.

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-26 03:09:27 +00:00
273bacfc78 [codex] Add design-system tracking analytics (#4783)
* feat(analytics): design-system tracking foundation (project_kind, entry source, brand picker)

Implements the first slices of the design-system tracking spec:

- §1 project_kind: brand-extraction backing projects now report
  project_kind=design_system so DS-project runs (creation + edits)
  drill down cleanly instead of collapsing into 'brand'.
- U3/U4: report design_system_source from the real selection source
  (request->user_selected, plugin->template_inherited, project->
  project_saved, app-default->default) instead of the hard-wired
  unknown/not_applicable; add design_system_kind (official/custom,
  derived from the user:<id> shape) and design_system_slug (official).
- §3.1 create entry source: thread the real entry (onboarding /
  design_systems_page / composer_picker / home_card / library /
  project_canvas) from each navigate() call site into the create
  page_view and create_result, replacing the binary heuristic.
- C7-C9 preset-brand picker: instrument the "Start from a brand"
  trigger click, picker surface_view, and brand_pick with
  preset_brand_category (never the domain).

Contracts: add TrackingDesignSystemKind, TrackingDesignSystemEditSurface,
DesignSystemsPresetBrandPicker{Click,SurfaceView}Props; extend
RunCreatedProps with design_system_kind/slug/edit_surface and both
entry_from enums with composer_picker/project_canvas/library.

Adds docs/design-system-tracking-spec.md.

Verified: contracts build + 170 tests, web typecheck + full suite (3463),
daemon typecheck + run-analytics/brand-extraction tests (70).

* feat(analytics): track AI-optimize (design_system_enrich) click

C13 (tracking spec §3.3): instrument the "AI Optimize" banner CTA on a
programmatically-extracted DS-as-project so the AI-conversion rate
(clicked ÷ programmatic creates) is visible.

Contracts: add design_system_enrich area, DesignSystemEnrichClickProps,
DesignSystemEnrichResultProps, and the design_system_enrich_result event
name (result event reserved for the C14 follow-up).

Adds an implementation-status table to the spec. C14 (enrich_result) and
C15 (ProjectMetadata.enrichmentStatus) remain follow-ups since they need
correlation with the async enrichment run's completion.

Verified: contracts build, web typecheck, brand-enrichment + analytics
tests (89).

* feat(analytics): report all design-system create sources (ds_source_origins)

Comment ②: multi-source creates were flattened to a single `mixed`
design_system_source, hiding which sources combined. Add a comma-joined
`ds_source_origins` (e.g. `source_url,local_code`) on create_result that
lists every source actually used, keeping the singular field for
back-compat. Mirrors the target_platforms/connectors multi-value convention.

Verified: contracts build, web typecheck.

* feat(analytics): distinguish onboarding build-DS vs skip-to-home (C2)

C2 (tracking spec §3.1): the final onboarding step forks into "Build a
design system" and going straight Home, but both reported
completion_type=completed_without_design_system, so the skip rate was
invisible. Parameterize runOnboardingCompletion so the build fork reports
completed_with_design_system and the home forks report
completed_without_design_system. Update the EntryShell onboarding test,
which clicked "Build a design system" yet asserted the without value.

Verified: web typecheck, EntryShell onboarding tests (24).

* feat(analytics): instrument design-system edit lifecycle (E1-E3)

Tracking spec §3.4/§3.6:

- E3 (direct module edits, ui_click area=design_system_edit, all carrying
  edit_surface=direct_module + artifact_kind=design_system + the DS id):
  DesignSystemsTab general ops (edit-with-agent / refresh / download / reset),
  DesignKitView module buttons via the parent handlers (logo/font/image
  upload incl. paste, color edit, logo/image delete, design_md edit-save),
  and the BrandPreviewCard three actions (use-in-chat / open-project / delete).
- E1 (agent-routed edits): a DS-project run editing an EXISTING design system
  now carries edit_surface — comment/mark from their entry_from, otherwise
  chat. First-generation runs get none.

Contracts: DesignSystemEditClickProps (+ union); reuses the
TrackingDesignSystemEditSurface added earlier and RunCreatedProps.edit_surface.

Not wired (enum reserved / no handler today): kit_import, kit_open (external
link in the stateless kit view), design_md_copy/upload.

Verified: contracts build; web + daemon typecheck; DS/Brand/Kit web tests
(89) + daemon run-analytics tests (44).

* feat(analytics): AI-optimize result + enrichment status (C14/C15)

Closes the programmatic-vs-ai_refined comparison gap (tracking spec §6):

- C14: the AI-optimize run is tagged (analyticsHints.dsEnrichment) from the
  ProjectView banner CTA; when it settles, the daemon emits
  design_system_enrich_result (result / design_system_id / project_id /
  run_id / duration_ms / error_code).
- C15: on a successful enrichment run the daemon flags the backing project
  metadata enrichmentStatus='ai_refined' + enrichmentCompletedAt, so the two
  DS cohorts can be split for retention/usage analysis.

Contracts: ProjectMetadata.enrichmentStatus/enrichmentCompletedAt; reuses
the design_system_enrich_result event + DesignSystemEnrichResultProps added
earlier. ProjectChatSendMeta gains dsEnrichment.

Verified: contracts build; web + daemon typecheck; daemon run-analytics +
brand-extraction tests (70); web brand-enrichment tests.

* fix(contracts): declare dsEnrichment hint in ChatAnalyticsHints

The daemon run route reads analyticsHints.dsEnrichment and ProjectView's
AI-optimize path sends it, but the shared ChatAnalyticsHints DTO did not
declare the flag — leaving the web/daemon HTTP shape ahead of the contract
layer so typed ChatRequest callers could not discover or type-check the hint
that drives design_system_enrich_result and the ai_refined metadata stamp.

Declare dsEnrichment?: boolean with analytics-only semantics and add a
request-shape test that compile-fails if the field is dropped again.

Addresses review feedback on PR #4740.

* chore: ignore .playwright-mcp capture output

Local Playwright MCP runs write YAML page snapshots and PNG screenshots to
.playwright-mcp/. These are ad-hoc local visual-check output (including local
UI/session state), not a maintained test fixture, and per the root AGENTS.md
local runtime data must stay out of git. Add the ignore rule so the directory
is never accidentally staged again.

* fix: repair AI optimize enrichment tracking

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

* fix: track design kit module edit clicks

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

* fix: stabilize project P0 catalog loading

Stub unrelated catalog endpoints in the scoped project workspace and runtime Playwright flows so the P0 checks assert their target behavior instead of waiting on large registry responses.\n\nGenerated-By: looper 0.9.10+codex.autoclean (runner=fixer, agent=codex)

* fix: guard design-system tracking repairs

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

---------

Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com>
Co-authored-by: Looper <looper@noreply.github.com>
2026-06-26 02:57:18 +00:00
4bfe4ba8ca feat(landing-page): add Ikigai One customer story at /story/ikigai-one (#4748)
* feat(landing-page): add Ikigai One customer story at /story/ikigai-one

Open Design's first customer story. Bespoke full-bleed landing page reusing the shared shell (header/footer/SEO), with per-locale variants so hreflang alternates resolve.

* feat(landing-page): add /story index + Stories nav + 18-locale i18n for the Ikigai One story

- New /story stories index (masthead, story card, value props) + Resources -> Stories nav entry, both localized.
- Full 18-locale i18n for the story and index, via a generated ikigai-one-i18n module.
- Content fix: feat01 is the 40-page branded report (not the brand book); ~25x -> ~50x; uses the report-cover image.
- Drop the 'Contact sales' CTA for now — the enterprise lead page isn't live yet (per standup); Download-only.

* fix(landing-page): rename /story -> /stories (plural) + SEO pass per review

- Rename the route /story -> /stories across index, story, locale variants, nav entry, and assets (review: Joey).
- SEO: shorten the story <title> to the quote + 'Ikigai One' (was ~114 chars); add descriptive alt text to the story images; add CollectionPage JSON-LD to the /stories index.

* fix(landing-page): enrich /stories index title + meta description for SEO

Index <title> now eyebrow + heading (~41 chars, en); meta description combines the sub + value-prop line (~155 after clamp). CJK locales are naturally dense. Resolves the short title/description audit warnings.

* fix(landing-page): brand-PDF cost is several thousand dollars (per customer); aria-hidden on decorative SVGs

- Problem section: the client-ready brand PDF costs several thousand dollars to produce, not ~$1,000 (Anthony's correction), in all 18 locales.
- Add aria-hidden="true" to the decorative hand-drawn SVGs (brush strokes, circles, scribble, stat line, arrow) so screen readers skip them.

---------

Co-authored-by: ScarletttMoon <scarletttmooon@gmail.com>
2026-06-25 15:44:40 +00:00
9f4fe9ff8a fix(landing-page): stop :loc fold from shadowing /plugins hub pages (#4786)
The kept-locale catalog folds use a `:loc` placeholder
(`/:loc/{skills,systems,templates}/* -> /:loc/plugins/...`), but `:loc`
also matches the literal segment `plugins`. So the canonical English hub
pages `/plugins/{skills,systems,templates}/` bound `:loc=plugins` and
301'd to `/plugins/plugins/.../` (404), taking three live catalog pages
down. `/plugins/craft/` survived only because it has no fold below.

Guard the three hub paths with a 200 rewrite placed before the folds, so
first-match-wins serves the real static pages (and their faceted
`/plugins/templates/<kind>/` children) instead of redirecting.

Verified with `wrangler pages dev`: the three paths return 200 again
while every locale fold (`/zh/templates/*`, retired `/vi/*`, ...) is
unchanged.

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-25 15:08:27 +00:00
dd02f9bc7c Update official social links in settings menu (#4779)
Co-authored-by: tuolaji <tuola@tuolajideMacBook-Air.local>
2026-06-25 13:49:19 +00:00
3b602f51f4 [codex] Polish design-system preview UI (#4776)
* fix(web): polish design system preview release UI

* fix(web): restore home carousel submit

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

* fix(web): keep design system spec sidebar

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

* fix(web): block carousel submit while plugins load

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

* fix(web): preserve design system preview modal behavior

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-25 12:01:02 +00:00
AmyandGitHub 5333098611 [codex] reduce noisy visual report matches (#4772)
* fix(e2e): reduce noisy visual report matches

* fix(e2e): use normalized visual diff area

Generated-By: looper 0.9.11 (runner=fixer, agent=codex)
2026-06-25 10:10:51 +00:00
michaeltaxman911-hueandGitHub 0c7955de69 fix(web): simplify run error source diagnostics (#4701)
* fix(web): simplify run error source diagnostics

* fix(web): preserve fallback error source text
2026-06-25 09:29:42 +00:00
db78a90b05 fix(landing-page): drop redirecting legacy routes from sitemap (#4773)
* fix(landing-page): drop redirecting legacy routes from sitemap

The sitemap listed ~468 URLs that 301-redirect: the legacy /skills,
/systems, and /templates catalog routes (now served under /plugins/* via
public/_redirects) and legacy region-cased locale codes (zh-CN, zh-TW,
es-ES, pt-BR, which 301 to /zh/, /es/). Their old page routes still build,
so @astrojs/sitemap emitted them even though every one returns a redirect.

A sitemap should carry only final 200 canonical URLs; redirecting entries
waste crawl budget and feed Google Search Console's 'Page with redirect'
exclusion bucket. Filter the legacy route and locale prefixes out, and drop
the now-dead /skills//systems//templates/ branches from the priority
serializer. Sitemap drops 1,217 -> 749 URLs (the 468 redirects), with no
200 page removed (verified against a full crawl of the live sitemap).

* fix(landing-page): keep canonical section hubs on elevated crawl hint

Address review: the legacy /skills, /systems, /templates roots 301 to
/plugins/skills, /plugins/systems, /plugins/templates. Give those canonical
hubs the same 0.7/weekly sitemap priority as the /plugins/ hub instead of
the generic 0.5/monthly default, so dropping the redirecting roots does not
quietly downgrade the crawl signal of their replacements.

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
2026-06-25 09:19:24 +00:00
8b9b169673 ci: add cost-sensitive runner tiering (#4764)
* test persistent contabo runner poc

* test persistent runner web workspace poc

* test persistent runner local cache setup

* test persistent runner aggressive setup poc

* test persistent runner web postinstall profile

* test restore stable persistent runner poc

* test keep persistent runner web tests default

* test route persistent poc to zxiyun runner

* test relax web vitest timeout on persistent poc

* test harden web vitest cases for persistent runner

* test add runner perf probe

* test isolate runner perf probe dispatch

* test pin runner perf probe node

* test expand runner perf probe matrix

* ci: route heavy jobs through runner modes

* ci: keep web workspace tests on blacksmith

* test: update web runner mode assertion

* ci: route cost-sensitive runner tiers

* ci: move preflight to hosted runner

* ci: downshift blacksmith ui runners to 4vcpu

* test: fix file viewer timeout after merge

* ci: route e2e vitest to hosted default

* ci: centralize runner profile selection

* test: type runner profile assertions

* ci: route e2e vitest to default blacksmith

* ci: remove runner experiment probes

* test: restore postinstall guard coverage

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

* test: cover postinstall script contract

* test: move postinstall guard to e2e

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-25 08:55:51 +00:00
lefarcenandGitHub 4c6f6549c6 ci: add landing QA Feishu summary (#4763) 2026-06-25 07:59:45 +00:00
AmyandGitHub a5e2f1bcff test(e2e): add target-level visual baselines (#4765) 2026-06-25 07:10:03 +00:00
lefarcenandGitHub a4dea37a22 fix(ci): harden backport automerge provenance (#4761) 2026-06-25 07:07:04 +00:00
lefarcenandGitHub 60d187b79f feat(ci): auto-merge the rolling plugin-preview manifest PR on green CI (#4727)
* feat(ci): auto-merge the rolling plugin-preview manifest PR on green CI

The post-merge bake opens ONE rolling PR (chore/plugin-previews) whenever a
baked preview changes (spec slice 1). Its diff is pure generated data
(data/plugin-previews/manifest.json; the clips already live on R2), yet someone
still had to merge it by hand — the last manual step the pipeline rework left
behind, and exactly the kind of bot PR that used to pile up.

Two coupled changes:

1. bake-plugin-previews.yml now authors the rolling branch + PR with the
   release-bot App token instead of GITHUB_TOKEN. A GITHUB_TOKEN-authored push
   does not trigger workflows, so the manifest PR never ran `Validate workspace`
   (main's required check) and could not clear the merge queue at all — even
   manually. (PREVIEW_BAKE_TOKEN, the old fallback, was never configured.)

2. bake-plugin-previews-automerge.yml reacts to ci.yml completing for the rolling
   branch and, for a non-draft same-repo PR authored by the release bot with only
   bot commits (pristine) at the exact SHA CI passed, approves it as
   github-actions[bot] (main requires one review; an author cannot approve its own
   PR) and enqueues it with `gh pr merge --auto --squash --match-head-commit`.
   CI failure pings Feishu instead.

Modeled on backport-automerge.yml, adapted for main: main has a merge queue, so
the merge is GitHub-native --auto (enqueue) rather than a direct squash, and
pristine checks the git committer email (the bot email maps to no GitHub user, so
.committer.login is null).

* fix(review): GitHub-backed pristine provenance + correct Feishu sign secret

Address two blocking review findings on the auto-merge path:

1. pristine could be satisfied by spoofed commit metadata. The bake commit was
   authored with a plaintext `git config user.email "bot@open-design.ai"`, and
   the reactor trusted that raw committer email — any collaborator who can push
   to chore/plugin-previews could set the same email and fake pristine=true,
   landing unreviewed commits on main. Commit AS github-actions[bot] (its
   canonical noreply email) and gate on GitHub's resolved `.committer.login`,
   the same GitHub-backed field backport-automerge.yml trusts.

2. the failure Feishu ping signed with secrets.FEISHU_WEBHOOK_SECRET, but every
   other FEISHU_RELEASE_WEBHOOK caller (notify-release-feishu, notify-daily-feishu,
   backport-automerge) signs with FEISHU_RELEASE_SIGN_SECRET; the wrong secret
   resolves empty and the signed release webhook rejects the unsigned request.
   Use FEISHU_RELEASE_SIGN_SECRET and assert the pairing in the topology test.

* test(ci): lock the auto-merge conclusion gates + bake producer invariants

Address nettee's non-blocking coverage follow-up so a regression can't pass the
topology test green:

- Assert the approve and enqueue steps gate on
  `workflow_run.conclusion == 'success'`, and the Feishu step on `== 'failure'`,
  so dropping a conclusion predicate fails the test.
- Add a companion `[P2]` block over bake-plugin-previews.yml asserting the three
  producer invariants the downstream pristine/auto-merge path depends on:
  the create-github-app-token mint, the App-token push URL, and the
  github-actions[bot] commit identity. Regressing the producer back to a
  GITHUB_TOKEN push or a different commit identity now fails here.

* fix(review): bind the Feishu failure alert to the run's exact SHA

A stale failed CI run can finish after the force-pushed rolling branch has
advanced to a newer (green) head. The Feishu step only gated on author/cross +
conclusion==failure, so it would page about a SHA that is no longer the PR head.
Add the same steps.pr.outputs.head_oid == workflow_run.head_sha guard the
approve/enqueue steps use, and lock it in the topology test.

* fix(review): prove bot provenance with GitHub signatures, not git headers

nettee correctly escalated: .committer.login is still a spoofable git-header
identity. A collaborator who can push to chore/plugin-previews can mint a local
commit with the bot's noreply email, GitHub then reports
.committer.login == github-actions[bot], and pristine=true passes — landing
unreviewed human changes on main.

Switch to non-spoofable provenance:

- bake-plugin-previews.yml now creates the manifest commit through the Git Data
  API (blob -> tree -> commit -> ref) with the App token, instead of a local
  `git commit` + push. A commit created through the API is signed by GitHub
  (verification.verified=true) and committed by the App bot (committer.type=Bot).
  Building the tree on the live main HEAD also rebases the rolling branch onto
  the latest main each run.
- the reactor's pristine gate now requires EVERY commit to be both
  verification.verified==true AND committer.type==Bot. A human's locally pushed
  commit is unsigned (verified=false) even with the bot email; a human signing
  with their own key is committer.type=User. Neither can be both, so the pair is
  forge-proof.
- topology test updated to lock the API-commit producer path (and forbid a
  regression to a local push) and the verified+Bot pristine check.

* fix(review): parent the manifest commit on the rendered revision, not live main

The previous change based the Git Data API commit on live main HEAD, but $NEW is
rendered from the job's checkout at start. The bake can run ~90min and main can
advance (unrelated merges) meanwhile, so basing the commit on live main would
publish a manifest from an older checkout on top of newer commits — the rolling
PR would look current while carrying stale preview data and could overwrite
newer plugin-preview changes.

Parent on `git rev-parse HEAD` (the exact revision that produced $NEW) instead,
so GitHub correctly shows the PR as behind once main moves and the next bake
re-renders on the newer HEAD. Topology test locks the rendered-revision base and
forbids regressing to a live-main base.

* fix(review): require the rolling PR's rendered base to equal main before merge

main's merge queue does not require an up-to-date branch, so a bake rendered
against an older main could be re-tested on the latest main and squash-merged
with a stale manifest.json — overwriting a newer manifest that landed meanwhile.
head_oid only proves the PR head is the SHA CI validated, not that it is current.

Add a base-freshness gate: the rolling commit's first parent is the revision the
manifest was rendered against, so require it to equal current main HEAD before
approving/enqueuing. A behind PR is skipped and refreshed by the next bake (the
nightly re-renders on the newer tip even if no plugin changed). Locked in the
topology test.

* fix(review): page Feishu on timed_out bakes too, not just failure

workflow_run has terminal RED states beyond 'failure'. ci.yml defines many
timeout-minutes jobs, so a timed-out run on the rolling manifest PR would block
auto-merge with no Feishu page. Broaden the alert predicate to
failure OR timed_out, and include the conclusion in the message. Deliberately
exclude 'cancelled': a force-push of the rolling branch routinely cancels the
prior in-flight run, so alerting on it would page on every normal refresh. Test
locks the failure+timed_out set and the cancelled exclusion.

* fix(review): gate auto-merge on a manifest-only diff, not commit signatures

nettee is right that the Git Data API does not sign commits — I verified it
empirically: a blob/tree/commit created via POST /git/commits comes back
verification.verified=false / reason=unsigned (and the Contents API is unsigned
too for non-web callers). So the previous verified==true && committer.type==Bot
pristine gate would never pass and the rolling PR could never auto-merge.

There is no per-commit field that is both bot-set and unforgeable without a
signature, so stop trying to prove "the bot authored every commit" and instead
bound what auto-merge can land: require the PR's changed files to be EXACTLY
data/plugin-previews/manifest.json. A human with push access can still push to
the rolling branch, but any commit that touches a code file (or anything but the
manifest) makes the file set != the single manifest path, so pristine=false and
the PR falls back to human review. The worst a forged manifest-only change can do
is point a gallery preview at a bad video URL — generated data the next bake
overwrites — never unreviewed code on main.

With signing no longer relied upon, revert the producer from the Git Data API
dance back to a plain App-token git push (still parented on the checked-out HEAD
per the base-freshness fix, still pushed with the App token so CI runs). Tests
updated to lock the manifest-only file gate and the simplified producer.

* test(ci): update secretless-bake assertion for the App-token producer

Merge main (#4691 landed the read-only pre-merge bake + its topology test). That
test asserted the post-merge workflow contains PREVIEW_BAKE_TOKEN as the
write-capable credential; this PR replaced that never-configured fallback with
the release-bot App, so assert secrets.RELEASE_BOT_APP_ID (and that
PREVIEW_BAKE_TOKEN is gone) instead.
2026-06-25 05:53:01 +00:00
2fb0ac5f26 feat(landing-page): concentrate to 11 SEO locales + 'best' over 'official' in homepage TDK (#4709)
* feat(landing-page): retire 7 low-traffic marketing locales

GSC (last 90d) shows the marketing site's non-English traffic is highly
concentrated: English ~80% (mostly homepage/brand), Spanish the clear #2,
and a long tail of locales returning near-zero clicks. Retiring the tail
removes thin/duplicate pages that dilute crawl budget on a low-authority
domain, and concentrates SEO on the languages that actually earn.

Keep 11 active locales (en, zh, ja, ko, de, fr, ru, es, pt-br, it, tr);
retire zh-tw, vi, pl, id, nl, ar, uk. Implementation keeps the full
historical list as ALL_LANDING_LOCALES so existing per-locale translation
data stays type-valid, and derives the shipped LANDING_LOCALES by filtering
out the retired set. Every consumer (routing, language switcher, hreflang,
sitemap) imports LANDING_LOCALES, so new pages automatically ship only the
active set and the retired languages cannot silently reappear.

Add public/_redirects 301s for the retired locales (plus legacy zh-cn/fa/
hu/th prefixes still in Google's index): Chinese variants fold into /zh,
everything else folds into the English page.

* feat(landing-page): retire locales in catalog i18n system too

The landing page has a second, parallel locale list in app/_lib/i18n.ts
(PREFIXED_LOCALES) that drives the catch-all catalog/craft routes, separate
from app/i18n.ts:LANDING_LOCALES. Filtering only the latter left a couple of
catalog pages per retired locale. Exclude the retired locales from
PREFIXED_LOCALES as well so no retired-locale pages are generated by either
system. zh-CN/fa/hu/th also remain covered by the existing
LEGACY_LOCALE_PREFIXES redirect handling.

* feat(landing-page): use "best" over "official" in homepage SEO title/description

The homepage TDK called Open Design the "official" open-source Claude
Design alternative. "official" carries no search demand (nobody queries
"official X") and reads as self-promotion. "best" matches the high-intent
"best open-source X" / "best Claude Design alternative" pattern users
actually search, lifting title CTR without changing the page's meaning.

Scope is the homepage SEO copy only — HOME_SEO_COPY title + description
across all 18 locales, plus the og.astro social-card title that mirrors
it. Deliberately left untouched: "official vs community registries" on
the plugins page, the /official/ canonical-disambiguation page, the
HTML Anything canonical title, and the FAQ entity-disambiguation copy,
where "official" is a meaningful claim rather than a CTR modifier.

* fix(landing-page): keep retired-locale redirects under Cloudflare's dynamic-rule cap

Cloudflare Pages `_redirects` ignores every rule past the 100th dynamic
(splat/placeholder) entry and only logs a build warning. The file had
already accumulated 113 dynamic rules, so the retired-locale catch-alls
appended at the end never took effect — `/vi/`, `/id/`, `/zh-tw/` etc.
returned 404 instead of the intended 301 to English, the exact soft-404
the prune set out to avoid.

The per-retired-locale sub-path rules (`/<loc>/skills/*`, `/<loc>/plugins/*`,
`/<loc>/plugins/previews/*`, …) are now dead weight: a single
`/<loc>/* -> /:splat 301` folds the whole locale to its English (or `/zh`
for Chinese variants) equivalent. Removing those 38 redundant rules drops
the dynamic count to 75, so the catch-alls land inside the cap and fire.

* refactor(landing-page): consolidate _redirects with :loc placeholders under CF cap

The previous commit trimmed 38 dead per-locale rules but the file still
exceeded Cloudflare Pages' total-rule cap (~131 rules on this project),
which silently drops every rule past the cap. Retired-locale catch-alls
and the later kept-locale plugin redirects landed in that dead zone and
404'd instead of 301'ing — verified on the PR preview and on production
(`/de/plugins/*` already 404s live, pre-dating this branch).

Collapse the per-locale catalog redirects (skills/systems/templates,
plugins, plugins/previews — 53 rules across 11 locales) into five `:loc`
placeholder rules, and drop the retired locales' now-redundant /wallet
rules (their catch-all folds /wallet through to /amr/wallet). Total rules
drop 169 -> 110, comfortably under the cap, so every redirect — retired
folds to English/zh, and the kept-locale ones that were already dead on
prod — fires again. Retired catch-alls are ordered before the generic
/:loc/* rules so a retired locale folds to English, not to its own
non-existent /plugins/ pages; real localized hub pages are static assets
and win over these rules.

* fix(landing-page): don't fold localized plugin hubs to English

The consolidated `/:loc/plugins/* -> /plugins/:splat` rule shadowed the
real localized plugin hub pages. On this project `_redirects` takes
precedence over static assets (verified: `/es/plugins/` has a 231 KB
static index but the rule 301'd it to `/plugins/`), so the rule regressed
`/<loc>/plugins/`, `/<loc>/plugins/skills|systems|templates/` from 200 to
a redirect. They only kept serving on production because the per-locale
rule sat past the redirect cap and never fired.

Drop the `/:loc/plugins/*` and `/:loc/plugins/previews/*` folds. Localized
plugin hubs are static and now serve 200 again; localized plugin detail
pages 404 exactly as they do on production today (no regression);
retired-locale plugin paths still fold to English via the retired
`/<retired>/* -> /:splat` catch-alls. Keep only the skills/systems/
templates legacy folds, whose source paths are not generated as static.

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

* fix(landing-page): retire zh-CN/es-ES/pt-BR catalog prefixes (full 11-locale convergence)

The catch-all catalog routes and blog RSS feeds build from PREFIXED_LOCALES,
which still included the BCP-47 aliases zh-CN, es-ES and pt-BR. Those are
duplicates of the kept short codes zh, es and pt-br: the canonical pages are
generated from LANDING_LOCALES, so the alias-prefixed pages only ever 301 back
to the short code via public/_redirects, yet still count toward the Cloudflare
Pages file-count cap.

Add the three aliases to RETIRED_PREFIX_LOCALES so the catch-all no longer
emits them. Every generated route now lands on the same 11 canonical short
codes (en zh ja ko de fr ru es pt-br it tr); incoming alias URLs remain covered
by the 301 migration rules.

---------

Co-authored-by: Joey <276262049+xne998808-ai@users.noreply.github.com>
Co-authored-by: lefarcen <935902669@qq.com>
2026-06-25 05:51:05 +00:00
Tom HuangGitHubCursorxne998808-aiPerishCodeopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>lefarcenSiri-Ray
29b138f7a3 feat(brands): turn any brand into a reusable design system (#4691)
* Implement brand management routes and CLI support

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

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

* Enhance memory management and onboarding experience

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

* Refactor onboarding flow and enhance design system integration

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

* Add brand management features and enhance font handling

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

* Enhance brand extraction and project management features

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

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

* Enhance onboarding profile management and memory persistence

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

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

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

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

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

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

* Sediment finalized brands into structured memory

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

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

* Implement logo fallback and imagery support in brand extraction

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

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

* Enhance memory management with rule proposal and verification features

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

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

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

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

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

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

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

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

* Wire annotation distillation into background memory extraction

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* feat(clipper): compress and budget capture inlining

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Address review feedback on PR #4260:

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

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

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

* Update clipper/brand-capture.js

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

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

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

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

* fix(web): surface missing backing projects

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

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

* fix(brands): reconcile failed extractions

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

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

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

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

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

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

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

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

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

* chore(nix): refresh pnpm deps hash

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

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

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

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

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

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

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

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

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

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

* feat(web): enhance BrandPickerModal and DesignSystemAssetDropzone

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* fix(ci): restore new project modal flow

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

* fix(ci): sync bake preview workflow action

* fix(ci): include plugin preview helper scripts

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

* fix(ci): stabilize web workspace tests

* fix(review): address latest blocking feedback

* chore(ci): retrigger validation after label update

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* chore(nix): refresh pnpm deps hash

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

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

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

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

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

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

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

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

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

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

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

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

* chore(nix): refresh pnpm deps hash

* fix(onboarding): preserve selected runtime

* fix(brand): localize generated kit copy

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

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

* fix(analytics): use design system onboarding step

* fix(ui): remove design system guide toggle

* fix(ui): position design system ready prompt

* fix(ui): space plugin task notice

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

* test(e2e): align onboarding visual capture

* test(e2e): align amr onboarding checks

* fix(brand): remove blocked reference brands

* feat(onboarding): show profile choices as chips

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

* test(e2e): select onboarding profile chips

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

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

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

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

* test(e2e): align design system detail visual

* fix(brand-extraction): backfill programmatic transcripts

* fix(web): refresh ready brand design systems

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

* fix(brands): return extraction transcript immediately

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

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

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

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

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

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

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

* Fix manual editing for brand kits

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

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

* fix(web): restore home ask mode toggle

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

* fix(web): stabilize design system workspace tests

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

* chore(pr): retrigger review after validation

* fix(web): surface design kit action progress

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

* fix(web): cancel programmatic brand extraction

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: xne998808-ai <xne998808@gmail.com>
Co-authored-by: PerishCode <perishcode@gmail.com>
Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
Co-authored-by: lefarcen <935902669@qq.com>
Co-authored-by: Siri-Ray <2667192167@qq.com>
2026-06-25 03:56:14 +00:00
ed1df234ad fix(ci): needs-validation gate must resolve the queued PR from the merge_group ref (#4742)
* fix(ci): resolve merge_group PR from the queue ref, not commits/<sha>/pulls

The needs-validation merge gate resolved PRs in the merge_group via commits/<sha>/pulls. The
merge queue squashes, so the queued commits are NEW synthetic SHAs that GitHub does not associate
back to the PR — the lookup returned no PRs, the gate logged "clear to merge", and a
needs-validation PR (#4736) merged with no QA. (This was latent until the pull_request branch was
removed and merge_group became the sole enforcement.)

Resolve the PR number(s) from the queue ref name instead
(refs/heads/gh-readonly-queue/<base>/pr-<N>-<sha>), which is stable regardless of squash. Fail
closed if the ref yields no PR number.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(ci): enumerate ALL PRs in a merge group (ref + commit subjects + commits/pulls)

Addresses review: a batched merge group names only the tip entry in the queue ref, so parsing
pr-<N> from the ref alone could miss earlier PRs in the batch (one could still carry
needs-validation). Take the union of three sources — the ref pr-<N>, each commit subject's
trailing (#N) (the queue's per-entry squash commit carries its own PR number, recovering non-tip
batched PRs), and commits/<sha>/pulls (non-squash queues) — and fail closed if none resolve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(ci): fail closed if the compare API (PR enumeration source) fails

Addresses review: the compare call feeding msg_prs/assoc_prs used 2>/dev/null || true, so an API
failure silently emptied those sources while ref_prs still held the tip — the -z check passed and
only the tip PR was validated, letting a batched needs-validation PR merge. Capture compare once
in a REQUIRED assignment (no || true) so failure trips set -e; derive subjects + shas from that
parsed JSON; make commits/<sha>/pulls a required assignment too. Only grep no-match within a
successful response is tolerated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 09:51:32 +00:00
netteeandGitHub d40006f70b fix(amr): extend ACP stage timeout (#4736)
* fix(amr): extend ACP stage timeout

* fix(amr): align the outer inactivity watchdog

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

* fix(acp): scope 30 minute timeout to hinted runtimes

Generated-By: looper 0.9.11 (runner=fixer, agent=codex)
2026-06-24 09:17:38 +00:00
lefarcenandGitHub ccfdc50929 feat(analytics): first-call cache-hit + is_followup_turn telemetry (session-reuse baseline) (#4725)
* feat(analytics): measure first-call cache hit + is_followup_turn on run_finished

Instrumentation-first (telemetry before optimization) for the session-reuse
work: ship a v0.12.0 baseline that measures the cache-hit rate of the FIRST
model call of each turn, then compare it against the post-optimization release.

Why first-call: the existing run_finished usage scan is a REVERSE scan that
takes the LAST usage event of the turn. Within a turn, every call after the
first re-reads the growing prefix, so the last/aggregate cache-hit ratio is
high regardless of whether the session was reused — it masks the signal. The
session-reuse win shows up only on the OPENING call of a follow-up turn.

- scanRunEventsForUsageAnalytics now also forward-scans for the first usage
  event and emits first_call_input_tokens / first_call_cache_read_input_tokens
  / first_call_cache_hit_ratio (anthropic vs openai cache accounting mirrored
  from the existing last-call path). The group is gated on a real first-call
  input so cache-only alias payloads don't emit a dangling cache_read.
- run_finished carries is_followup_turn (a prior completed assistant turn
  exists) so first_call_cache_hit_ratio can be sliced to the turns where
  session reuse actually applies.
- The first-call fields are reliable only for per-call-usage agents
  (claude / opencode / codebuddy / pi). codex reports a single cumulative
  turn.completed usage, so its first stream event is the whole-session
  aggregate, not the opening call — gated out of the stream path here; its
  per-call number must come from the rollout last_token_usage (follow-up).

* feat(analytics): recover codex first-call cache hit from the rollout

Completes the first-call cache-hit telemetry for codex. codex emits only a
cumulative `turn.completed` usage on the exec/json stream the daemon consumes,
so the stream cannot reveal the cache-hit of a turn's OPENING model call — the
number that moves when a session is reused. codex does record per-call usage in
its rollout JSONL (`token_count.info.last_token_usage`), so we read it there.

- codex-rollout-usage.ts: pure `extractCodexLastTurnFirstCallUsage` takes the
  first `token_count` after the last `task_started` (the turn the daemon just
  finished), skipping zero-input placeholder calls. Validated against real
  codex 0.133.0 rollouts: a warm resume turn reads ~95-96% cache hit, a cold
  open ~15-18% — the exact baseline-vs-optimized signal. `readCodexRolloutFirstCall`
  locates the rollout best-effort (newest-first walk of
  `$CODEX_HOME/sessions/**/rollout-*-<thread_id>.jsonl`) and never throws.
- json-event-stream.ts surfaces codex's `thread.started` thread_id on the same
  `sessionId` status channel claude uses, so run_finished can find the rollout
  (and a future native-resume path can reuse it). `codexSessionIdFromRunEvents`
  recovers it from the stored run events.
- run_finished now resolves first-call usage per agent: codex from the rollout,
  every other agent from the stream forward-scan, behind one `firstCallUsage`
  object. CODEX_HOME comes from the drift-proof `spawnEnvForAgent('codex')`
  resolver so it honors sandbox relocation.

* fix(analytics): default codex rollout home to ~/.codex when CODEX_HOME unset

End-to-end testing through a real daemon surfaced this: codex's first-call
fields were silently dropped on every non-sandboxed run. The daemon only sets
CODEX_HOME when sandbox mode relocates it; with sandbox off, `spawnEnvForAgent`
returns an empty CODEX_HOME, codex itself falls back to ~/.codex and writes the
rollout there — but readCodexRolloutFirstCall bailed on the empty value instead
of mirroring codex's `$CODEX_HOME || ~/.codex` resolution.

Verified against a real daemon-driven codex run: the emitted run_finished now
carries first_call_input_tokens / first_call_cache_read_input_tokens /
first_call_cache_hit_ratio alongside is_followup_turn. Adds hermetic tests for
the locate-and-read layer (plant a rollout under <home>/sessions/.../, read it
back by session id) which previously had only the pure extractor covered.

* fix(analytics): harden first-call telemetry per release-readiness review

Adversarial review of the first-call cache-hit telemetry before a release
cherry-pick surfaced four fixable items; all are read-only/additive and keep
the feature best-effort:

- Contain throws in the codex run_finished branch. spawnEnvForAgent /
  agentCliEnvForAgent ran outside any local guard, so a throw there bubbled to
  the outer run_finished `.catch` and would have dropped the ENTIRE completion
  event for that run (not just the codex first-call fields). Wrap them so a
  failure degrades to "no first-call fields".
- Match the anthropic first-call denominator to the last-call one: include
  cache_creation_input_tokens in the effective-input sum. Previously first-call
  omitted it, skewing the very cross-turn comparison the metric exists for.
  Added a regression test with non-zero cache_creation.
- Bound the codex rollout locator. On a miss (session captured but file
  relocated/deleted) it walked the user's entire codex history; cap the scan to
  the newest few day-dirs since the run's own rollout is always recent.
- Declare first_call_* and is_followup_turn on RunFinishedProps in
  packages/contracts so the analytics shape is typed at the boundary.

* refactor(analytics): share one cache-token extraction for first/last-call

Review follow-up: the first-call cache-creation extraction only matched two of
the aliases the last-call path accepts (it missed cache_write_input_tokens,
cache_creation_tokens, and nested cache_creation.input_tokens), so a provider
emitting one of those on the opening usage event would compute
first_call_cache_hit_ratio with too small a denominator and overstate the cache
hit — the exact baseline metric this PR adds.

Extract one `extractUsageCacheFields` helper carrying the full provider alias
matrix and route BOTH the last-call reverse scan and the first-call forward
scan through it, so the two effective-input denominators can never drift. Adds
a fixture using the nested `cache_creation.input_tokens` alias to lock it.
2026-06-24 08:20:47 +00:00
009ff6566f [codex] Fix onboarding brand action layout (#4702)
* Fix onboarding brand action layout

* Match browser tab width to file tabs

* Restore release tool script mode

---------

Co-authored-by: Siri-Ray <2667192167@qq.com>
2026-06-24 07:55:01 +00:00