Commit Graph

594 Commits

Author SHA1 Message Date
root b939cfa2fa feat(auth): support per-deploy login password key override
Deployment Config CI / Deployment Config (push) Successful in 27s
Backend CI / Backend (push) Successful in 15m4s
Multi-replica deployments need every Pod/container to share one RSA private key, otherwise public keys handed to the browser may not match the key that decrypts the resulting ciphertext. Introduce a `*.local.yaml` override layer that ops-config and tenant-config both load on top of the base config, ship example overrides plus compose/k3s wiring, and tolerate PEM bodies that arrive folded or escaped from Secrets.
2026-05-14 11:54:40 +08:00
root 2bc192b3c7 fix(prompts): refine region output guidance for geographic terms
Deployment Config CI / Deployment Config (push) Successful in 27s
Desktop Client Build / Resolve Build Metadata (push) Successful in 40s
Frontend CI / Frontend (push) Successful in 4m3s
Backend CI / Backend (push) Successful in 16m31s
Desktop Client Build / Build Desktop Client (push) Successful in 26m53s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 53s
2026-05-14 11:16:23 +08:00
root 036377f02e feat(admin-web): add 404 page for unknown routes
Unknown URLs previously rendered a blank page. Add a catch-all route
under AppShell that shows the requested path plus back / workspace
actions, with zh-CN and en-US copy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 11:15:09 +08:00
root 879677516f fix: harden login for MLPS requirements 2026-05-14 11:05:20 +08:00
root ecf3ee1ef0 fix(ci): prune old registry package versions
Deployment Config CI / Deployment Config (push) Successful in 19s
Frontend CI / Frontend (push) Successful in 11m18s
Backend CI / Backend (push) Successful in 17m54s
2026-05-13 23:22:58 +08:00
root b3bd23e238 feat(admin-web): improve responsive admin layout
Frontend CI / Frontend (push) Has been cancelled
2026-05-13 22:29:46 +08:00
root 34ef5873ca feat: load question expansion prompts from yaml
Deployment Config CI / Deployment Config (push) Successful in 27s
Backend CI / Backend (push) Successful in 16m5s
2026-05-13 20:24:51 +08:00
root 8890cd1ca4 style(admin-web): refine edit button hover and card shadow polish
Frontend CI / Frontend (push) Successful in 4m21s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 20:12:36 +08:00
root 887f5b672e chore: update tenant repository generated models
Backend CI / Backend (push) Successful in 17m58s
2026-05-13 19:54:23 +08:00
root 0823e47d46 feat: tighten desktop presence loop and refine admin-web UX
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m46s
Backend CI / Backend (push) Failing after 7m52s
Desktop Client Build / Build Desktop Client (push) Successful in 27m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 59s
- Shrink desktop presence TTL to 30s and heartbeat to 15s so unexpected
  client exits surface within one TTL even if the explicit offline call
  is missed; keep migration default aligned.
- Trust a known presence miss in resolveDesktopClientOnline instead of
  falling back to the recent-heartbeat heuristic, so a still-cached
  LastSeenAt cannot mask an offline client.
- Release the runtime session before clearing renderer desktop sessions
  on shutdown to avoid leaving stale leases behind.
- Auto-refresh the MediaView account list every 5s and revamp card
  layout (inline platform badge, status tags, UID row, meta box).
- Let the brand-question AI wizard accept multiple seed topics via a
  tag-style input; candidates from each topic are merged and deduped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 19:36:24 +08:00
root 18cdbf25f8 fix: harden competitor create and batch kol stats
Backend CI / Backend (push) Failing after 6m48s
2026-05-13 17:31:22 +08:00
root 7aa786fbf4 feat(template-wizard): enhance competitor management and update UI messages
Frontend CI / Frontend (push) Successful in 3m27s
2026-05-13 17:10:31 +08:00
root 1eae6fb6d4 feat(questions): make brand questions the primary monitoring & template axis
Deployment Config CI / Deployment Config (push) Successful in 29s
Frontend CI / Frontend (push) Successful in 4m4s
Backend CI / Backend (push) Failing after 7m12s
- add /questions/combination-fill endpoint with AI-driven, IP-region-aware matrix fill
- extract ip2region resolver from ops/app into shared/ipregion for cross-service use
- thread question_id filter through dashboard composite, citation summary, and collect-now
- switch template wizard from keyword inputs to brand-question selection (primary + supplemental)
- pass brand_question and supplemental_questions through assist/title/outline prompts
- add AiWaitingModal + 45s client timeout and request_timeout error mapping for long AI flows

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 15:59:39 +08:00
root 37b0b32327 feat(admin-brand): add question expansion service and related functionality
- Implemented QuestionExpansionService for generating and materializing questions based on combinations and AI distillation.
- Added question metadata classification logic to infer intent and layer of questions.
- Created API handlers for question expansion operations including combination preview, AI distillation, metadata classification, and materialization.
- Introduced database migrations to support new question-related fields and constraints in brand_questions and brand_keywords tables.
- Added caching mechanism for AI distillation results to improve performance.
- Defined JSON schemas for question distillation responses to ensure data integrity.
2026-05-12 21:53:36 +08:00
root 77d542c282 feat(server): make tenant login guard toggleable via config
Frontend CI / Frontend (push) Successful in 3m38s
Backend CI / Backend (push) Successful in 14m43s
Add auth.login_guard.enabled config (default on) so the tenant login
brute-force / rate-limit guard can be disabled per environment.
Surfaces an AUTH_LOGIN_GUARD_ENABLED env override and a startup warning
when disabled. Wired through Diff() so hot reload picks up changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:32:39 +08:00
root 77f3e5ee99 perf(admin-web): relax template wizard assist poll cadence to 3s
Polling analyze/title/outline task results every 1.2s was over-eager
for AI tasks that typically run 15-30s. Bump interval to 3s and lower
max attempts to 40, extending total timeout from 72s to 120s while
roughly halving request volume.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:32:06 +08:00
root 01fa2b8309 fix quota reset reservation race
Desktop Client Build / Resolve Build Metadata (push) Successful in 28s
Frontend CI / Frontend (push) Successful in 3m57s
Backend CI / Backend (push) Successful in 17m3s
Desktop Client Build / Build Desktop Client (push) Successful in 26m8s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 51s
2026-05-12 02:24:57 +08:00
root 1aad002a3e feat(ops): use 'reset' quota status for plan-usage reset and invalidate quota cache
When ops staff reset a tenant's current-plan usage, the existing
'refunded' terminal status conflated user-initiated refunds with
ops-driven resets, and tenants still saw the old balance in the top-nav
chip until the quota-summary cache TTL expired.

- Introduce a dedicated 'reset' status for quota_reservations, separate
  from 'refunded'. Both the initial and an incremental migration widen
  the CHECK constraint to allow it; the down migration folds 'reset'
  rows back into 'refunded' before tightening the constraint.
- resetQuotaReservations / resetAIPointReservations now write 'reset'
  without touching refunded_amount, and stop cascading into
  ai_point_usage_logs (carried no audit value for ops resets).
- AdminUserService gains an optional cache dependency and calls
  invalidateQuotaSummaryCache(tenant_id) immediately after a successful
  reset so the tenant's top-nav chip refreshes on the next request
  without waiting on TTL.
- Wire the existing appCache into AdminUserService at boot.
- Drop the now-unused ai_point_usage_logs field from the reset response
  and from the ops-web AdminUsersView type.
- Add a unit test covering the cache-key invalidation contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:55:29 +08:00
root 51d32fa96d fix(admin-web): invalidate workspace cache after every AI-points-consuming call
Top-nav quota chip (会员到期 / 生成文章 / AI 点数) only refreshes when its
query is invalidated. Several mutations and stream-based flows that debit
points or article quota on the server were not invalidating it, so users
had to refresh the page to see updated balances.

- TemplateWizardView: invalidate `['workspace']` inside `endAssistTask()`,
  covering analyze / title / outline assist tasks in one place.
- FreeCreateView: invalidate after `articlesApi.create` success.
- GenerateTaskDrawer: add `['workspace']` to the instant-generate
  `Promise.all` alongside the existing `articles` / `instantTasks` keys.
- KolPromptEditor: invalidate in the `finally` of both `runAiAssistStream`
  (generate) and `generateSelectionAiPreview` (optimize) so abort / error
  paths also refresh.
- ArticleEditorCanvas: bring in `useQueryClient` and invalidate in the
  selection-optimize stream `finally`.

Together with the existing invalidations in TemplateWizard.generate,
ImitationGenerate, KolGenerate, and article-regenerate, every quota-
debiting call site now feeds the cache refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:54:12 +08:00
root 793c310560 refactor(desktop-client): harden external-window load flow with loading page and timeout watchdog
- Introduce `navigateRemoteURL` / `showLocalPage` / `showErrorPage` helpers
  that centralize remote navigation, watchdog wiring, and error fallback,
  replacing the ad-hoc logic inside `loadWindowURLSafely`.
- Show a localized loading page (`loadingPageDataURL`) while a remote URL
  is fetching, so the window no longer sits on blank white during slow
  navigations.
- Add a 25s remote-load timeout watchdog that switches the window to the
  error page when the target never finishes loading, plus an active load
  token so stale watchdogs from earlier navigations cannot fire on the
  current attempt.
- Track `localPageKind` and `activeTargetURL` per window so blank-page
  retries, did-fail-load handlers, and ready-for-detection checks behave
  correctly when the window is currently showing a local loading/error
  page.
- Escalate the blank-page watchdog: after the retry attempt, if the page
  is still blank, surface the error page instead of looping silent
  reloads.
- Restyle the error page (drop gradients, use a neutral light/dark token
  palette, single primary retry button) and add a dedicated loading page
  template with the same look.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:31:50 +08:00
root b6cc12cefe feat(admin-web): show centered modal in Chinese when AI points are insufficient
- Add `ai_points_insufficient` / `ai_points_unavailable` Chinese mappings in
  errors.ts so the toast copy is localized.
- Add `showAiPointsInsufficientModal()` helper that renders a centered
  `Modal.confirm` with localized title/body and a "查看点数明细" action that
  routes to `/account/ai-points`. The helper is debounced so concurrent
  failed requests do not stack multiple modals.
- Trigger the modal globally from the admin-web response interceptor when
  the backend returns `ai_points_insufficient`, so every AI-generating
  endpoint surfaces the same prominent prompt without per-callsite changes.
- Drop the English `detail` for ai_points_insufficient in `formatError` so
  the secondary toast stays pure Chinese.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:31:02 +08:00
root 635782041a feat(admin-web): preserve template wizard entry source and refresh AI banner
- Carry `from=workspace` query from the workbench into the wizard so cancel
  and post-generate redirects return to the workbench instead of always
  landing on /articles/templates.
- AppShell now resolves an effective navKey from `route.query.from`, so the
  sidebar highlight and breadcrumb track the entry source while inside the
  wizard.
- Redesign the brand-info AI analyze CTA into a standalone banner with
  template-aware copy (default / product_review / research_report) and add
  the matching i18n keys.
- Drop the unused 批量生成文章 button and its styling from the templates
  page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:12:01 +08:00
root f06c8dfc01 fix(knowledge): always retry source fetch via lightpanda on trigger status
Backend CI / Backend (push) Successful in 15m15s
LinkReader 500 (or other trigger_status) used to be gated by an extra
allowed_domains whitelist on the tenant API side, so URLs like
m.baidu.com/bh/m/detail/... fell straight through to the user with a raw
"webpage parser failed" message. Drop the whitelist gate — enabled +
trigger_status is enough — and surface a friendly Chinese prompt when
both LinkReader and the lightpanda fallback give up. Full error chain
is kept in the logger for debugging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 19:48:21 +08:00
root 83c5cc76d6 feat(bilibili): enhance article submission process and error handling
Desktop Client Build / Resolve Build Metadata (push) Successful in 29s
Frontend CI / Frontend (push) Successful in 5m28s
Desktop Client Build / Build Desktop Client (push) Successful in 26m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 39s
2026-05-11 19:37:14 +08:00
root 18011a7892 fix(admin-web): auto-reload on stale dynamic-import chunks after deploy
Listen for vite:preloadError and router onError, force a one-shot reload
(10s cooldown via sessionStorage) when a hashed lazy-loaded module 404s
because a new deploy replaced it. Eliminates the user-visible "Failed to
fetch dynamically imported module" error on login and route navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:47:51 +08:00
root c16a684add fix(browser-fetch): allow baidu source fallback
Deployment Config CI / Deployment Config (push) Successful in 1m35s
Backend CI / Backend (push) Successful in 17m20s
2026-05-11 14:30:58 +08:00
root 2113bcb601 ci(browser-fetch): include browser-fetch image in build and deploy pipelines
Backend CI / Backend (push) Successful in 14m25s
Add browser-fetch to backend-ci image list, NAS compose/K3s deploy options
and rollout loops, and the offline package bundle so the new service ships
through the same pipelines as the rest of the backend.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:58:48 +08:00
root 3d396e4ac8 fix(docker-compose): update healthcheck command syntax for service
Deployment Config CI / Deployment Config (push) Successful in 12s
2026-05-11 12:37:08 +08:00
root 6b177be6fd chore(browser-fetch): enable lightpanda by default and widen allowlist
Deployment Config CI / Deployment Config (push) Failing after 10s
Desktop Client Build / Resolve Build Metadata (push) Successful in 25s
Frontend CI / Frontend (push) Successful in 3m38s
Backend CI / Backend (push) Successful in 16m45s
Desktop Client Build / Build Desktop Client (push) Successful in 26m27s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 39s
Turn the lightpanda-backed fetch service on, bump worker concurrency to
3, and add baidu.com plus weixin.sogou.com to the allowed domains so the
knowledge URL fallback can resolve those sources without a config edit.
2026-05-11 12:27:13 +08:00
root 8c0fbc8ffa fix(desktop-task): drop LEFT JOIN in lease query so FOR UPDATE locks only desktop_tasks
Postgres rejects FOR UPDATE on the nullable side of a LEFT JOIN, which
made LeaseNextQueuedDesktopTask fail under contention. Replace the join
with a NOT EXISTS subquery, scope the row lock to the dt alias, and add
a regression test plus warn-level logging on lease query failures so
similar issues are easier to diagnose.
2026-05-11 12:26:54 +08:00
root 6fa9a6c052 feat(dongchedi): translate platform "server exception" into actionable copy
Map dongchedi adapter failures (raw "server exception" or
dongchedi_platform_exception) to a Chinese prompt steering the user to
the dongchedi backend, so renderer/admin views and desktop-task error
payloads no longer surface the opaque platform message.
2026-05-11 12:26:38 +08:00
root f34c6f2ceb feat(admin-web): surface generation error message and speed up active polling
Hoists hasActiveGenerationStatus into the shared display helper so all
views agree on what counts as in-flight generation, shows the backend
generation_error_message inline on the imitation list and detail drawer
when status is failed, and drops the workspace/templates/imitation poll
interval from 10s to 3s (with a 5s fallback when streaming is enabled)
plus explicit query-cache invalidation so failed/completed states show
up promptly.
2026-05-11 11:11:40 +08:00
root cbbed4b42c fix(generation): repair articles stuck in generating when latest task is terminal
The state-consistency worker now detects articles still flagged as
generating whose latest generation_task is already failed or completed
(with a version) and aligns the article status to the terminal task,
invalidating article caches on the way out. Adds supporting partial
indexes and switches UpdateGenerationTaskStatus to COALESCE started_at
and completed_at so partial status updates don't wipe the timestamps.
2026-05-11 11:11:31 +08:00
root 7f08d92958 feat(browser-fetch): add lightpanda-backed fetch service and knowledge URL fallback
Adds a new browser-fetch microservice that wraps Lightpanda for rendering
JS-heavy pages, and wires it into the knowledge URL parser as a fallback
when the upstream link reader returns 403/429/5xx for an allow-listed
domain (e.g. zhuanlan.zhihu.com). Includes config/env plumbing, hot-reload
diff support, and full deploy assets (Dockerfile target, docker-compose,
k3s manifests, image-build/package scripts).
2026-05-11 11:11:21 +08:00
Xu Liang 708a45ba16 fix(desktop): skip obfuscation for electron main to preserve page.evaluate
Desktop Client Build / Resolve Build Metadata (push) Successful in 19s
Desktop Client Build / Build Desktop Client (push) Successful in 21m39s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 30s
Playwright serializes page.evaluate callbacks via Function.prototype.toString and runs them in the target page context. Obfuscating the main bundle injected string-array helper references that the browser page could not resolve, surfacing as `ReferenceError: wO is not defined` for bilibili and dongchedi publishes. Mirrors the existing Vite `minify: false` guard for main/preload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 17:46:37 +08:00
Xu Liang 1082e9010e feat(admin-web): add collapsible metadata section with toggle functionality
Frontend CI / Frontend (push) Successful in 4m9s
2026-05-09 09:40:17 +08:00
Xu Liang 8bd2d88d88 fix(qwen): redirect HavanaOne login bridge to qianwen home on success
Desktop Client Build / Resolve Build Metadata (push) Successful in 27s
Desktop Client Build / Build Desktop Client (push) Successful in 23m56s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 51s
Detect the passport.qianwen.com bridge page after a successful SSO login
and navigate the webContents back to the original returnUrl so account
binding can proceed instead of stalling on the bridge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:28:20 +08:00
root 3102e261ae feat(admin-web): use real platform logos in publish queue table
Frontend CI / Frontend (push) Successful in 9m6s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:20:31 +08:00
root 3f8971aa55 chore(desktop): brand dev-time app name as ShengxinPush
Desktop Client Build / Resolve Build Metadata (push) Successful in 1m26s
Desktop Client Build / Build Desktop Client (push) Successful in 33m18s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 44s
setName pins the runtime app name (menu bar, task switcher) and
setAboutPanelOptions overrides the macOS About panel which is sourced
separately from Info.plist when running unpackaged. Packaged builds are
unaffected: electron-builder productName "省心推" still drives the .app
bundle and NSIS installer metadata. The macOS Dock label in dev still
shows "Electron" because that comes from the unpacked Electron.app
bundle's CFBundleName, which is outside Electron's API surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:15:08 +08:00
root b7ba3ba58a feat(desktop): surface baijiahao challenge-required failures with actionable copy
Baijiahao throws baijiahao_challenge_required when its risk control flags
the network environment, but PublishManagementView previously showed the
raw "code: ..., message: ..." string. Route the error through the existing
normalizer pipeline so users see a clear "需要人机验证 + 去后台手动完成
一次发稿" prompt instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:03:00 +08:00
root 8396bdeb48 fix(desktop): disable main/preload minification to keep page.evaluate stable
Desktop Client Build / Resolve Build Metadata (push) Waiting to run
Desktop Client Build / Publish Client Artifacts to NAS (push) Blocked by required conditions
Desktop Client Build / Build Desktop Client (push) Has been cancelled
Playwright serializes the function passed to page.evaluate via .toString()
and runs it in the browser context. With main-process minify on, esbuild
renames inlined helpers (e.g. __name) and closure references to two-letter
identifiers like FK/p/ed; their definitions stay at module scope on the
Node side, so the browser eval throws ReferenceError. Mac dev builds were
unaffected because dev mode doesn't minify; only packaged Windows builds
hit this. Main process bundle size is irrelevant (loaded once on startup)
so turning minify off is the cheapest correct fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:30:43 +08:00
root cb42d4b662 fix(desktop): keep oauth popups alive on redirect aborts and blank loads
Toutiao's wap_login redirect chain raises ERR_ABORTED (-3) without the
literal symbol in the message, so the previous regex fell through to the
fallback error page. Now match the numeric form too, and add a 7s blank-
page watchdog that auto-reloads stuck "Loading..." popups once per fresh
navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:12:28 +08:00
root 0f3a9a977e fix(kimi): keep monitor robust against K2.6 redesign noise
Desktop Client Build / Resolve Build Metadata (push) Has been cancelled
Desktop Client Build / Build Desktop Client (push) Has been cancelled
Desktop Client Build / Publish Client Artifacts to NAS (push) Has been cancelled
Frontend CI / Frontend (push) Successful in 6m6s
K2.6 introduced new UI surfaces that polluted the answer extraction and
the busy-signal probe, breaking monitor runs even though Kimi rendered a
correct answer:

- collectCandidates now drops elements that contain a chat composer child
  (<textarea>, non-hidden <input>, [contenteditable]). This filters
  wrapper containers like .chat-detail-content that the wide
  [class*="content"] fallback would otherwise pick, pulling editor
  placeholder text ("可快捷使用技能", "Kimi K2.6 已就位") into the answer.
- isAuxiliaryPanelElement skips elements with role="dialog" /
  "alertdialog", aria-modal="true", or the <dialog> tag, so the K2.6
  launch-announcement popover ("Kimi K2.6, 已就位 / 一键部署 OpenClaw")
  no longer counts as answer content.
- Drop the class-based loading-indicator probe entirely. The previous
  global [class*="loading"]/"stream"/"typing"/"spinner" sweep matched
  K2.6's always-on text-stream wrapper and held busy=true forever, which
  caused kimi_query_timeout even after the assistant turn had fully
  rendered. The textual busySignalsPattern (思考中/搜索中/生成中…) is
  the actual semantic signal and survives any UI rename.
- Surface a capacityNotice from the assistant turn when Kimi shows its
  short capacity-exhausted message ("算力不够 / 请稍后再试"). The top
  level falls back to it when answerText is empty so the SaaS pipeline
  records the user-visible message instead of an unknown row, with
  capacity_limited / capacity_notice flagged in raw_response_json.

All filters lean on HTML form / ARIA semantics and visible text rather
than Kimi-specific BEM classes, so they survive future redesigns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:51:49 +08:00
root 1e6ed77453 fix(yuanbao): track new hunyuan_t1 SSE protocol and align inline citations with DeepSeek
- findInteractiveByText now also accepts elements carrying business
  attributes [dt-button-id]/[data-button-id]. The new yuanbao toolbar
  renders the deep-think toggle as <div dt-button-id="deep_think"> rather
  than a <button>, so the previous text-only locator missed it and probes
  silently ran in the fast model — without inline citations.
- Lower <div data-idx-list="1,2,10"> placeholders to bare "[1][2][10]"
  (previously "[citation:1] [citation:2] [citation:10]") and accept both
  forms in YUANBAO_CITATION_MARKER_PATTERN. Final answer text runs through
  normalizeCitationMarkers so any residual SSE [citation:N] is rewritten
  to [N], matching DeepSeek's chip rendering on the SaaS side.
- searchGuid frames in the new protocol carry every reference inside
  docs[] (each with a 1-based index that mirrors the answer markers) and
  citations is now always null. Promote docs into the citations bucket so
  citations[index-1] aligns with the inline marker, eliminating the
  spurious yuanbao_incomplete_citations failures.
- Update the SaaS detail view: createYuanbaoCitationPattern accepts both
  "[N]" and "[citation:N]" so yuanbao answers render the same clickable
  superscript chips as DeepSeek.

Tests cover the new searchGuid.docs alignment, fast-cache answers (no
markers, no sources -> still succeed), legacy [citation:N] -> [N]
rewriting, and mixed-format marker extraction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:51:24 +08:00
root af35301d9b test(desktop): cover deepseek account name extraction for wechat + phone logins
Desktop Client Build / Resolve Build Metadata (push) Successful in 28s
Frontend CI / Frontend (push) Successful in 4m5s
Backend CI / Backend (push) Successful in 17m7s
Desktop Client Build / Publish Client Artifacts to NAS (push) Has been cancelled
Desktop Client Build / Build Desktop Client (push) Has been cancelled
Refactor readDeepseekAccountIdentity so the JSON payload parser is a pure
ts function (extractDeepseekIdentityFromPayload). The webContents IIFE now
just polls for userToken and returns the raw API JSON; payload picking lives
in ts and is unit-tested.

Tests lock the contract for both login types we observed in the wild:
  - WeChat-bound account: id_profile.name = '阿白', picture present.
  - Phone-only login: id_profile = null, mobile_number = '177******08',
    email = '' (empty string, not null) — the case that originally regressed.

Plus regressions for the priority order (profile.name > mobile_number > email),
the all-empty fallback, and non-record payloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:02:57 +08:00
root bc8f1c353f fix(desktop): handle deepseek phone-number login in account name extractor
Phone-number logins return id_profile=null, mobile_number="177******08", and
email="" (empty string, not null). The previous fallback used `??`, which only
short-circuits on null/undefined, so an empty email string clobbered the
mobile_number fallback and the displayName ended up null — leaving the
DeepSeek card stuck on the "${label} 会话" placeholder.

Switch to a truthy pickString helper that requires a non-empty trimmed string
before accepting a candidate, and prefer mobile_number over email so the
masked phone number shows up exactly the way DeepSeek's own sidebar renders it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 19:59:58 +08:00
root 34b26e1079 fix(desktop): extract real account name for wenxin/yuanbao/deepseek binding
The generic AI page-state heuristic only catches displayName via DOM patterns
like [class*="user-name"], so wenxin/yuanbao/deepseek (CSS-module hashed
classes or no exposed store) fell back to the placeholder "${label} 会话".

Add per-platform readers under adapters/{wenxin,yuanbao,deepseek}/account-identity.ts:
- wenxin: GET /eb/user/info with BDUSS cookie; fall back to __NEXT_REDUX_STORE__
  and sidebar DOM if the API fails or hasn't responded yet.
- yuanbao: poll the stable BEM .yb-nav__user .nick-info-name + avatar img,
  since yuanbao exposes no user-info API and the sidebar renders late.
- deepseek: poll localStorage for userToken, then call /api/v0/users/current
  with Authorization: Bearer <token>; reads biz_data.id_profile.{name,picture}.

detectWenxin/Yuanbao/DeepSeekPlatform now run the credential-backed detector
first, then override the placeholder displayName/avatar via the per-platform
reader. Existing rows in DB still hold the placeholder until the account is
re-bound — probe does not write back display_name yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 19:54:46 +08:00
root 1fb6d28102 fix(desktop): align AI platform sidebar badge with media-account semantics
The AI 平台 badge counted distinct platforms with at least one
active-auth account, while 媒体账号 counted raw account rows
regardless of auth state. The two numbers shared a slot but meant
different things, which made them not comparable at a glance.

Switch the AI 平台 count to mirror 媒体账号: account-level count
of accounts whose platform falls in the monitoring catalog, with
no authState filter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 19:14:16 +08:00
root 94c6b5d5a5 fix(desktop): stop forcing login window on business API 401
Desktop Client Build / Resolve Build Metadata (push) Successful in 29s
Frontend CI / Frontend (push) Successful in 4m48s
Desktop Client Build / Build Desktop Client (push) Successful in 26m5s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 42s
Business calls (heartbeat, account sync, lease/pull/resume tasks,
preempt monitoring lease) used to short-circuit any 401 into
handleAuthExpired, which tore down the runtime and switched the
window to login. That stole the screen on transient or per-request
auth glitches and conflicted with the renderer-side proactive token
renewal.

Now business 401s fall through to the existing warn/danger activity
log paths and runtime keeps running. The login redirect is owned
solely by the renderer's renewAuthenticatedSession → on refresh /
rotate failure → forceLogoutAfterRenewFailure path. Server-side
revocation via error code 40991 is unaffected.

Removed the now-orphan plumbing: handleAuthExpired,
isApiClientError helper, emitRuntimeAuthExpired /
onRuntimeAuthExpired events, and forceLoginWindowForAuthExpired
listener registration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:55:10 +08:00
root e54efdacee fix(knowledge): enforce upload type and size limits on client
Why: 添加知识库弹窗只在 hint 文案里写了「docx/pdf/txt/md/xls/xlsx,<=30M」,
beforeUpload 没做校验,用户可以提交任意大小、任意格式的文件后再被后端拒绝。
现在前端按白名单扩展名 + 30MB 阈值拦截,并给 dragger 加 accept 让系统选择器
默认过滤非法格式。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:42:14 +08:00