mirror of
https://github.com/nexu-io/open-design.git
synced 2026-07-03 12:27:55 +08:00
* feat: show AMR wallet balance * fix: preserve AMR wallet reauth state * chore: retrigger PR validation * fix: bound AMR wallet balance fetch * chore: retrigger wallet validation * chore: bump bundled Vela CLI to 0.0.18 * chore: retrigger Vela CLI validation * chore(nix): refresh pnpm deps hash * feat(web): reposition AMR as Open Design's cloud subscription (#4684) * feat(web): reposition AMR as Open Design's cloud subscription Fold the standalone "AMR" product into Open Design's own cloud service: unify all user-facing copy, surface the signed-in account's plan + wallet balance, and add upgrade CTAs. - Copy: user-facing "AMR" / "Open Design AMR" -> "Open Design" across 19 locales, agent labels, and daemon error strings (balance/recharge wording preserved). - Account: daemon reads plan + balance via `vela billing summary` (CLI route, control-key) and injects them into the vela status; web shows plan + balance on the settings card, the model-switcher account row, and the runtime-switcher avatar row (balance field aligned with the console wallet's headline balanceUsd). - Upgrade: filled "Upgrade" CTA next to the plan on all three surfaces when the tier is below max; opens the console wallet at ?view=plans. - Runtime-switcher Open Design row restructured to carry account info inline, with a selected-state highlight. - Analytics: new amr_entry elements settings_amr_upgrade / inline_amr_upgrade / avatar_amr_upgrade / avatar_amr_agent_card. - specs/: design doc for the Open Design account/avatar direction. * fix(daemon): surface live account for env-backed auth + isolate cache per credential Address @nettee review on #4684: - applyVelaLiveAccount() now populates plan/balance even when the login status has user:null (VELA_RUNTIME_KEY / VELA_LINK_URL env auth), so env-backed Open Design sessions no longer drop the fetched billing data. - Key the live-account cache by the full credential revision (auth source + profile + userId + config mtime), not just profile, and clear it on logout — a logout / account switch can no longer surface the previous account's plan or wallet balance before the background refresh runs. - Regression tests for both in tests/integrations/vela.test.ts. Sync tests to the AMR -> Open Design copy: - web: tests/providers/sse.test.ts error-string assertions. - e2e: onboarding / logout / run-failure / login-pill specs + visual fixture. * fix(i18n): drop duplicated "Open Design" in switchBody fallback copy The AMR -> Open Design rename sweep collided with the existing brand mention in chat.amrCard.switchBody, rendering "Open Design official Open Design model service" across 13 locales (zh-TW, ja, ko, ar, es-ES, hu, id, fa, pl, tr, ru, pt-BR, uk). Remove the redundant second mention so the retry/switch card reads cleanly. Flagged by @nettee on #4684. Also start aligning InlineModelSwitcher unit tests to the new copy (agent display name AMR -> Open Design, compact error string). * fix(amr): resolve live billing before first /status; hide Upgrade until plan known Address @nettee review on #4684 (two correctness issues in the new plan/balance path): - Cold cache: the signed-in /status handler now BLOCKS the first response on fetchVelaBillingSummary() when the cache is empty, instead of returning config-only and refreshing in the background. The new account surfaces read /status once and never re-poll, so the old flow left plan/balance hidden until the user refocused. Warm cache keeps the non-blocking fast path. fake-vela gains a `billing summary` handler and vela.routes.test.ts covers the cold-cache-first-open case. - Upgrade CTA: canUpgradeVelaPlan() now treats an unknown/empty plan as NOT upgradeable, so a signed-in session whose live summary hasn't resolved no longer flashes Upgrade at top-tier users. Unit-tested. * style(amr): bold the plan/balance text in the switcher + avatar account rows The settings card already renders both bold (the plan value reuses .agent-card-amr-balance-value); align the inline switcher account row and the runtime-switcher avatar row so plan + balance read with the same emphasis everywhere. * fix(amr): single-flight cold billing fetch + surface plan/balance on its own field Address @nettee follow-up review on #4684: - Race: the cold-cache decision keyed off the refresh throttle, so a second /status arriving during the first billing fetch saw refreshAccount=false, fell through, and returned config-only — which the read-once surfaces can't recover from. Now `peekVelaLiveAccount(key) === null` is the cold signal and the billing fetch is single-flighted per credential revision: concurrent cold callers await the same in-flight promise. setVelaLiveAccount stamps the fetch time so the warm path doesn't immediately re-refresh. - Identity: applyVelaLiveAccount no longer fabricates a `{ id: '', email: '' }` user for env-backed sessions. The live billing projection now rides on a new VelaLoginStatus.account field, so `user` stays null (preserving the analytics `user.id` null signal) and plan/balance are surfaced uniformly. SettingsDialog / InlineModelSwitcher / AvatarMenu read status.account.{plan,balanceUsd}. Regression coverage updated in vela.test.ts (applyVelaLiveAccount) and vela.routes.test.ts (cold-cache first open now asserts body.account). * style(amr): match the switcher plan text color to the balance The inline switcher account row showed the balance in --text-strong but the plan in --text-muted, so "$247.51 Plus" read with two different weights of grey. Use --text-strong for the plan too so balance + plan sit at the same emphasis. * fix(amr): treat tier-less billing summary as free; register new entry sources Address @nettee review on #4684: - Free vs unknown: fetchVelaBillingSummary() returned plan:undefined when `membershipTier` was absent, but that field is omitted for free accounts. The new surfaces read status.account.plan for both display and canUpgradeVelaPlan, so a successful free-account read rendered as "unknown" — plan hidden and the Upgrade CTA suppressed for the exact users who should see it. A successful summary without a tier now normalizes to the explicit 'free' sentinel; "unknown" stays signalled by a null account (failed fetch). Regression in vela.routes.test.ts (balance, no tier → account.plan === 'free'). - Analytics: the four entry sources this PR adds (settings_amr_upgrade, inline_amr_upgrade, avatar_amr_upgrade, avatar_amr_agent_card) were in the source→page map but not in the AMR_ENTRY_SOURCES validator set, so parseAmrEntryAnalyticsPayload rejected them and /analytics-entry 400ed for the new buttons. Added them to the set; parser regression covers all four. * fix(amr): invalidate the env-backed live-account cache on config/account change Address @nettee 11:19 review (the inline comment did not post, but the flagged env-backed live-account cache path has a real leak): readVelaCredentialRevision forced configMtimeMs to null for env-backed auth, so the live-account cache key became `env|profile|1||` with nothing to distinguish accounts. Because the live billing summary is fetched with the config profile's controlKey, a config rewrite (account switch) left an env-backed (VELA_RUNTIME_KEY) session serving the previous account's plan/balance. Keep configMtimeMs for env auth too so a config/account change yields a fresh key. Regression added in vela.test.ts. * fix(amr): fingerprint the configured AMR env in the live-account cache key Address @nettee 11:35 review on #4684: configMtimeMs alone wasn't enough. The AMR env credentials (VELA_RUNTIME_KEY / VELA_LINK_URL) can come from agentCliEnv.amr in app-config, and env-backed sessions report user:null — so switching the Settings-backed credential from account A to B on the same profile, without touching ~/.amr/config.json, left the revision at `env|profile|1||<same-mtime>` and let B reuse A's cached plan/balance. readVelaCredentialRevision now adds a non-secret credentialFingerprint (sha256 of the runtime key + link url, truncated) and velaLiveAccountCacheKey includes it. Regressions: a unit test (env key differs by fingerprint) and a route test that rewrites agentCliEnv.amr's VELA_RUNTIME_KEY without touching the config and asserts the second account does not inherit the first's cached billing. * feat(amr): label + stack balance/plan in the switcher account row; fix its tests UI: the inline switcher Open Design account row rendered "$247.51 Plus" with no labels, so users couldn't tell what the two values were. Balance and plan now stack on two labelled lines ("可用余额 / Available balance" and "当前套餐 / Current plan"), with the Upgrade CTA on the plan line. The settings.amrBalance / settings.amrPlan labels are made descriptive across all 19 locales (the settings card reuses them), so the meaning is explicit everywhere. Tests: rewrite InlineModelSwitcher.test.tsx for the account-row structure — the agent radio now carries status only in its aria-label (icon-only visible), and the sign-in / signing-in / cancel affordances live on the inline-model-switcher-account-action button. Redundant within(amrButton) getByText assertions are dropped (the radio-name query already asserts status); pending/error assertions target the account row. 22/22 green. * test(amr): align AmrLoginPill tests to the Open Design copy Account-status group is labelled 'Open Design account status', the console link is 'Console', and the compact sign-in error reads 'Sign-in failed.' — update the queries to match. 29/29 green. * feat(amr): redesign the account row — tier badge + balance subtitle; short labels Iterated on the Open Design account row in both the inline model switcher and the runtime-switcher (avatar) list so the plan/balance no longer collide: - Plan tier renders as a small neutral pill right after the "Open Design" name (identity + tier read as one group, à la Claude's "name · Max"). - Balance moves to a second line below the name, labelled "余额 $247.51" (small grey label + bold value) so users know what the number is. - Upgrade stays as the trailing action, vertically centred against the two lines. Account logo bumped to 24px to balance the taller row. - Revert the amrBalance / amrPlan labels back to the short "余额 / 套餐" ("Balance" / "Plan") across all 19 locales. * test(amr): align remaining web specs to the Open Design copy + account row Update the rest of the web component specs that still asserted the pre-rename wording / old account-row shape (the `Web workspace tests` red CI @nettee flagged): - EntryShell.onboarding: "Sign in to Open Design Cloud" -> "Sign in to Open Design"; "AMR sign-in failed." -> "Sign-in failed.". - SettingsDialog.execution: AMR card queried as /^Open Design\b/ (was /^Open Design AMR\b/). - HandoffButton: agent label "Open Design"; website link "打开 Open Design 官网". - AvatarMenu: drop the two obsolete avatar console-shortcut specs (the avatar console link was removed when the row was consolidated; the upgrade entry remains covered by the daemon parser + contract). Full web suite green: 3403 passed. * test(amr): cover the avatar-row upgrade CTA (plan/balance + stamped link) Replaces the two removed avatar console-shortcut specs with focused coverage for the new runtime-switcher upgrade path (@nettee): mocks a signed-in /api/integrations/vela/status, opens the menu on the non-prod `test` profile, asserts the rendered plan badge + balance, and verifies the clicked upgrade link carries view=plans and od_entry_source=avatar_amr_upgrade attribution. * test(e2e): update avatar visual spec to the redesigned account row The Playwright visual (settings-workspace) job was red on a functional assertion, not a pixel diff: the spec queried the removed `.avatar-amr-account-link` console entry and 'AMR account' / 'Balance & recharge' copy. Rewrite it to override the signed-out status with a signed-in plan/balance, then assert the Open Design row renders the Plus badge + $247.51 and the upgrade link points at ?view=plans. * chore: re-trigger CI on updated main — needs-validation gate moved to merge_group (#4714) * test: capture Open Design account balance visuals * chore: retrigger workspace validation --------- Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> Co-authored-by: lefarcen <935902669@qq.com> Co-authored-by: a1chzt <chizblank@gmail.com> * [codex] keep AMR wallet balance stable during refresh (#4730) * fix: keep AMR wallet balance visible during refresh * fix: remove AMR wallet refresh hover tooltip * chore: retrigger validation * fix(ci): align AMR wallet branch validation * feat(web): Open Design 云账户入口 UI 优化(名牌/置顶/新 logo) (#4787) * feat(web): polish Open Design cloud account surfaces (plan badge, pin-to-top, new logo) - 模型切换器(InlineModelSwitcher): Open Design 账号卡片上位为可点选入口并置顶, 移除重复的代理行 - 头像菜单(AvatarMenu): Open Design 置顶代码代理列表; 执行模式选中态改为勾选标记(不再与代理选中态争色块) - 统一套餐名牌: 新增共享 PlanBadge 组件(全局 CSS, 跟随主题色), 替换设置页/切换器/头像菜单三处各自实现 - 设置页 CLI 卡片: 删除无用的钱包刷新按钮与"更新于…缓存"行; 余额统一为两位小数 - 全局替换 AMR logo 资产(amr.svg) * test(web): align AgentIcon AMR assertion with new logo fill --------- Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> * fix(web): preserve AMR wallet balance in switcher * fix(amr): avoid stale wallet status on refresh failures * fix(web): align avatar AMR balance row * fix(web): avoid stale AMR wallet snapshots * fix(web): keep avatar AMR console link * fix(amr): support wallet fallback for older vela cli --------- Co-authored-by: michaeltaxman911-hue <michaeltaxman911@gmail.com> Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> Co-authored-by: lefarcen <935902669@qq.com>