mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
73d07d8dfb2ce3425c1527aba4119eddd39def43
215
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
73d07d8dfb | test(e2e): stabilize AMR onboarding assertions (#4462) | ||
|
|
b02d20e6b9 |
fix: unify Discord invite links (#4452)
Co-authored-by: koki yanlai xu <koki@kokideMacBook-Air.local> |
||
|
|
15d3759834 |
[codex] Optimize CI topology and Playwright suites (#4460)
* Consolidate PR validation into ci * Tune absorbed CI runner tiers * Fold visual validation into CI Playwright shards * Run PR shards during manual CI dispatch * Optimize CI topology and scopes * Increase UI P0 Playwright workers * Relax visual Playwright timeout |
||
|
|
fdb1638183 |
[codex] Refresh local CLI auth state after API key switches (#4453)
* Refresh Codex auth status after CLI changes * Probe Claude Code auth status * Stabilize project route during agent refresh * Respect API key auth during CLI probes |
||
|
|
8ff19c6b41 |
[codex] Add main-risk smoke and E2E coverage (#4322)
* test(e2e): cover daemon reload artifact recovery * test(e2e): expand critical flow coverage * test(daemon): add startup and recovery smoke coverage * test(e2e): add visual and desktop chrome smoke coverage * ci: gate packaged onboarding smoke to nightly * fix(web): repair artifact replay type narrowing Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(ci): repair preflight smoke coverage checks Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(web): tighten artifact recovery polling Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(web): keep error recovery retries alive Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(e2e): relax brittle UI P0 assertions Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(web): recover pointer artifact outputs Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(e2e): stabilize manual edit reload smoke Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(e2e): avoid noisy win onboarding cleanup Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(web): stop failed artifact recovery polling Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(daemon): isolate startup smoke data root Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(web): recover standalone html artifacts Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(web): guard pointer artifact recovery by run time Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(ci): narrow strict visual gate to critical smoke Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * fix(ci): limit PR visual capture to critical cases * fix(ci): keep PR visual capture complete * fix(web): keep reload artifact recovery retryable * fix(ci): clarify PR visual gate layering * fix(e2e): stabilize visual home P2 capture * fix(e2e): align visual gallery detail clicks * fix(e2e): preserve packaged install during onboarding cleanup * fix(ci): shard PR visual capture * fix(ci): remove duplicate nix validation from ci * fix(ci): keep visual capture screenshots flat * fix(ci): point nix hash autofix at ci-nix * fix(ci): stabilize PR P0 recovery gate * fix(web): ignore stale artifact pointers during recovery * fix(web): reset BYOK model after clearing key * ci: run critical UI P0 subset on PRs * ci: combine PR UI P0 critical shards * ci: combine PR visual capture shards * ci: preserve visual capture shard manifests * fix(web): clear ProjectView delayed timers on unmount * test(e2e): harden onboarding connect gate coverage * test(e2e): align AMR auth recovery and visual catalog timeout |
||
|
|
e1b8d9921e |
Merge pull request #4421 from nexu-io/release/v0.11.0
release: Open Design 0.11.0 — The Bazaar |
||
|
|
d0d1df8e60 |
fix(web): portal New Project design-system dropdown so it isn't clipped (#4346)
* test(e2e): red-spec reproducing #4303 design-system dropdown clipping The New Project design-system popover (local DesignSystemPicker in NewProjectPanel.tsx) opens with plain position:absolute and is clipped by its .newproj-body { overflow-y: auto } ancestor, so lower options are truncated. This P1 UI spec opens the picker on a short window and asserts the popover does not spill past the .newproj-body / viewport bottom. https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6 * fix(web): portal New Project design-system dropdown so it isn't clipped (#4303) The New Project modal's design-system picker opened its popover with plain position:absolute, anchored inside .ds-picker. Its clipping ancestor is .newproj-body { overflow-y: auto } (the modal scroll container), so when the trigger sat low in the body or the window was short, the popover was truncated and the sections below bled through — the reported misaligned/truncated UI. This is platform-independent (shared web CSS rendered by the same Chromium in macOS and Windows desktop), not a macOS-only regression. Mirror the shared DesignSystemPicker: render the open popover through a portal to document.body, positioned from the trigger's viewport rect with viewport-aware up/down placement and a clamped max-height, so it escapes the clip box. A scoped .ds-picker-popover-portal variant flips the popover to position:fixed (z-index above the modal backdrop) and lets the list flex and scroll inside the bounded height. The sibling PlatformPicker shares the same absolute-popover pattern and is left for a follow-up. https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6 * fix(web): clamp design-system popover height to available viewport space Review follow-up (#4346, thanks @mrcfps): the anchor used Math.max(200, Math.min(440, space)), so when both sides of the trigger were under the 200px preferred minimum (a very short window) the fixed popover was still sized to 200px and overflowed the viewport instead of staying scrollable. Size the popover to the chosen side's actual available space, honoring the 200px preferred minimum only when the side can fit it. The list already flexes and scrolls inside the bounded height, so a smaller box just scrolls rather than spilling past the viewport edge. Extend e2e/ui/new-project-ds-picker-clipping.test.ts with a tight-viewport case (1280x360) that asserts both sides fall under 200px and the popover stays within the viewport. https://claude.ai/code/session_01EqWRnbYoxmugj4R1yj2LJ6 --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
1e2f47fb8d |
fix(amr): surface vela login URL/code so sign-in survives a failed browser handoff (#4402)
* fix(amr): surface vela login URL/code so sign-in survives a failed browser handoff AMR (vela) sign-in is a device-authorization flow: `vela login` prints the activation URL + user code to stdout, then best-effort opens the browser and keeps polling until the server-issued expiry (>5min). The daemon spawned it headless, only read the first 250ms of output, and the UI showed nothing but a "Signing in…" spinner — so when the browser failed to open (stripped PATH in a packaged build, blocked network) the user had no URL to fall back to and stared at a dead spinner for the full AMR_LOGIN_TIMEOUT_MS (5 minutes). - daemon: parseVelaLoginActivation + lifetime stdout/stderr capture surface activationUrl / userCode / browserOpenFailed on VelaLoginStatus. - web: the AMR account pill's signing-in state now shows an activation block (open sign-in page + copy code) as soon as the URL is known, instead of only a spinner; it adapts to the active theme. - web: an AMR run that fails with AMR_AUTH_REQUIRED now offers inline sign-in in the chat error card (the login pill) and auto-retries once on success, rather than bouncing the user out to Settings. Tests: red->green parser spec (validated against real vela login output), AmrAccountControl activation-block specs, ChatPane inline-auth specs. * test(amr): real-vela E2E for the login activation capture seam Spawns an actual `vela login` child through the daemon's spawnVelaLogin and asserts readVelaLoginStatus surfaces the real activation URL + code while the login is in flight, then cancels (never approves, so no config is written and any existing session is untouched). Covers the daemon capture wiring (beginLoginActivationCapture -> readVelaLoginStatus) that the pure parser spec can't reach. Auto-skips where the vela CLI isn't installed, so CI is unaffected. * fix(amr): polish inline auth retry layout * fix(daemon): try AMR login direct first, fall back to IPv4 proxy loopback AMR API proxy (forced IPv4) to dodge broken `amr-api.open-design.ai` edge paths for some hosts (#3726). But behind a corporate transparent proxy that hijacks `amr-api.open-design.ai` onto an internal gateway (e.g. 飞连/CorpLink → 30.x), the extra proxy hop makes the upstream lose the client IP and reject device authorization with `502: Invalid IP address: undefined` — even though the direct path resolves fine. Result: AMR "Authorize" fails in every packaged build that ships this change (beta/main), while release builds without it still work. Only `vela login` was rerouted; the model catalog and chat inference already go direct (to amr-link / VELA_LINK_URL), so this restores login to the same direct-first default. The IPv4 proxy is kept strictly as a fallback: the route now starts login over a direct connection and only retries through the proxy when the direct attempt fails to start — never when a login is already in flight. Both cohorts win: transparent-proxy users succeed directly, broken-edge users (#3726) still get the proxy. Tests: fake-vela gains FAKE_VELA_LOGIN_FAIL_WITHOUT_API_URL to model a broken direct path; the login suite now asserts direct-first (no VELA_API_URL on a healthy path) and proxy-fallback (VELA_API_URL set only after a direct failure, incl. OD_PUBLIC_BASE_URL derivation). * fix(amr): clear stale login activation details * fix(amr): refresh login status immediately after auth starts * fix(amr): sync inline auth card with login status * fix(amr): tighten inline auth retry state * fix(amr): wait for direct login activation before fallback * fix(amr): show activation details only in chat auth card * fix(amr): guard clipboard copy explicitly in the activation block navigator.clipboard?.writeText(...).then(...) already short-circuits the whole chain when the clipboard API is absent, but make the guard explicit so the copy handler reads as a clean no-op rather than relying on optional-chain reach. * fix(amr): don't kill a slow-but-healthy direct login; only fall back on real failure The login activation watchdog turned a merely slow direct CreateDeviceAuthorization into a hard failure: after the grace it killed the direct child and let the route retry through the IPv4 proxy — the exact proxy hop that 502s on the transparent-proxy networks this fix targets. Now the grace only stops blocking the request; a still- running direct attempt is left alive (the UI polls /status), and the proxy fallback fires only on an explicit pre-activation exit/error. The grace is overridable via OD_AMR_LOGIN_ACTIVATION_GRACE_MS so the new route test can exercise the slow-direct path quickly (fake-vela gains FAKE_VELA_LOGIN_ACTIVATION_DELAY_MS). Addresses review feedback on #4402. * test(e2e): AMR auth failure now signs in inline, not via Settings The chat AMR_AUTH_REQUIRED card replaced its 'open Settings to authorize' bounce with an inline sign-in pill (POSTs vela login in place, auto-retries on success). Update the [P0] runtime-recovery spec to assert the inline flow: clicking Authorize & retry issues the login request and opens no Settings dialog. The non-AMR 'Switch to AMR' recommendation flow (AmrGuidance) is unchanged. * fix(amr): only auto-retry inline auth on a real sign-in transition The inline AMR auth card auto-retried the failed run whenever /status reported signed-in — via both the 500ms shared-status poll and the pill's onStatusChange. Because the per-assistant-id guard resets on each retry (new run = new id), a run that keeps failing AMR_AUTH_REQUIRED while /status reads signed-in retried forever (caught by the runtime-recovery UI P0 spec). Now we retry only on an explicit signed-out -> signed-in transition; a null/unknown status never fabricates one, and once signed-in we don't retry again until an explicit signed-out is seen. - Unit specs updated to drive the transition (and a loop-guard spec for the already-signed-in case). - e2e: the AMR auth spec asserts the inline sign-in flow (no Settings bounce); the switch-to-Codex spec mocks /status signed-out, the realistic state for an AMR_AUTH_REQUIRED failure, so the Authorize & retry action is offered. * fix(amr): fall back to the proxy on a post-grace direct login failure The direct-first login route only fell back to the IPv4 proxy when the direct child crashed inside the 250ms startup grace. A direct vela login that survives the grace and then errors out before printing its activation URL (the common broken-edge shape, #3726) returned 202 and stranded the user on a dead direct login. Re-introduce waitForActivation: the route now blocks until the direct attempt reaches device-auth steady state (prints its activation URL) or exits/errors before it; only a pre-activation exit/error triggers the proxy retry, and a slow-but-healthy direct login is left running (never killed). fake-vela now prints the activation block (so the daemon can detect steady state) and gains FAKE_VELA_LOGIN_FAIL_WITHOUT_API_URL_DELAY_MS; the route suite gains a regression where the direct attempt fails past LOGIN_STARTUP_GRACE_MS and must still reach the proxy. Addresses review feedback on #4402. |
||
|
|
4b9a15734d |
[codex] Consolidate PR validation into CI (#4451)
* Consolidate PR validation into ci * Tune absorbed CI runner tiers * Fold visual validation into CI Playwright shards * Run PR shards during manual CI dispatch |
||
|
|
891981d460 |
[codex] Optimize CI runtime topology (#4450)
* Optimize e2e tools-dev runtime parallelism * Remove visual networkidle wait * Optimize e2e vitest parallelism * Optimize Nix flake caching * Test CI on Blacksmith runners * Allow parallel manual CI runs * Tier CI runner sizes * Temporarily narrow CI debug scope * Instrument watcher CI timeouts * Instrument watcher event diagnostics * Avoid default polling in watcher tests * Skip runtime trace during watcher debug * Probe ARM runner tiers for CI * Focus CI runner probe on x64 browser * Probe browser workers by runner size * Probe Playwright file parallelism * Probe Playwright worker scaling on 8v * Reshape CI topology * Fix split E2E Vitest CI lane * Simplify daemon CI topology * Optimize Windows payload CI setup * Revert "Optimize Windows payload CI setup" This reverts commit |
||
|
|
67ade60bce |
fix(e2e): seed win smoke onboarding into the live daemon data dir (#4444)
The packaged Windows smoke's onboarding seed derived its target path from the installed app's baked config, which falls back to AppData and never matches the data dir the running daemon actually reads. `tools-pack win start` rewrites `namespaceBaseRoot` to the tools-pack runtime root and hands it to the runtime via OD_PACKAGED_CONFIG_PATH, so the live daemon's RUNTIME_DATA_DIR is always under `runtimeNamespaceRoot`. The seed landed in the AppData fallback instead, so the daemon never read `onboardingCompleted`. This stayed invisible until #4389 removed the step-0 "Skip" affordance from the now-required Connect onboarding step: `ensureMainAppShell` used to click Skip to reach home, so an ineffective seed didn't matter. With Skip gone and the seed missing its target, the app sat on onboarding and the smoke failed with "packaged windows runtime did not reach main app shell". Write the seed to `<runtimeNamespaceRoot>/data/app-config.json` — the exact dir the running daemon reads (already asserted for logs at line ~400) and the same approach the macOS smoke uses. Drop the now-dead manifest-derivation helper chain. |
||
|
|
39cad2b8a5 | chore(release): bump version to 0.11.0 for release/v0.11.0 | ||
|
|
f6cceb303d |
fix(plugins): unwrap cosmetic hard wraps in bundled manifest descriptions (#4406)
Picking a Home example-prompt card (or "Replicate this content" in the plugin detail modal) seeds the composer with the plugin manifest's `description`. Many descriptions were authored with cosmetic hard wraps (a single newline mid-paragraph, ~75 cols, as if formatted for a terminal/markdown source). The composer renders the seed with `white-space: pre-wrap`, so those newlines survived as short ragged lines that never filled the editor width — leaving a large blank gutter on the right of the input box (e.g. the Trading Analysis Dashboard template: 4 hard breaks, ~200px / 29% of the editor blank). Reflow the offending `description` / `description_i18n` strings in the 56 affected bundled manifests into flowing text (wrapped lines joined, real blank-line paragraph breaks preserved; CJK joins carry no space). Surgical string edits only — manifest formatting/key order untouched (146 lines changed across 56 files). The full build spec still reaches the agent as plugin context (SKILL.md + example.html); only the human-facing seed copy changed. Add an e2e guard (plugin-description-hardwrap.test.ts) that fails if any bundled manifest description carries an intra-paragraph hard wrap, so the cleanup can't silently regress when new examples are added. |
||
|
|
a4abae3804 |
fix(release): build the daily beta from main, not the latest release branch (#4393)
* fix(release): build the daily beta from main, not the latest release branch
notify-daily-feishu picked the highest-semver release/vX.Y.Z branch and
built beta off it. Once that branch ships stable, its base version equals
the latest stable, so release-beta's strictly-greater-than-stable guard
rejects every scheduled run until someone hand-bumps the retired branch —
which is exactly how the daily beta + Feishu card silently stalled for
days after 0.10.1 shipped.
Beta is the daily R&D channel, so track the development tip (main), which
always leads stable. Keep the workflow_dispatch `ref` input for one-off
builds from a specific branch.
* test(release): scope daily-beta resolve check and assert ref override
Strengthen the regression test per review: scope the assertions to the
resolve job and prove both control-flow branches — the empty-input
default writes ref=main, and the workflow_dispatch override still
forwards ${{ inputs.ref }} verbatim — so a refactor can't keep the test
green while breaking the preserved override path.
|
||
|
|
f81439bdae |
feat(onboarding): gate Connect step, sequential stepper, restyle progress bar (#4389)
* feat(onboarding): gate Connect step, sequential stepper, restyle progress bar - Remove "Skip for now" — Connect is now a required step, not skippable. - Gate Continue until the selected runtime is usable: AMR signed in, an available local CLI selected, or a BYOK connection test that passed. - Make the stepper a strictly-sequential wizard: only already-reached steps are clickable, no forward jumps. Keys off a maxStepReached counter instead of the async AMR login probe, so the indicator no longer flickers disabled->enabled while that status resolves. - Disable the "+" new-tab affordance (button + Cmd/Ctrl+T) while on the onboarding route, so opening a tab can't bypass the Connect gate. - Restyle the stepper as a thin segmented progress bar with centered labels; drop the oversized "Welcome" hero title. - Deprecate the now-unreachable onboarding `skip` / `skipped` analytics enums (kept for historical data; no longer emitted). * test(onboarding): update specs for the new Connect gate behavior CI flagged onboarding tests still asserting the removed/changed UI. Vitest (apps/web): - e2e helper: wait for Continue to be enabled before clicking — AMR detection lags, so the Connect gate keeps it disabled until vela/status confirms signed-in; clicking a disabled button was a no-op and stalled at step 0. - "switches runtime" test: assert Continue is now disabled after switching to a not-yet-ready Local runtime (gate behavior). - about_you_submit-once test: advance via Continue instead of a stepper forward-jump, which is no longer allowed. - replace the Skip-exits test with one asserting the Connect step has no Skip affordance and emits no skip/skipped telemetry. Playwright (e2e/ui): - gotoOnboarding: key off the "Choose a runtime" heading instead of the removed "Welcome" hero title. - replace the skip-exits P0 with a no-Skip-affordance assertion. - visual-home: same Welcome -> Choose a runtime marker update. --------- Co-authored-by: free666799 <293857035+free666799@users.noreply.github.com> |
||
|
|
30b8eac48c |
chore(release): bump version to 0.10.2 on main (#4387)
main read 0.10.1 (== latest stable 0.10.1), so the daily beta build's strictly-greater-than-stable version guard refused to produce a beta from main. Advance the 0.10.x dev line to 0.10.2 across the same 16 lockstep workspace package.json that #4381 bumped, and align the packaged-smoke stable dry-run fixture to 0.10.2. This continues the existing beta line on R2 (0.10.2-beta.4) so a build from main produces 0.10.2-beta.5. |
||
|
|
66d9cf9fb6 |
fix(release): accept releaseVersion/releaseNumber in beta metadata reader (#4383)
The daily beta build (notify-daily-feishu) reads beta/latest/metadata.json via scripts/release-beta.ts, which only understood the legacy betaVersion/betaNumber fields. The unified release publisher and the in-flight tools-release rewrite stamp the feed with generic releaseVersion/releaseNumber instead, so once a build from that tooling wrote the feed the daily reader died with 'must include betaVersion or baseVersion+betaNumber' and the scheduled beta + Feishu card stopped. Accept either field spelling so the reader survives whichever publisher last wrote the feed. |
||
|
|
a3a5f02d87 |
chore(release): bump version to 0.10.1 on main (#4381)
Back-fill the 0.10.1 version bump that shipped via the release/v0.10.1 branch (tag open-design-v0.10.1, already published) but never merged back to main. The feature/perf content of that release already landed on main via #4198, #4203 and #4202; only the version-number bump and the packaged-smoke stable fixture were left behind, so main still read 0.10.0. This applies the release-specific deltas onto current main: - bump version 0.10.0 -> 0.10.1 across the 16 workspace package.json in the 0.10.x release set (apps/daemon, apps/desktop, apps/landing-page, apps/packaged, apps/web, e2e, root, packages/contracts, packages/download, packages/host, packages/launcher-proto, packages/platform, packages/sidecar-proto, packages/sidecar, tools/dev, tools/pack) - align e2e packaged-smoke stable fixture to 0.10.1 launcher-proto was added to main after the 0.10.1 release branch was cut, so it was not in the original release commit; it is part of the lockstep 0.10.x release set (private workspace package, sibling of sidecar-proto), so it is bumped here to keep main release metadata consistent. Independently-versioned workspace packages (agui-adapter, components, diagnostics, metatool, plugin-runtime, registry-protocol, tools/serve, telemetry-worker) are intentionally left untouched. Supersedes the stale release/v0.10.1 PR (#4205). |
||
|
|
f2fef8d9a5 |
[codex] fix prompt title summaries (#4348)
* fix prompt title summaries * fix ui p0 title expectations * use selected agent for title suggestions * strip generated titles across streams |
||
|
|
95900a615b |
Fix design system preview image asset URLs (#4177)
* fix: rewrite design system preview image assets * fix: reopen design review feedback cards * fix: preserve app urls in design previews * fix: preserve design preview asset suffixes * fix: rewrite inline design preview css assets * fix: refresh design manifest labels * fix: surface invalid design manifests * test: stabilize workspace restoration p0 * fix: validate design manifest card entries |
||
|
|
6c555f93d6 |
chore(ci): stabilize visual regression screenshots (#4290)
* Stabilize visual regression screenshots * Stabilize BYOK visual settings states |
||
|
|
a0afc584bb |
[codex] centralize daemon data directory docs (#4222)
* docs: centralize daemon data directory contract * fix(e2e): allow slower artifact consistency navigation Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * docs: localize daemon data directory pointers Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com> |
||
|
|
f82a4e3828 | fix(web): apply composer BYOK model selection (#4209) | ||
|
|
571b43dce0 |
[codex] Expand UI E2E coverage and P0 CI signal (#4196)
* add PR UI P0 gate * fix(ci): keep critical UI check in required workflow Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * ci: split workspace restoration P0 shard * ci: reduce visual and daemon test wall time * ci: skip duplicate critical UI gate on PRs * ci: increase daemon test sharding * test(e2e): expand critical UI flow coverage * test(e2e): promote critical onboarding and automation flows * test: expand ui e2e coverage * test: repair PR P0 onboarding and media sync checks Generated-By: looper 0.9.7 (runner=fixer, agent=codex) |
||
|
|
21e01f6a25 |
Fix raw asset review cards in design systems (#4093)
* fix: avoid raw asset review cards * fix: resolve web component styles in dev * fix: keep design system component images reviewable * fix: use webpack for local web dev sidecar * fix: improve design system review cards * fix: render design system review previews from srcdoc * fix: keep image ui kit cards generic * fix: rebase inlined preview css urls * test: allow slow send-now navigation --------- Co-authored-by: Siri-Ray <2667192167@qq.com> |
||
|
|
2f301902d7 |
fix(web): keep New Project design-system dropdown above form sections (#4026)
The 'Design system' dropdown in New Project rendered behind the form sections below it (Target platforms, Companion surfaces, Fidelity, Create), so the form bled through the open popover. Every .newproj-section carries a residual identity transform from the od-fade-slide-up entrance animation (animation-fill-mode: both), turning each section into its own stacking context. .ds-picker is such a section, so the popover's z-index was trapped inside the picker and could not rise above later sibling sections. Lift the OPEN picker's stacking context above its siblings so the dropdown paints on top. Red->green Playwright spec samples points down the open popover and asserts elementFromPoint resolves into the popover. |
||
|
|
d055737de7 |
[codex] Add PR UI P0 gate (#4142)
* add PR UI P0 gate * fix(ci): keep critical UI check in required workflow Generated-By: looper 0.9.7 (runner=fixer, agent=codex) |
||
|
|
8c3500c807 |
[codex] Cover preview toolbar and conversation history flows (#4134)
* test(e2e): expand home and project detail coverage
* test: cover preview toolbar and conversation history flows
* test: lower priority of supplemental e2e cases
* Revert "test: lower priority of supplemental e2e cases"
This reverts commit
|
||
|
|
4c8914dc71 |
feat(web): split onboarding newsletter into its own third step (#4106)
* feat: move onboarding newsletter signup to its own third step * test(e2e): walk amr-onboarding through the new newsletter step before finishing * fix(web): keep about_you_submit exactly-once on the onboarding completion path The newsletter step is now its own (final) step with a clickable stepper and Back button. Emitting the about_you_submit survey snapshot when the user leaves the About-you step double-fired on Back-then-Continue and fired zero times on a forward stepper jump. Move it onto the completion path, stamp it with fixed About-you coordinates (it describes the About-you submission regardless of which step finishes), and guard it with a per-session ref so it is exactly-once. Adds regression tests for the stepper-jump and Back-then-Continue flows. * test(web): walk amr onboarding e2e through the newsletter step before finishing --------- Co-authored-by: qiongyu1999 <2694684348@qq.com> Co-authored-by: lefarcen <935902669@qq.com> |
||
|
|
70c70ff9a3 |
feat(web): replicate-first Use menu + send-button attention pulse (#4059)
* feat(web): lead the plugin detail Use menu with Replicate this content The split-button menu only exists when the plugin ships an example query, and reproducing the previewed result is what most users open it for — so the replicate option now comes first and structure-only Use drops to second. * feat(web): pulse the send button after a plugin Use or example-prompt pick Choosing Use / Use with query in the plugin detail modal, or clicking an example-prompt card, seeds the composer and returns the user to it — but nothing signals that sending is the next step. Flash the send button twice (house ease-out, 0.25s delay so the scroll-back settles first, none under prefers-reduced-motion) via a new HomeHeroHandle.pulseSend() fired from routePluginUse and useExamplePlugin. * feat(web): replicate-content as the primary detail CTA + sheen-style send pulse - The detail modal's primary Use button now reads (and acts as) 'Replicate this content' when the plugin ships an example query; structure-only Use moves behind the caret menu. Shared via pluginUsePrimaryAction so all four detail variants agree. - The send-button attention effect drops the ring+scale flash for a soft light sweep crossing the button twice — same trigger points, same reduced-motion opt-out. - Plain structure-only Use now pulses only when the composer is actually submittable (draft text or staged files); flashing a disabled send button pointed at a dead end. * feat(web): first-run guidance trail — prototype chip and first preset card sheen Brand-new users (no projects, fresh storage) get a sheen pulse on the Prototype type chip ~1s after Home settles; picking any type chip advances a persisted stage and the first example-prompt card pulses once when the chip's presets render, completing the trail (the existing send-button pulse covers the final beat after a card pick). Users with projects have the stage completed silently so the trail never shows. The send-button sheen generalizes into a shared .home-hero__attention-sheen class (accent-tinted glint on light chip / card surfaces), still skipped under prefers-reduced-motion. * fix(web): gate the first-run guide on project loading completing firstRunGuide was true whenever projects was the initial empty array, so the trail could arm for an existing user whose projects were still loading. Make the prop tri-state (undefined while loading): the guide neither arms the chip pulse nor silently completes the stage until the projects answer is known. * fix(web): close any in-flight guide stage for existing users + gate the card pulse A chip pick during the projects-loading window can advance the guide stage to 'card' before firstRunGuide resolves; if the user then turns out to have projects, the stage lingered and the beat-2 effect (not gated on firstRunGuide) could sheen the first preset card for a non-new user. The firstRunGuide === false branch now completes ANY unfinished stage, and the card-pulse effect requires firstRunGuide === true. * fix(web): pulse Send from the static prompt-example path too The fallback prompt-example cards (rendered when a chip has no example plugins) seed and focus the composer entirely inside HomeHero, so they never reached the HomeView-routed pulseSend(). Extract a local triggerSendAttention() shared by the imperative handle and usePromptExample, with a focused spec clicking a home-hero-prompt-example card. * fix(test): null-guard the first prompt-example card lookup tsc (noUncheckedIndexedAccess) rejects passing exampleCards[0] straight to fireEvent.click; guard explicitly. * fix(web): gate the Send pulse on the composer actually being submittable usePlugin() now resolves a boolean: whether the bound plugin left the composer submittable (inputs valid, apply not failed/superseded). All three pulse call sites (use-with-query, plain Use, example preset pick) consult it, so a plugin with required inputs and no defaults routes the user to the inputs form without a misleading flash on the disabled Send button. Spec: required-input plugin via detail-modal replicate → Send stays disabled and unsheened. * fix(web): carry the guide's beat 2 through the static prompt-example fallback A chip with no plugin presets renders static prompt-example cards, but the beat-2 effect only watched filteredExamplePlugins — a fresh user on that path never got the card pulse and the persisted stage stuck at 'card'. Either card surface now satisfies beat 2, the first static prompt-example button carries the sheen, and a regression spec covers the presetless-chip path. * test(e2e): route freeform Use through the Use-plugin-only menu option The replicate-first menu change makes the detail modal's primary Use button seed the example query for query-bearing starters, so the structure-only freeform path now lives in the caret menu's 'Use plugin only' option. Update the P0 critical 'keeps the prompt freeform' spec to open the caret menu and click that option, matching the shipped behavior. * test(e2e): route the remaining freeform Use cases through the menu option The replicate-first primary CTA also seeds the prompt for query-bearing starters rendered via PluginExampleDetail/PreviewModal, so the neighboring [P1] 'Use plugin from the details modal' case (an html-preview fixture with an example query) that clicked the primary button and asserted an empty composer would fail once it runs outside the @critical gate. Route it through the caret menu's 'Use plugin only' option like the P0 case, and correct the now-stale 'no pre-fill' comments on the chip-only and use-with-query cases. --------- Co-authored-by: qiongyu1999 <2694684348@qq.com> Co-authored-by: lefarcen <ontf116@gmail.com> |
||
|
|
a0221deaba |
[codex] Fix onboarding dropdown styling (#4066)
* Fix onboarding dropdown styling * Fix onboarding dropdown placement test Generated-By: looper 0.9.7 (runner=fixer, agent=codex) * Fix searchable onboarding dropdown regressions Generated-By: looper 0.9.7 (runner=fixer, agent=codex) |
||
|
|
844a0c0af1 |
fix(web): scope Use actions to the plugin detail modal and decouple the Community filter from hero chips (#4037)
* fix(web): remove inline Use actions from Community gallery tiles The Home Community gallery tile grew an inline Use / Use with query split button in its title bar, repeating per card. The gallery tile is a pure live preview: opening the detail modal is where Use and Use with query live. Drop the gallery use menu (and its CSS) and route the visual-home use-with-query e2e flow through the detail modal's split Use button. The rich management layout (PluginsView installed tab) keeps its hover-overlay Use menu. * fix(web): decouple the Community category filter from hero type chips Picking an example-prompt type chip (Prototype / Slide deck / ...) — including the default chip on first paint — force-synced the Community grid's category selection through presetSelection, silently rewriting the user's browsing filter. The two surfaces share a taxonomy but are independent controls: the chip drives what the composer generates, the pills only filter the gallery. Remove the presetSelection plumbing (HomeView memo -> PluginsHomeSection prop -> usePluginFacets effect); the Community grid now boots on All and only moves when its own pills are clicked. * fix(e2e): match the Deck Writer detail dialog by plugin name Deck Writer carries a previewEntry, so its detail surface is the PreviewModal whose dialog is labelled 'Deck Writer preview' — the '... details' label only exists on the scenario detail. Match the dialog on the plugin name so the visual use-with-query flow finds it. --------- Co-authored-by: qiongyu1999 <2694684348@qq.com> |
||
|
|
39cf931290 |
Remove project instructions UI and preserve stream errors (#4045)
* Remove project instructions UI and preserve stream errors * Stop injecting hidden project instructions Generated-By: looper 0.9.7 (runner=fixer, agent=codex) |
||
|
|
3f5fe0f96c |
feat(amr): forward AMR_CLIENT_SOURCE to vela + source on wallet links (#4005)
* fix(landing): keep auth redirects on AMR wallet * feat(amr): tag vela CLI launches with AMR_CLIENT_SOURCE + source on wallet links So vela analytics can attribute Open Design's command funnel and model spend back to this host (source=open_design), and the AMR wallet landing carries the source for the web page_view. - runtimes/env: set AMR_CLIENT_SOURCE=open_design for the amr agent spawn (not PII, so no telemetry-consent gate) - integrations/vela: spawnVelaLogin forwards OD_INSTALLATION_ID (consent-gated) - web/daemon: AMR wallet recharge URL gains ?source=open_design Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(web): expect ?source=open_design on AMR console/recharge URLs The AMR console/recharge links the OD app opens into vela web now carry ?source=open_design so vela attributes the visit to Open Design. Update the console/recharge URL assertions accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(daemon): expect ?source=open_design on AMR insufficient-balance recharge URL DEFAULT_AMR_RECHARGE_URL now carries the source param for attribution. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(amr): bump bundled vela CLI to 0.0.15 + fix e2e recharge URL assertion - tools/pack: bundle @powerformer/vela-cli 0.0.15 (the release carrying the source-attribution logic that reads AMR_CLIENT_SOURCE and tags model_request) - e2e: expect the insufficient-balance recharge URL to carry ?source=open_design (addresses review on DEFAULT_AMR_RECHARGE_URL) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(nix): refresh pnpm-deps hashes after vela CLI bump The tools/pack @powerformer/vela-cli bump changed pnpm-lock.yaml, invalidating the daemon/web fetchPnpmDeps fixed-output hashes. Update to the values the Nix flake check computed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: audit <a@b.c> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6313286232 |
feat(home): plugin detail "Use plugin" split menu + align use-with-query with example-prompt seed (#3997)
* feat(home): plugin detail "Use plugin" split menu + align use-with-query with example-prompt seed
- PreviewModal.primaryAction gains an optional split-button menu. The plugin
detail modal's "Use plugin" now offers two variants — 仅使用插件 (use) and
复刻此内容 (use-with-query) — wired through the existing routePluginUse action,
i18n'd across all 19 locales (new preview.usePlugin / usePluginOnly* /
replicateContent* keys).
- use-with-query now seeds the composer with the SAME human-friendly text the
Home example-prompt cards use. Extracted examplePresetSeedPrompt (+ its
dependencies) from HomeHero into a shared plugins-home/presetSeedPrompt module
so both surfaces share one source of truth, instead of the detail modal
dumping the raw od.useCase.query meta-instruction ("follow the en field
verbatim; start from example.html") into the textarea.
- The example-prompt active plugin chip now shows the same × clear button as the
Community path (activeBadge.isExplicitPlugin distinguishes a user-picked
plugin from a task-chip default).
- Analytics: community_gallery/use_plugin (action=use|use_with_query) lands the
documented row-118 event; chat_composer/plugin_chip_clear mirrors
working_dir_clear for the chip ×.
* feat(prompt): generate artifact copy in the user's UI locale
Chinese (and other non-English) prompts were producing English pages: when a
template / plugin / design-system ships English reference content, the agent
copied that wording verbatim. The UI-locale override only covered chat prose
and generated form controls, not the artifact body.
Extend the locale override so all user-visible copy in the generated
HTML/React/page/deck (headings, body, nav, button/link labels, captions, alt
text, form fields) is written in the run's UI locale by default — and reference
content in another language must be translated/adapted, not shipped verbatim.
Brand names / code / identifiers stay as-is; an explicit user request for a
different output language still wins.
* fix(plugin-details): scenario fallback gets the use/use-with-query split menu
Review follow-up (#3997): PluginScenarioDetail was a single onUse(record,'use')
button, so any plugin routed to the text/scenario fallback lost the new split
action — users couldn't pick "Use plugin only" vs "Replicate this content" even
when od.useCase.query exists. Reuse the shared buildPluginUseMenu in the footer
as an upward-opening split button (caret menu), matching the html/design/media
variants, and keep a plain single button when there is no query.
Also update the home use-with-query visual e2e: use-with-query now seeds the
rendered preset text ("Draft a topic deck.") rather than the raw `{{topic}}`
query, matching the example-prompt card path.
Regression tests: scenario+query renders the split menu caret; scenario without
query keeps a single button.
* fix(home): preserve placeholder write-back when use-with-query seed is the query
Review follow-up (#3997, blocking): use-with-query unconditionally nulled
`queryTemplate`, dropping the only path that writes composer edits back into
`active.inputs`. For presets whose seed IS the rendered (human-friendly) query,
that meant editing a hydrated value before running submitted the plugin with
stale default inputs.
examplePresetSeedPrompt now returns `{ text, fromRenderedQuery }`. routePluginUse
keeps the raw `{{...}}` query template (and `queryTemplateAllowsPrefix`) only when
the seed came from the rendered query; it still nulls the template when we fell
back to a description / meta-instruction seed (no placeholders to extract). The
meta-instruction → description fix is unchanged.
Tests: friendly-query use-with-query now asserts the placeholder edit flows back
into pluginInputs (empty-draft and edited-draft-prefix cases); the
meta-instruction case still seeds the description with no write-back.
* fix(home): persist explicit-pick flag for active plugin chip visibility
Review follow-up (#3997): the active plugin chip's visibility + clear-button
gate inferred "explicit pick" from `record.id !== defaultPluginIdForChip(chipId)`.
An example-prompt preset whose plugin id equals the chip's default plugin — the
prototype rail binds `example-web-prototype`, which is also the prototype chip's
default — was therefore misclassified as a task-default binding, so its chip/×
never appeared even though the user explicitly picked the preset.
ActivePlugin now carries an `explicitPick` flag, set on the example-prompt
preset (useExamplePlugin) and Community / detail-modal (routePluginUse) paths.
Both `activeBadge` (chip label vs plugin title + ×) and
`shouldShowActivePluginChip` (the chip-visibility gate) short-circuit on it
before falling back to the id heuristic — so an explicit pick always surfaces
its own chip, while a type-chip default binding still stands in for the task
chip. Added a HomeView.activePluginChip regression covering the preset-equals-
default case.
* fix(home): keep prefix matching on for use-with-query placeholder extraction
Review follow-up (#3997): `queryTemplateAllowsPrefix` only enabled prefix
matching when the composer already had text BEFORE the user clicked Replicate.
The empty-draft → prepend-intro → edit-placeholder path then fell through:
extraction stayed anchored at `^`, so a placeholder edit after a freshly-added
intro stopped writing back into active.inputs and submit could re-apply stale
defaults.
Enable prefix matching whenever we track the query template (`hasTemplate`).
Suffix matching is equally correct with no prefix, and now tolerates an intro
the user prepends after the seed is inserted. Added the empty-draft → add
prefix → edit placeholder regression.
---------
Co-authored-by: qiongyu1999 <2694684348@qq.com>
|
||
|
|
f9433a7a07 |
release: harden packaged launcher validation (#3995)
* Unify release metadata publishing * Allow empty release asset suffix * Harden beta-s release publishing * Clean beta Windows release namespace * Clean Windows launcher namespace * Retry transient mac notarization uploads * Control mac notarization upload mode * Notarize release mac DMGs after build * Harden release mac DMG notarization retries * Make beta-s mac updates payload-first * Bake mac updater metadata URL * Add unsafe DMG install helper * Fix beta-s feed and About version * Improve release validation observability * Build launcher proto before packaging * Notarize release-stable mac artifacts * Enable mac notarization in tools-pack * test: update packaged release workflow assertions |
||
|
|
6a10e8e178 |
fix(daemon): classify Claude mid-stream socket drops as retryable (#3937)
* fix(daemon): classify Claude mid-stream socket drops as retryable
When the Claude Code CLI's connection to the Anthropic API (or a custom
ANTHROPIC_BASE_URL relay) drops mid-response, the SDK surfaces 'The socket
connection was closed unexpectedly...'. The daemon relayed this raw SDK
string verbatim into the error bubble because diagnoseClaudeCliFailure had
no branch for an established-then-dropped connection (distinct from the
existing connection-refused case).
Add a connection-drop branch that classifies socket-close / ECONNRESET /
socket hang up / fetch failed / premature close into a human-readable,
retryable diagnostic, pointing at the proxy when a custom endpoint is set
and at the network otherwise. Most visible on long, large generations.
The fake-agent CLI gains a 'Return a daemon socket-drop failure' mode whose
claude shape was captured from the real Claude Code CLI 2.1.168 driven at a
socket-dropping endpoint (error on stdout as a synthetic assistant block +
result{is_error:true}, exit 1, empty stderr), so the e2e path exercises the
real failure shape rather than a guessed one.
* fix(daemon): use OpenClaude socket-drop diagnostics
Generated-By: looper 0.9.7 (runner=fixer, agent=opencode)
* fix(daemon): harden Claude connection-drop diagnostic from real repro
Reproduced end-to-end against the real Claude Code CLI (2.1.168, official
auth, no ANTHROPIC_BASE_URL) by tunneling through a local proxy that resets
the TLS stream mid-response. Two real error faces observed: 'The socket
connection was closed unexpectedly' (SSE cut) and 'Unable to connect to API
(ECONNRESET)' (tunnel reset); the CLI retries internally for minutes before
surfacing either, which is why long runs appear to abort after a while.
Broaden the connection-drop matcher with 'unable to connect to api' and
ETIMEDOUT, and lock the real ECONNRESET transcript into the test suite.
* fix(daemon): narrow Claude API drop matcher
Generated-By: looper 0.9.7 (runner=fixer, agent=opencode)
* feat(daemon,web): structured AGENT_CONNECTION_DROPPED code + localized message
Promote the Claude connection-drop diagnostic from a raw English string to a
stable, machine-readable failure class so the web can localize it and triage
can count it by code.
- contracts: add AGENT_CONNECTION_DROPPED to API_ERROR_CODES.
- daemon: ClaudeCliDiagnostic carries an optional code; the connection-drop
branches stamp AGENT_CONNECTION_DROPPED; server.ts prefers diagnostic.code
over the generic service-failure sniff so the run records the specific class
(flows into run_finished error_code + routine_runs.error_code for triage).
- web: resolveRunFailureUi maps AGENT_CONNECTION_DROPPED (any agent) to the
localized chat.connectionDropped message, plain retry, no AMR promotion.
- i18n: add chat.connectionDropped to types.ts and all 19 locale bundles.
* fix(daemon): classify Claude in-stream connection-drop error frame
End-to-end repro on a real daemon + fake Claude CLI revealed the diagnostic
never fired: Claude surfaces a connection drop as an in-stream `error` frame
(assistant error:"unknown" + the raw SDK string), which claude-stream emits
as a type:'error' event. The daemon's stream-error handler sent that raw
string verbatim as a non-retryable AGENT_EXECUTION_FAILED and set
agentStreamError, so the child-exit diagnoseClaudeCliFailure path was skipped
entirely.
Run the same per-agent diagnostic in the stream-error handler so a connection
drop emits AGENT_CONNECTION_DROPPED (retryable, with localizable copy +
triage-countable code) instead of the raw SDK string. Verified end-to-end via
the real-daemon-run Playwright test, which now asserts the localized card copy.
|
||
|
|
90817ce72c |
Rebalance Playwright critical gate (#3904)
* Rebalance Playwright critical gate * Fix staged attachment e2e selectors * Run critical gate before visual PR checks * Expand strict PR visual coverage * Widen visual harness config fixtures Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * Expand strict visual suite to 35 cases * Stabilize critical app artifact selectors * Fix onboarding visual model assertion Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * Stabilize settings dialog e2e entry * Reduce UI extended E2E failure fanout * Handle nested settings menus in e2e helper * Sync AMR logout status to settings card * Centralize agents route mocks in E2E * Fix critical smoke settings grep Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * Consolidate E2E agents route fixtures * Stabilize critical project instructions test Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * Let nested agents mocks handle routed requests Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * Stabilize project instructions critical gate Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * Stabilize visual home plugin surfaces * Upload critical gate artifacts in visual PR job * Fix visual PR gate reports and fixtures * Address PR 3904 review paths * Localize project instructions control |
||
|
|
5e5134ba86 |
fix(web): interrupt the active run when sending a queued chat now (#3959)
* fix(web): interrupt the active run when sending a queued chat now
Clicking the up-arrow ("send now") on a queued chat send while the
agent is still working only moved that item to the front of the queue.
For the common single-item case that is a no-op: the button looks like
a send action but nothing happens until the in-flight turn finishes on
its own, so it reads as broken.
Make "send now" do what it says: when the conversation is busy, stop the
active run and prioritize the chosen item. Stopping flips the conversation
out of its busy state and the existing auto-start effect then flushes the
now-first queued send through the same path as a natural completion, so
runs still never overlap.
handleStop moves ahead of the queued-send handlers so sendQueuedChatSendNow
can call it.
* fix(web): preserve replacement run streaming on stale cancel
Generated-By: looper 0.9.7 (runner=fixer, agent=opencode)
* fix(web): ignore stale run finalization after queued send
Generated-By: looper 0.9.7 (runner=fixer, agent=opencode)
* fix(web): ignore a superseded run's late stream error
Final stale-callback edge in the "send now" interrupt path. The stream
onError handler unconditionally painted a global failure banner, appended
an assistant error event, and marked the assistant message failed. A run
interrupted by send-now can still land in onError (e.g. a canceled stream
that lost its terminal SSE and whose fallback status fetch sees a
non-terminal run), so the superseded run could flash a stale failure
banner while the replacement run is already streaming.
Gate the banner / message finalization on the same controller-pair
ownership check used for the marker and latest-run teardown. Only the run
that still owns the active controllers surfaces the error.
* fix(web): ignore stale run completion side effects
Generated-By: looper 0.9.7 (runner=fixer, agent=opencode)
* fix(web): guard reattach terminal callbacks for superseded runs
The send-now interrupt's real target is often a reattached run (the agent
was already streaming when the user queued). Apply the same controller-pair
ownership guard the stream path uses to the reattach terminal callbacks: a
superseded reattached run's late onDone must not persist artifact /
produced-file output, and its late onError (or the consume catch) must not
paint a global failure banner, over the replacement run that now owns the
conversation. Normal completion is unchanged.
* test(web): cover the interrupted reattached run's late error
Red-green regression for the reattach guard: a reattached run interrupted
by send-now, whose late onError lands after the replacement queued send has
started, must not paint a global failure banner. Goes red without the
controller-pair ownership guard on the reattach error path.
* fix(web): don't drop a normal run's completion after its terminal status
The superseded-run guards checked ownership as
`abortRef === controller && cancelRef === cancelController`, but the daemon
emits the terminal onRunStatus *before* onDone, and that terminal status
clears the run's active refs. So for a normal successful run the refs were
already null by the time onDone ran, the guard read false, and onDone bailed
— skipping artifact persistence and produced-file attachment. (Caught by the
artifact-consistency e2e: the saved file metadata never aligned.)
Reframe the check as "a newer run owns the active slot": a run may finalize
when abortRef is null (its own terminal status cleared it — the normal path)
or still points at its own controller; only a live replacement (abortRef set
to a different controller) means it was superseded. Applied to every stream
and reattach terminal callback. Adds a unit regression that fires the terminal
status before onDone and asserts the completion flow still runs.
* fix(web): tag superseded runs at interrupt time, not via abortRef
The previous guard read ownership off abortRef in each terminal callback,
but that is unreliable: a normal run's terminal onRunStatus clears the refs
before onDone, and handleStop() clears them before a canceled run's late
callbacks arrive — so abortRef === null was ambiguous between "completed
normally" and "interrupted, replacement not yet attached". The latter let a
superseded run still run its completion flow and repaint the shared artifact.
Record the interrupted run's abort controller in a WeakSet synchronously in
sendQueuedChatSendNow — before handleStop() clears anything — and have every
stream/reattach terminal callback skip its current-run side effects when its
controller is tagged. This is independent of abortRef churn and holds even
before the replacement send attaches. The reattach onDone also bails ahead of
parser.flush()/setArtifact()/message finalize so a stale run can't repaint the
artifact preview; only run bookkeeping is released for a superseded run.
Adds a regression that interrupts a reattached run and delivers its late
onDone, asserting the completion flow (file refetch) does not run.
* fix(web): reset applying comment status when send-now interrupts
A turn moves its preview-comment attachments to 'applying' when it starts.
Now that send-now suppresses the interrupted run's terminal callbacks, those
callbacks no longer flip the comments to 'needs_review'/'failed', so they were
left stuck as 'applying' after the replacement send took over — the UI kept
showing an interrupted review comment as still being applied.
Reset the conversation's 'applying' preview comments back to 'open' in the
send-now interrupt path (local state + persisted), so a canceled turn's
comments don't strand mid-apply. Adds a red-green regression.
* fix(web): only reset the in-flight run's stuck applying comments
The previous reset flipped every 'applying' comment in the conversation to
'open', but queued sends (including the one being prioritized by send-now)
also hold their attachments in 'applying'. Resetting those raced the
replacement run's re-apply and reopened comments still reserved by other
queued work.
Scope the reset to the interrupted in-flight run's comments only — the
'applying' ones not owned by any queued send. Regression flipped to assert a
queued comment-bearing send's own comment is NOT reset to 'open' when
send-now flushes it.
* test(e2e): cover send-now interrupt end-to-end
Browser-level e2e against a real daemon + fake agent for the send-now
queued-send feature: start a held (never-finishing) run so the conversation
stays busy, queue a second turn, click the queued item's send-now arrow, and
assert the held run is canceled and the queued turn dispatches as a fresh run
while the queued strip drains.
Adds a 'Hold the daemon run open until canceled' fake-agent mode that stays
alive until the daemon cancels it, and a data-testid on the queued send-now
button for a stable selector.
---------
Co-authored-by: audit <a@b.c>
|
||
|
|
d859f6dec7 |
fix(web): flatten the composer footer into one tidy inset card (#3962)
* fix(web): flatten the composer footer into one tidy inset card Follow-up polish to the alignment fix (#3949). The composer mounts under `.chat-composer-fixed-layer`, whose shell had `padding: 0`, so the staged chips, the input field and the toolbar hugged the card's rounded frame and the footer stacked several competing layers: a tinted outer card around a separate inner box, a toolbar divider, and the + / Send buttons flush against the card edges with no side margin. Collapse it into a single inset card: - Keep the typing area a clean white field (`--bg-panel`) with a soft resting border so it reads as the one input surface inside the tinted card. - Drop the toolbar's `border-top` divider (and its 2px spacing) — the white field is the only separator the footer needs now. - Give the shell an even `6px 8px` inset so the chips, input and toolbar all sit off the frame, including a real side margin on + and Send. - Pin the toolbar row to the 28px control height (was a 32px min-height that left 4px of dead space and made the footer band feel too tall). - Lower the footer label-collapse `@container` breakpoint 430px -> 414px to account for the shell's new side padding shrinking the queried container width, so the "Design"/"Send" labels stay until the pane is genuinely tight. Adds e2e/ui/composer-footer-card.test.ts as the regression boundary: the + and Send keep a side inset, the input field is evenly inset, and the toolbar has no top border. Red on main (insets ~1px, border 1px), green here. * fix(web): scope composer footer inset to the fixed layer, keep @container generic Addresses review feedback: the previous commit lowered the shared `@container (max-width: 430px)` label-collapse breakpoint to 414px to compensate for the fixed-layer shell's new side padding. But that @container block governs every `.composer-shell` — including the comment composer (`.comment-side-new-comment-shell` in FileViewer.tsx) — so the global shift would have delayed the Send/label collapse on surfaces whose sizing never changed, risking cramped/overflowing controls there. Keep the breakpoint generic at 430px and instead apply the footer's side inset as a margin on the fixed-layer shell's children rather than horizontal padding on the shell. The shell's content-box width (what the @container measures) stays full, so the chat footer keeps its + / Send side margins while every other composer's responsive behavior is untouched. --------- Co-authored-by: audit <a@b.c> |
||
|
|
2ce9d09f41 |
Fix Windows launcher beta update lifecycle (#3960)
* fix windows beta updater acceptance harness * fix: harden windows launcher beta updates * fix: align launcher payload e2e relaunch stub Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * fix: gate windows uninstall version sync Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * fix: verify launcher payload before activation Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com> |
||
|
|
992824c594 |
fix(web): align composer footer controls to one height (#3949)
The composer's bottom toolbar mixes five controls authored in five
components — the + icon, the working-dir pill, the agent avatar, the
session-mode ("Design"/CLI) toggle and Send. The composer mounts under
`.chat-composer-fixed-layer` (a body-level portal), so chat.css's
`.app`-scoped "one control system" normalization never reached it. The
controls drifted to 28/30/32px: the + and avatar/Design at 32px (the
28px override floored back up by a leaking min-width/min-height:32 from
chat.css), Send at 30px, and only the working-dir pill at 28px. They
stay vertically centered, but the differing heights leave the pills and
Send visibly misaligned against the left buttons.
Normalize all five to one 28px control height in routines.css (the
last-loaded, winning stylesheet): clear the leaking 32px min-width/
min-height on the + icon, drop fixed-layer Send from 30px to 28px, and
pin the session-mode toggle and agent avatar — which had no fixed-layer
override — to 28px. Covers both the `.app` and `.chat-composer-fixed-layer`
hosts.
Adds e2e/ui/composer-toolbar-alignment.test.ts as the regression
boundary: every interactive control in the composer row must share one
height. Red on main (height spread 4px), green here (spread 0).
Co-authored-by: audit <a@b.c>
|
||
|
|
3aeb3a125e |
feat(web): live-preview Community gallery + redesigned plugin detail modal (#3903)
* feat(web): live-preview Community gallery + redesigned plugin detail modal Community (Home) now renders each plugin as a minimal live-preview tile — a macOS-window bar (status dot + name + open-in-new-tab) over an eagerly rendered, scaled example.html iframe that auto-pans on hover; clicking the tile opens the detail modal. Adds a `gallery` card layout so the installed- plugins management view keeps its rich hover-overlay card. Reworks the plugin detail modal for designers: - Preview is the hero: the info sidebar starts collapsed and the scaled iframe fills the stage edge-to-edge (measure via clientWidth so the modal entrance transform no longer leaves a white gutter). - Header: title + description on the left, Use plugin + Share on the right, one centered row. Drops the More and Plugin-info header buttons; the sidebar opens via the preview-edge handle. - Fullscreen moves to a hover-only icon button in the preview's top-right. - Sidebar (variant="minimal"): author + example query up top, developer manifest detail behind a "Developer details" disclosure; calmer labels, box-free author, softer query block in the regular UI font. - Softer slide-in animation when the info panel opens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): restore detail test hook + keyboard guard on gallery plugin cards The gallery tile replaced the rich card's "Details" button with a whole-card onClick, which broke e2e/visual flows (and the strict visual job) that open the detail modal via `plugins-home-details-<id>`, and HomeView.plugin-i18n which drove Use through the inline card buttons. - Re-add `data-testid="plugins-home-details-<id>"` to the gallery article so click-to-open keeps a stable hook equivalent to the old Details button. - Guard the card keydown handler with `event.currentTarget === event.target` so Enter/Space on the nested ↗ external-link anchor opens the real page instead of being swallowed into the detail modal. - HomeView.plugin-i18n: drive plain Use through the detail modal (gallery has no inline Use button); drop the Home use-with-query case — that affordance now lives on the rich PluginsView cards (covered by PluginsView.test.tsx) with query localization covered by state/projects.test.ts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): scope the header sidebar-toggle removal to the plugin detail Removing the PreviewModal header sidebar toggle globally also dropped the design-system modal's "DESIGN.md" button, breaking the entry-chrome-flows e2e. Add a `hideSidebarToggle` prop and set it only on the HTML plugin detail (PluginExampleDetail), which opens its collapsed info panel via the preview-edge handle. Design-system / media / scenario keep their toggle. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): keep fullscreen for media views; adapt Home e2e to the gallery flow - PreviewModal: render the stage fullscreen button for custom-stage views too (image/video/audio media players). The header no longer carries a fullscreen control, so this hover icon is their only fullscreen affordance (addresses review feedback). - entry-chrome-flows e2e: the Home Community gallery has no inline Use / Use-with-query buttons, so drive Use through the plugin's detail modal (plain "Use" routes the plugin as the active driver). The starter-query pre-hydration is gone from Home — the live tile preview replaces it — so the project-creation P0 now types the brief before submitting and still asserts the picked plugin is carried as the run driver (pluginId). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(web): remove Saved from Community + make gallery tile a11y-accessible Per product direction, drop the Saved collection from the Community gallery so the minimal tiles aren't paired with an orphaned Saved filter: - Remove the Saved filter chip, the per-card save button, the `saved` facet mode, and the savedPlugins store; delete savedPlugins.ts and the chip / card-save styles. Update unit + e2e specs that drove the save flow. Accessibility (review feedback): the gallery tile was a focusable `role="listitem"` with click/keydown, which announced as a bare list item. Make the tile's title a real `<button>` (the announced "open details" control, and the e2e hook); the article stays a non-interactive listitem with a mouse-only click-through. Also adapt the remaining Home e2e to the redesigned detail modal: the info sidebar opens via the preview-edge handle (header "Plugin info" toggle and the inline "More" share menu were removed), and keep fullscreen for media (custom-stage) views. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(e2e): drive the direct-Use P0 through the gallery detail modal The last Home e2e still clicked the inline `plugins-home-use-<id>` rich-card button, which the gallery tile no longer renders. Open the starter's detail modal and Use it from there; the rest of the flow (active-driver chip, empty prompt, freeform fill, create-project pins the plugin) is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): keep the plugin info sidebar reachable on small screens The plugin detail modal hides the header sidebar toggle and starts the info panel collapsed, leaving the preview-edge handle as the only opener — but that handle is display:none under 760px, so on phones the panel was unreachable (review feedback). Always render the toggle and only hide it on desktop (where the handle works); a max-width:760px rule shows it again so mobile users can open the info panel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): scope Saved removal to the Community gallery, keep it in PluginsView Earlier this PR removed the Saved collection from the shared PluginsHomeSection, which also stripped the save button + Saved chip from the installed Plugins tab (PluginsView, rich layout) and dropped access to existing saved-plugin data (review feedback). Restore the Saved store, facet mode, rich-card save button, and chip, but gate the chip on the rich layout via a new `showSaved` prop. The minimal Community gallery (cardLayout="gallery") has no per-card save affordance, so it hides the chip; PluginsView keeps the full Saved experience. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: qiongyu1999 <2694684348@qq.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
1828bb942d |
[codex] Fix onboarding AMR login cancel (#3912)
* Fix onboarding AMR login cancel * Handle onboarding AMR cancel race |
||
|
|
532ced93f1 | test(e2e): mock streamed agents in main P0 flows (#3877) | ||
|
|
ae58382040 |
test(e2e): stabilize main P0 follow-up alerts (#3844)
* test(e2e): stabilize main P0 follow-up alerts * ci: cover no-browser Playwright failure alerts Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * ci: distinguish fallback CI alert fingerprints Generated-By: looper 0.9.2 (runner=fixer, agent=codex) * test(e2e): tolerate AMR onboarding model defaults |
||
|
|
7231c891f8 |
Allow release-stable preflight dry runs (#3857)
* Allow release stable preflight dry runs * Fix stable dry-run nightly branch validation Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com> |
||
|
|
7a1ad1a438 |
feat(packaged): add launcher payload updates (#3812)
* feat(packaged): add launcher payload runtime * ci: focus launcher payload windows smoke * ci: publish beta mac x64 launcher payload * test(e2e): harden payload updater smoke * fix(pack): inject launch config for installed windows smoke * fix(daemon): allow packaged payload resource roots * fix(updater): relaunch after payload update * test(e2e): refresh windows updater UI status * test(e2e): ensure windows smoke reaches main shell * test(e2e): skip onboarding before windows updater smoke * fix(updater): detach windows payload relaunch helper * test(e2e): run payload smoke without updater dry run * fix(desktop): relaunch windows payload updates on quit * fix(updater): preserve installed payload relaunch target * fix(updater): require launcher target for payload updates Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * test(e2e): align mac x64 artifact mode assertion * test(e2e): canonicalize launcher relaunch root * fix(updater): validate launcher payload config before activation Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * fix(updater): require live launcher target for payload updates Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com> |
||
|
|
8dcf4ff9f4 |
fix(plugins): route picked plugins through their own pipeline and trust local installs (#3743)
* fix(plugins): route picked plugins through their own pipeline and trust local installs
Two related defects prevented an installed plugin from actually driving a
generation when the user picked it:
- HomeView "Use" attached the plugin as background context only (via
requestPluginContextUse), so submit fell back to the hidden od-default
scenario and the plugin's pipeline + SKILL.md/asset context never
applied. Route the picked plugin as the active driver instead
(usePlugin), preserving the use-with-query textarea seed behavior.
- resolvePluginFolder hard-coded trust='restricted' for every install,
ignoring sourceKind. A local scenario plugin could then never obtain the
pipeline:* capability it needs to run its own pipeline. Honor the
documented source-kind policy (local => trusted) via defaultTrustForRecord
and resolveCapabilitiesGranted.
* fix(plugins): preserve draft on use-with-query and update trust/route test coverage
Addresses review feedback on the plugin-use routing + local-trust change:
- use-with-query no longer discards the user's existing draft. routePluginUse
now APPENDS the rendered plugin query to the current prompt (matching the
legacy context-use semantics) before routing the plugin as the active
driver, instead of letting usePlugin replace the whole prompt.
- Update daemon trust coverage for the local-default flip: the installer
test asserts a local install is trusted by default, and the headless
pipeline fixture drops its ephemeral grantCaps to exercise the
stored/default grant path (local trusted => pipeline:* already granted).
- Update web + e2e tests for the new active-driver behavior: picking a
plugin now routes it as the run driver (its own pipeline) rather than
attaching it as background context. Drops two context-only `Use` regression
tests whose scenario no longer exists under active-driver routing.
* test(plugins): stabilize direct-Use e2e timing and cover plugin-use submit
The P0 "direct Use routes the plugin as the active driver" browser test could
race the in-flight apply: it submitted before `/api/plugins/:id/apply`
resolved, so the active snapshot was not yet bound and the create-project
request never fired (waitForRequest timed out). Wait for the apply response
and an enabled submit button before clicking.
Also extend the HomeView prefill unit test to drive the full plain-`use` →
type a draft → submit flow and assert the routed plugin (not od-default)
drives the run, so this path is covered at the unit layer too.
* test(e2e): assert plugin-use submit via the project request, not a run POST
The two P0 plugin-use flows ("direct Use" and "Use with query carries the
prompt") still waited on POST /api/runs after submit. Under active-driver
routing the picked plugin is a scenario pipeline whose run is fired from the
bound snapshot when the project page mounts — Home no longer posts a separate
/api/runs — so waitForRequest(isCreateRunRequest) timed out even though the
create-project request (which pins pluginId) succeeded. Assert on the project
request + navigation instead, and drop the now-unused message-listing helper.
* fix(plugins): preserve query template on use-with-query so edits flow into inputs
Routing use-with-query passed the rendered prompt as nextPrompt, which made
usePlugin null out active.queryTemplate (nextPrompt-set branch). handlePromptChange
then stopped extracting edited {{...}} values back into active.inputs, so a user
who edited the hydrated query before submit would send the stale default inputs
and the applied snapshot would disagree with the visible prompt.
routePluginUse now passes an explicit queryTemplate aligned with the combined
prompt (untouched draft prefix + raw placeholder-bearing plugin query), so
extraction keeps working. Adds a prefill test that edits a hydrated
use-with-query prompt and asserts the edited value reaches the submitted
pluginInputs.
Also stabilizes the two P0 plugin-use e2e flows: they asserted live navigation
after submit, but the real e2e daemon has no mocked plugin installed so the
live create-project call cannot complete. Assert on the create-project request
payload (which pins the routed pluginId) instead, and drop the now-unused
project-context/message helpers.
* fix(plugins): extract use-with-query inputs independent of the mutable draft prefix
The previous fix baked the user's draft prefix into the query template, so
extractPluginInputsFromPrompt anchored the whole prompt and editing that prefix
made extraction return null — a later placeholder edit then never reached
pluginInputs and the snapshot refreshed from stale defaults.
The template now carries the plugin query segment only. usePlugin/active gain a
queryTemplateAllowsPrefix flag (set by the use-with-query route when a draft
prefix exists) that tells extractPluginInputsFromPrompt to match the query as a
suffix after any leading text. Editing the draft prefix no longer breaks
placeholder extraction.
Adds a regression: existing draft -> use-with-query -> edit both the draft
prefix and a hydrated placeholder -> submit asserts pluginInputs reflects the
edited placeholder.
---------
Co-authored-by: qiongyu1999 <2694684348@qq.com>
|
||
|
|
0582749df5 |
Refactor beta release workflows (#3741)
* Refactor beta release workflows * Fix beta workflow runner bootstrap * Fix self-hosted beta release bootstrap * Use pnpm cmd in self-hosted beta Windows bootstrap * Pass mac notarization profile to beta builds * Allow direct Apple notarization credentials * Fix beta Windows asset handoff * Skip Windows report zip in beta publish * Fix beta metadata workflow cleanup * Stabilize self-hosted beta metadata checkout * Retry self-hosted beta manifest downloads * Use release storage for self-hosted manifests * Isolate self-hosted beta metadata scripts * Add Windows pack phase diagnostics * Disable beta self-hosted Windows security checks * Remove beta Windows security preflight * Add release-beta-s version reservation * Fix beta daily workflow caller inputs Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * Guard beta latest publish and build-only runs Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * Tighten beta latest publish guards * Fix beta publish artifact suffix handling Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * Fix beta metadata suffix and Windows publish target handling * Fix self-hosted beta release ref and publish guards Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * Fix beta release commit identity wiring Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * Fix hosted beta checkout pinning Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com> |