Commit Graph
1874 Commits
Author SHA1 Message Date
Wesley Liddick 8869775ed3 Merge pull request #5636 from feitianbubu/fix/proxy-status-expired-i18n-key
fix(i18n): add missing expired key to account status block used by proxy list
2026-08-18 10:06:56 +08:00
Wesley Liddick f66a42c40e Merge pull request #5697 from feitianbubu/fix/ops-error-distribution-legend-labels
fix(admin): show category labels in ops error distribution legend
2026-08-18 10:05:39 +08:00
shaw 6bf335965a merge main 并修复与 #5730 的语义冲突
main 侧 #5730 新增的 openai_gateway_cn_fixes_test.go 按旧 11 参签名调用
calculateOpenAIRecordUsageCost;本分支为该函数新增了第 12 个参数
pricingAt。文本无冲突但 test build 会失败,此处按本分支对同类测试
调用点的既有处理方式补传 time.Time{}。
2026-08-17 22:27:22 +08:00
lyen1688 9f24a55305 功能:支持渠道模型分时倍率定价 2026-08-17 19:45:07 +08:00
shaw c38c5beef8 fix(i18n): CN 余额单元格误引 grokBalance 键致渲染原始 key
CNProviderBalanceCell 无快照占位标签引用 admin.accounts.grokBalance,
但该键实际嵌套在 admin.accounts.usageWindow 下,未命中时 DeepSeek/Kimi
payg 账号的用量窗口列直接显示原始键名。

- cnProviders 块新增自有占位键 balance(zh: '余额 --' / en: 'Balance --'),
  单元格改引该键
- 用 esbuild 实际加载模块对 zh/en 全部 admin 语言包做键路径深度比对:
  除本处外 CN 相关键(静态 14 个 + 动态拼接 accountMode/apiProtocol 系列)
  双语全部对齐;唯一存量漂移是 claudeMaxSimulation 块(zh 嵌套于
  modelRouting 下/en 为 groups 直属),全源码零消费方属死键,不在本次
  范围内处理
2026-08-17 17:44:33 +08:00
shaw 7cdca9e495 feat(groups): 放行 kimi/zhipu/deepseek 平台分组创建入口
PR #5666 引入 CN 平台后,路由/调度/前端类型均已支持 CN 平台分组,但分组
创建入口两头缺失:后端 Create/UpdateGroupRequest 的 platform oneof 白名单
与前端 GroupsView 平台选项都没有三平台,导致 CN 账号「无可用分组」、整条
流量链路不通(composite 不能作为替代:CN 不可为 composite 路由目标)。

- group_handler.go: 两处 oneof 加 kimi/zhipu/deepseek;composite 路由目标
  白名单有意不动(DetectModelPlatform/isConcreteRequestPlatform 均无 CN 分支)
- GroupsView: platformOptions/platformFilterOptions 补三项;两处徽章配色链
  按 platformColors.ts 色系补 CN 分支
- i18n: admin.groups.platforms 补 kimi/zhipu/deepseek 键(zh/en),缺键时
  分组徽章/GroupRPM/RateMultipliers 弹窗/ChannelsView 会渲染原始 key
- GroupBadge: badgeClass/labelClass 补 CN 配色
- 新增表驱动测试:9 平台 Create/Update 全放行、非法值(别名/大小写/空格)
  全拒绝、composite target 对 CN 保持拒绝的守卫
2026-08-17 17:28:51 +08:00
Wesley Liddick e330c243a8 Merge pull request #5666 from Randark-JMT/feat/cn-providers-kimi-zhipu-deepseek
feat: 国产供应商多协议支持(Kimi/Zhipu/DeepSeek 原生 Anthropic 直通 + DeepSeek Responses)与配额/余额监控
2026-08-17 14:55:20 +08:00
InCerryGit 22fc0cdbf5 fix(frontend): clarify OpenAI Fast/Flex policy rules 2026-08-16 23:49:21 +08:00
feitianbubu cb7841d85c fix(i18n): add missing expired key to account status block used by proxy list 2026-08-16 18:48:49 +08:00
feitianbubu e8ff2017c0 fix(admin): show category labels in ops error distribution legend 2026-08-16 18:04:52 +08:00
Randark 901a0439f1 feat: 国产供应商一等支持(Kimi/Zhipu/DeepSeek 多协议 + 配额/余额监控)
后端:
- 协议凭证维度 credentials[api_protocol] ∈ chat_completions(默认)/anthropic/responses(deepseek)
- /v1/messages 零转换直通原生 Anthropic 端点(kimi/zhipu/deepseek),CC/Responses
  入站交叉组合走 apicompat 双向转换链(responses/chat_completions anthropic-native 转发器)
- count_tokens:anthropic 协议透传原生端点;其余 CN 协议本地 tiktoken 估算
- Coding Plan 额度探测(5h/weekly 滚动窗口)+ payg 余额探测(kimi/deepseek),
  deepseek 双币种 CNY+USD 明细,任一币种达标不停调
- 周期任务 [CNBalance] 并发探测 + 预算随工作量放大;响应式 429 冷却到最早窗口
  重置点;余额不足可恢复临时停调;智谱 CREDIT_LIMIT 不污染窗口解析
- CC→anthropic 流式客户端断开后继续排水上游保住 usage 计量

前端:
- 创建/编辑弹窗 account_mode + api_protocol + base_url 联动预设(含 watcher 竞态防护)
- 用量单元格:kimi/zhipu coding 显示 5h/weekly 窗口,kimi/deepseek payg 显示余额,
  多币种并列展示;探测失败保留快照;挂载自动探测 5min 去抖
- 调度阈值设置面板补 kimi/zhipu 平台(对齐后端 AllowedSchedulingThresholdPlatforms)
2026-08-15 10:37:51 +00:00
shaw fce41e318f fix(openai): make Codex fingerprint convergence opt-in and cover passthrough
Default codex_fingerprint_mode to off. v0.1.175 treated a missing key as
"session", so upgrading silently rewrote installation/session/thread/turn/
window identifiers for every existing OAuth account that had never configured
this field. The quota regressions in #5555, #5556 and #5582 line up with that
version boundary, with A/B reports that rolling back to v0.1.173 restores
quota. Convergence is now explicit opt-in (#5610).

Only accounts that never set the field change behaviour; explicit off /
device / session / full keep working exactly as configured. That required
flipping the persistence condition in all three account modals from
"!== 'session'" to "!== 'off'": the old rule deleted the key when it equalled
the default, which after the flip would have silently discarded an
administrator's explicit opt-in to session.

Also extend convergence to the passthrough path, which previously left client
identifiers untouched:

- resolve the ids once in forwardOpenAIPassthrough and rewrite
  client_metadata on the raw bytes (gjson extract + sjson splice) because
  passthrough is a hot path that must not fully unmarshal multi-MB bodies;
  a shared core keeps the raw and map variants from drifting
- both request builders apply the staged ids at the same relative position
  (after session isolation, before identity enforcement) so headers and body
  share one id set and turn_id stays consistent
- stage the ids unconditionally, including nil: a failover from a converged
  account to an off account must not leave the previous account's ids behind
2026-08-15 16:35:26 +08:00
lyen1688 89d826be29 修复:解决分组用量 PR 的 CI 失败
恢复分组时区测试进入前的全局时区,避免污染高峰计费和支付租约测试。同步升级 Go 1.26.6 与 nanoid 3.3.18,清除后端和前端安全门禁。
2026-08-14 23:25:31 +08:00
lyen1688 cb7b03795d feat: 优化分组用量统计 2026-08-14 22:34:43 +08:00
IanShaw027 e215c98c2c fix: 账号页自动刷新偏好改为模块初始化时恢复
onMounted 再读一次会覆盖已在 setup 阶段恢复的偏好。
2026-08-13 09:22:41 +08:00
IanShaw027 0ae151a238 fix: 徽章改读 grok_usage_snapshot,增量刷新比较 Grok 快照
后端写入 grok_usage_snapshot,列表却读无 writer 的 grok_quota_snapshot;
增量刷新不比 Grok 快照,档位更新后行不替换。

- 正式快照优先 usage,quota 仅兜底;计划字段只收非空字符串
- buildGrokUsageRefreshKey 接入自动刷新
- 注明网关 Extra 写入依赖每请求独立 Account 副本
2026-08-13 08:38:10 +08:00
IanShaw027 b830bc14d6 fix: 长上下文默认保持开启,并与 OpenAI 账号开关取交集
迁移默认 false 会让存量分组静默丢掉 ≥200k 阶梯与渠道多档价。
OpenAI 路径传入 Group 后,账号级 openai_long_context_billing_enabled 被顶掉。

- 列默认 TRUE,并对存量行回填
- 分组价卡不再手填 token 区间,勾选走官方/预设阶梯
- 分组开关与账号开关 AND;价卡 JSON 损坏时打 warn
2026-08-13 08:38:10 +08:00
IanShaw027 363cc4994b fix: SuperGrokPro 用 4.5 窗口区分 Heavy,容量抖动只封单模型
JWT 的 SuperGrokPro 同时覆盖 SuperGrok 与 Heavy,账单月额度又滞后,
账号会误升/误降。multi-agent 容量抖动还会把整号提出调度。

- CanonicalGrokPlan:明确 JWT 优先;模糊档仅采新鲜的 grok-4.5 Responses 窗口
- 配额快照写入 plan_from_45_responses 时间戳,过期信号不用
- engine_overloaded 对 multi-agent 只封当前模型 0.5s–5min
2026-08-13 07:49:14 +08:00
IanShaw027 f3d9491071 feat: 分组支持逐模型定价,并可关闭长上下文阶梯
运营需要按分组覆盖渠道/内置价,且部分套餐不应自动吃 200k 倍率。
原先只能改渠道价卡,分组侧只剩 Voice 三列。

- groups 新增 model_pricing / long_context_pricing_enabled,解析链改为 Group → Channel → 内置
- 关闭长上下文时 token 模型只取最低档;video 按秒计费可写进同一价卡
- 回退价对齐官方卡:4.5 缓存 $0.30、4.3/imagine/audio/search 默认值一并校正
2026-08-13 07:49:08 +08:00
IanShaw027 69648476d4 fix: 账号徽章与用量格按实时档位展示,避免账单滞后误判
订阅失效刷新后凭证已是 free,但残留的 monthly_limit / usage_percent
仍会把用量格锁在付费 7d/30d,徽章也优先信滞后的 billing.plan。

- 凭证 subscription_tier 优先于账单/配额快照
- 用量格先看实时档位,再回退账单指标;Lite 仍走付费条
- 徽章补齐 SuperGrok Lite / Plus / X Basic
2026-08-13 01:23:54 +08:00
IanShaw027 a04ce49016 feat: 新增 grok-4.6 目录、官方定价与请求路径支持
官方目录价:<200k 为 $2 / 缓存读取 $0.50 / $6,≥200k 全部 2 倍。
原先没有独立价卡,/models 宣称可配 reasoning 但请求路径会剥掉 effort。

- 目录与别名接入 grok-4.6 / grok-4.6-latest,默认文本模型仍为 grok-4.5
- 独立回退价卡含缓存读取价与 200k 长上下文倍率
- 保留 reasoning_effort;Chat→Responses 的 cache/vision 桥接同样识别 4.6
2026-08-13 01:23:45 +08:00
shaw c0ab3a00ea feat: Codex OAuth 设备指纹收敛,减少上游可见的设备数和会话数
多人共享同一 OAuth 账号时,各用户 Codex 客户端携带各自不同的 installation_id/session_id/thread_id,
上游据此判定设备数和会话数并限制配额。本功能将这些标识改写为账号级恒定值。

四档策略(账号级 extra 字段 codex_fingerprint_mode):
- off: 不做任何收敛,原样透传
- device: 仅收敛 installation_id
- session(默认): 收敛 installation_id + session_id,thread_id 按客户端原始 session 派生
- full: 收敛所有标识(installation_id + session_id + thread_id)

改写覆盖 6 个指纹载体:x-codex-turn-metadata 头(JSON 内部字段)、x-codex-window-id、
x-codex-installation-id、x-client-request-id、session-id/session_id/thread-id、
请求体 client_metadata。头和体共享同一份预计算 IDs 确保 turn_id 等随机字段一致。
2026-08-12 17:57:50 +08:00
Wesley Liddick 4ec9ceec4a Merge pull request #5508 from pcmid/fix/show-security-audit-menu-in-simple-mode
fix(frontend): show security audit menu in simple mode
2026-08-12 10:01:20 +08:00
Wesley Liddick 177bf30867 Merge pull request #5527 from creamtea47/codex/ops-memory-capacity-display
fix: 优化运营监控内存容量显示
2026-08-12 09:57:45 +08:00
feitianbubu 670b03f7e7 fix(i18n): move account scheduling threshold keys out of status block 2026-08-12 00:10:34 +08:00
NellPoi 943f09d357 fix: 优化运营监控内存容量显示 2026-08-11 17:34:58 +08:00
Wesley Liddick bc0a6a7039 Merge pull request #5480 from scp-planet/fix/admin-usage-request-id-column
修复管理端使用记录请求 ID 列显示 / Restore admin usage request ID column visibility
2026-08-11 14:00:07 +08:00
pcmid 0d7b6ae64c fix(frontend): show security audit menu in simple mode
The security audit group (Risk Control + Prompt Audit) was hidden from
the sidebar via `hideInSimpleMode`, but nothing else in the stack
restricts it in simple mode:

- `router/index.ts` simple-mode `restrictedPaths` does not cover
  `/admin/risk-control` or `/admin/prompt-audit`
- the `/risk-control` and `/prompt-audit` admin route groups have no
  `RunMode` gate, and neither does `internal/securityaudit/` nor
  `service/content_moderation.go`
- `SettingsView.vue` renders the risk control toggle together with a
  `<router-link to="/admin/risk-control">` shortcut, and the settings
  page stays visible in simple mode

The feature is therefore fully usable in simple mode and already
reachable through the settings page — only the sidebar entry was
missing. Drop the flag so the menu matches actual behaviour.

The group remains gated by `risk_control_enabled` (opt-in, default
false) through `featureFlag: flagRiskControl`.
2026-08-11 11:27:49 +08:00
shaw 33351c7bc7 fix(billing): gofmt channel.go and drop the redundant response-model hint
- channel.go: 常量块里插入注释后 gofmt 会把 BillingModelSourceResponse 单独成组,
  原写法沿用了上一组的对齐空格,CI 的 gofmt 检查因此失败
  (internal/service/channel.go:45: File is not properly formatted)。
- 撤掉渠道表单里新加的那条提示:说明本就多余,且"只降不升"只在"相对基线收费"
  这个口径下成立,容易被读成"上游返回更贵的模型也不会多收",反而误导。
2026-08-10 18:45:16 +08:00
shaw b689e5b401 fix(billing): harden response-model billing and repair its test fixtures
按上游响应模型计费的准入过宽、且自带用例必然失败,本次一并修复。

严格化准入
- 新增 PricingService.GetIdentifiedModelPricing / BillingService.HasIdentifiedTokenPricing:
  只接受价格表中能被确定性识别的条目(精确名、已知拼写变体、去掉日期版本后缀),
  不再接受 getFallbackPricing / matchByModelFamily 按子串猜出的系列兜底价。
  此前上游只要自报一个含 "haiku" 的编造名字就能被判定"已定价",把账单压到最便宜的
  系列价(实测 claude-opus-4.8 基线 $0.0019250 → $0.0000963,20 倍少收)。
  GetModelPricing 的对外行为不变,仅把前三步查找抽成共用函数。
- 图片 / 视频 / 网页搜索请求不再走响应模型覆盖:这些路径按张、按秒、按次定价,
  与准入检查所验的 token 价不是同一套价格表。
- 准入判断抽成 responseModelBillingDeclaration,两条计费主干共用同一套规则。

正确性与可观测性
- 去掉 recordUsageCore 中 billingModel 的无效赋值(ineffassign 已启用,会让
  golangci-lint 直接失败),改由日志表达实际生效的计费基准。
- 补 cost != nil 守卫,与 OpenAI 侧及本文件既有写法对齐。
- 每次实际生效的基准切换记一条 billing.response_model_applied,少收可审计。
- 修正 upstreamResponseModelObserver 上"冲突仅用于诊断、永不影响计费"的过期注释。

测试
- gpt-5.1 与 gpt-5.5 实际共用同一条 gpt-5.4 价格,夹具"价格必须不同"的前置断言
  必然失败,OpenAI 侧 3 个用例(含 4 个子用例)从未跑通;改用 gpt-5.4-nano /
  gpt-5.5。Anthropic 侧 claude-opus-4 不是价格表精确条目,改用 claude-opus-4.8。
- 夹具增加"必须可被确定性识别"的前置断言,避免用例被更靠前的门挡掉而失去判别力。
- 新增:准入规则表驱动用例、可识别性判定用例、编造家族名在两条主干上均被拒的用例。

前端
- 选择该模式时提示"计费基准以上游自报模型为准,只降不升,仅对可信上游启用"。
2026-08-10 18:45:15 +08:00
pigzwy 9096492b55 feat(billing): support safe upstream response model billing 2026-08-10 18:45:14 +08:00
scp-planet 5350b3d98e fix(usage): restore request ID column visibility 2026-08-10 10:54:39 +08:00
Wesley Liddick 5deeb7ef15 Merge pull request #5376 from wucm667/fix/issue-5369-composite-image-permission
fix(admin): enable image generation permission for Composite groups
2026-08-10 10:51:54 +08:00
lyen1688 bbc8b6e906 完善大文件备份分卷上传与恢复 2026-08-09 20:58:07 +08:00
shaw 563a72ca73 feat: add default-off switch for email domain registration quota
PR #5423 relaxed the email suffix whitelist: once a whitelist is
configured, non-whitelisted registrable domains are each allowed to
register one account. That behavior activated unconditionally.

Add registration_email_domain_quota_enabled (default false) to gate it:

- Off (default): restore pre-#5423 strict whitelist semantics — with a
  non-empty whitelist, non-whitelisted domains are rejected with
  EMAIL_SUFFIX_NOT_ALLOWED; the register/verify views restore the
  client-side whitelist pre-check and allowed-domain hint.
- On: keep #5423 behavior — one account per non-whitelisted registrable
  domain (EMAIL_DOMAIN_REGISTRATION_LIMIT).
- Empty whitelist keeps allowing all domains in both states.

Gating lives in validateRegistrationEmailQuota and (as a race-safety
backstop) createUserWithRegistrationEmailGuard; the repository-level
domain lock + in-tx recheck is unchanged. The admin update field is
*bool (omitted = keep current) so stale full-payload saves cannot
silently flip the switch. Email binding and OAuth auto-signup keep
their strict policy, and pending-OAuth bind-login for existing
accounts is unaffected because the handler resolves existing emails
before the quota check.

Frontend adds the toggle to admin settings (zh/en copy; whitelist hint
restored to strict wording, quota wording moved to the new toggle) and
exposes the flag via public settings + SSR injection payload.

Tests: #5423 quota tests now enable the switch explicitly; new
default-off regression tests cover register/send-code/async/pending
OAuth/OIDC create-account plus both register views; API contract JSON
and the injection drift guard are updated.
2026-08-09 15:53:40 +08:00
Wesley Liddick f2da30bcd9 Merge pull request #5423 from lyen1688/feat/email-domain-registration-quota
完善邮箱域名注册额度策略
2026-08-09 15:16:26 +08:00
shaw d92edc01be Merge origin/main into feat/channel-monitor-v2-ops-ui
Resolves three conflicts, all of the "both branches appended to the same
block" shape. Every one is resolved as a union of both sides; nothing from
either parent is dropped.

- handler/admin/setting_handler_update.go: keep ChannelMonitorHideThroughput
  (V2) alongside GrokDefaultTextModel / GrokCrossClientModelMapEnabled /
  GrokDefaultBaseURLMode (#5408). UpdateSettings writes every key on each
  save, so dropping either side would reset those settings to zero values.
- service/domain_constants.go: keep SettingKeyChannelMonitorHideThroughput
  and the three SettingKeyGrok* constants.
- repository/migrations_runner.go: keep the 195 checksum rule (V2) and the
  218/219/220 rules (#5408).
2026-08-09 12:11:35 +08:00
lyen1688 4999231d61 修复邮箱域名注册额度策略 2026-08-08 21:05:20 +08:00
IanShaw027 04d9eeaf07 fix(channel-monitor-v2): clear CI lint and align trend axis with range zoom
Fix golangci unused/gofmt on the gentle-backfill path. Plot matrix and
line-chart X axes on the selected [requested_start, requested_end)
window (empty slots while backfill lags), and let plain mouse-wheel zoom
narrow the visible interval so pulse blocks grow wider.
2026-08-08 14:46:35 +08:00
IanShaw027 825f9c78d5 fix(channel-monitor-v2): default mode v1 and gentle adaptive backfill
Default channel_monitor_mode to v1 (opt-in V2) so upgrades keep active
probes; existing explicit v2 rows are left alone via ON CONFLICT DO NOTHING
plus migration checksum compatibility for already-applied 195.

V2 first-enable backfill no longer compresses ticks to 5s or uses 24h
chunks. Each tick does recent overlap plus at most one historical chunk
with depth-based ceilings (2h/4h/6h), adaptive grow/shrink, and failure
backoff. Error request_id dedup is bounded by a 90-minute lookback so
ops_error_logs is not scanned for full history.

Also align hide_throughput parse default with privacy-preserving public
runtime (missing key → true).
2026-08-08 13:59:11 +08:00
IanShaw027 a4faa015a7 fix(deps): bump nanoid 3.3.16 -> 3.3.17 for GHSA-2v37-7h3g-55p8
Match upstream lockfile pin so frontend-security audit gate passes.
2026-08-08 12:50:53 +08:00
IanShaw027 1f58e25ab3 Merge upstream/main into feat/grok-complete-integration
冲突集中在 chat completions / messages 两条 Responses 转发路径:
upstream 给 OpenAIForwardResult 增加了 UpstreamResponseModel 与
UpstreamResponseModelConflict(配套 beginUpstreamResponseModelObservation
观测器),本分支在同样位置把返回值改成了具名变量以便挂 Grok 原生搜索计数。
两侧不互斥,合并结果同时保留上游的响应模型观测字段与 Grok SearchCount 逻辑。

frontend/pnpm-lock.yaml 取 upstream 版本:package.json 与 upstream 完全一致,
本地差异只是 pnpm install 的重解析噪音。
2026-08-08 11:12:56 +08:00
shaw 8ad0a5ff52 fix(deps): bump nanoid 3.3.16 -> 3.3.17 to clear GHSA-2v37-7h3g-55p8 audit gate 2026-08-08 10:48:42 +08:00
IanShaw027 b7112d596f fix(keys): grok-4.5 上下文窗口按 500k 对齐并修正账号测试 i18n mock
- UseKeyModal 中 grok-4.5 的 context_window / model_context_window /
  OpenCode 模型目录统一改为 500000,与 xAI 实际上下文一致
- UseKeyModal.spec 的 OpenCode 目录断言同步为 500000
- AccountTestModal.spec 补齐 imagePreviewAlt 的 i18n mock,
  跟上组件把 alt 文案迁到 i18n 之后的行为
2026-08-08 10:40:40 +08:00
IanShaw027 b717ed9d0d feat(keys): complete Grok Build sample with endpoints/auth/session/features
Expand Use Key Grok CLI config.toml to include production-oriented sections
from working gateway setups: full [endpoints], preferred_method=api_key,
image_description, auto_compact threshold, and Imagine image/video feature
overrides with guided comments.
2026-08-08 10:33:45 +08:00
IanShaw027 f3bac4619e feat(keys): expand Grok client samples and tune free soft-gate default
Ship Use Key templates that match Grok Build / Codex best practice: env
vars + multi-model config.toml with api_backend=responses, env_key over
hardcoded secrets, and clearer shell/path guidance for Claude/Codex/OpenCode.

Also set free_quota_token_limit default to 500k (24h soft-gate), clean up
personal-dev-only comments, and keep billing test fixtures aligned.
2026-08-08 10:26:16 +08:00
IanShaw027 2e857b20b8 chore(grok): 从 PR 中移除进度文档与 lockfile 噪音
- 删除 CHANNEL_MONITOR_V2_DESIGN.md(属于其它分支的设计草稿)
- 删除 backend/docs/GROK_INTEGRATION_PROGRESS.md(开发期进度记录,不属于产物)
- 还原 frontend/pnpm-lock.yaml 至 upstream/main(package.json 无变化,
  差异全部来自本地 pnpm install 重解析)
2026-08-08 10:00:56 +08:00
IanShaw027 b7863650ec fix(usage): prefer explicit video billing mode over image_count
Reuse shared getDisplayBillingMode so user usage rows with billing_mode=video
are not mislabeled as image when image_count is non-zero.
2026-08-08 09:45:12 +08:00
IanShaw027 bdeb13021a fix(admin): i18n account-test media uploads and shared file pickers
Replace native file-input labels with translated choose-file buttons, localize
upload errors and previews, and fix ImageUpload defaults for zh/en.
2026-08-08 09:45:12 +08:00
IanShaw027 85fb776151 test(frontend): mock getLiveCapability and align rollback timeout
Stub GroupsView live capability API in unit tests and expect the longer
system rollback request timeout; refresh pnpm-lock after dependency resolve.
2026-08-08 08:48:38 +08:00