@deepseek-ai/dsh-client-ui-settings-account 0.1.7-rc.2 → 0.2.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -6,8 +6,8 @@
6
6
  en: 1fcba8f273b661fb
7
7
  zh: 14e1236f84ae39d7
8
8
  /deepseek-ai-dsh-client-ui-settings-account:
9
- en: 76e18729c08888be
10
- zh: 170a2032838071b4
9
+ en: 9ff7ac2d70f70b59
10
+ zh: ded522c4cfd6e040
11
11
  /deepseek-ai-dsh-client-ui-settings-account/summary:
12
12
  en: 9ff357621753be69
13
13
  zh: 3f7ede82acc9fa31
@@ -15,8 +15,8 @@
15
15
  en: c26f81e8adf0128b
16
16
  zh: e11ab371f51f66bc
17
17
  /deepseek-ai-dsh-client-ui-settings-account/use-this-package:
18
- en: bc11406a04989a27
19
- zh: 27e5fffa2b3eda6d
18
+ en: db54432d24abc9d9
19
+ zh: 55add79efabfae08
20
20
  /deepseek-ai-dsh-client-ui-settings-account/use-this-package/desktop-onboarding:
21
21
  en: c1c4db71fd09ca13
22
22
  zh: a40c0a01e9951945
@@ -24,8 +24,8 @@
24
24
  en: 6b3ad3b6860100cf
25
25
  zh: aeced4fb37642f15
26
26
  /deepseek-ai-dsh-client-ui-settings-account/further-exploration:
27
- en: c785923662681191
28
- zh: f24389c25e954035
27
+ en: a28acdef21b1643a
28
+ zh: 5e2e357a6b716274
29
29
  /deepseek-ai-dsh-client-ui-settings-account/model-experience:
30
30
  en: ee1df7ca3467ee3f
31
31
  zh: 84904a5148da3862
package/README.md CHANGED
@@ -7,6 +7,8 @@ kind: "package-reference"
7
7
 
8
8
  English | [中文](README.zh.md)
9
9
 
10
+ Desktop product events use the optional [product analytics service](../product-analytics/README.md); ordinary Web interactions are excluded. Workspace login dialogs emit no authentication events; native welcome owns authentication analytics.
11
+
10
12
  Server-expired account credentials clear the displayed account details and emit a localized sign-in reminder toast once; account snapshot replay does not repeat it.
11
13
 
12
14
  ## Summary
@@ -38,11 +40,11 @@ Desktop usage, top-up, and onboarding recharge actions open one isolated native
38
40
 
39
41
  Chat offers each live quota failure from a bound Session to the frame-wide `shell.quota-notice` chain from its host in `shell.overlay`, so the notice outlives the Chat panel that reported it. The account entry claims `ACCOUNT_QUOTA`: while an account credential is stored and the shared host entry exists, the Modal offers Cancel and Top up. While a page requested through the shared request channel is showing, the native view covers this document, so the entry paints neither the Modal nor the Toast. A quota failure that arrives while a Settings-opened page is already showing is not retained: it stays subject to newest-notice replacement, and the Modal appears after the viewer returns while that notice is still current. That Modal reports the failure of the original request, not the account's current balance: the top-up re-read is a separate read, and returning neither proves a successful payment nor dismisses the notice on its own. The notice's own Top up is the retained case: it calls `keepOpen()` and requests the `top-up` page through the shared request channel, keeping that notice and its page mounted through later quota failures. With the shared host entry the entry waits for the first account snapshot instead of rendering a Toast that its own timer could discard; a snapshot that reports no stored credential, or a failed account stream with no snapshot, then renders the same neutral warning Toast itself, and without that host entry the entry renders that Toast immediately, instead of relying on the chat host fallback. The entry owns the hold and its page request and releases both when it unmounts, so a later quota failure publishes again without replaying the dropped ones; dismissal or sign-out clears the hold and the page request. Close, Cancel, a sign-out, or leaving the notice's own embedded page takes the notice down without retrying the request.
40
42
 
41
- The account menu's Feedback entry opens the Feishu questionnaire in the system browser. It supplies the available build version, UI locale and physical screen resolution as prefill_* parameters, with hide_*=1 for every context field; the account UID, tokens and contact details are excluded. Configure contactFormUrl on the ui-settings-account plugin to select another HTTPS form. contactSource defaults to empty until the questionnaire supports a Harness source option; OS and device fields remain unfilled, matching the Web implementation.
43
+ The account menu's Feedback entry opens the Feishu questionnaire in the system browser. Every click samples its context then: the account UID when the profile is ready and carries an id, the build version as harness_version, the UI locale, the physical screen resolution, and device_info. Each context field also carries hide_*=1, stale prefill values for these fields are dropped from the configured form URL first, including uid, device_info and harness_version regardless of the configured URL. Tokens and masked contact details stay out, and a signed-out, still-loading, or failed profile leaves prefill_uid out. When the Desktop bridge has no deviceInfo reader, the form opens with navigator.userAgent. Desktop exposes the optional dshDesktop.deviceInfo reader, whose field format the [Desktop README](../../../apps/desktop/README.md) owns; its answer replaces the user agent, a failed read opens the form with device_info empty instead of dropping the report, and device_info describes the reported environment rather than a hardware model. Configure contactFormUrl on the ui-settings-account plugin to select another HTTPS form; contactSource defaults to empty until the questionnaire supports a Harness source option.
42
44
 
43
45
  Account profile and balance cards share the [settings card material and radius](../../../docs/web-styling.md#corner-radii-and-settings-cards). Usage and top-up links match standard Button geometry; authorization actions use the shared Button.
44
46
 
45
- The sidebar account menu uses the shared Menu surface and backdrop blur. The signed-in menu keeps the shared row typography; the signed-out menu carries its own wider rows and its Contact us copy for the Feedback entry. Its Settings row shows the effective key combination supplied by the shell. Closing Settings returns focus to the sidebar account launcher.
47
+ The sidebar account menu uses the shared Menu surface and backdrop blur. The signed-in menu keeps the shared row typography; the signed-out menu carries its own wider rows. Both menus label the questionnaire entry Feedback. Its Settings row shows the effective key combination supplied by the shell. Closing Settings returns focus to the sidebar account launcher.
46
48
 
47
49
  The account card’s More account information link has no underline and opens the root of the Host-provided Platform usage URL in the system browser, following `platformOrigin`.
48
50
 
@@ -75,7 +77,7 @@ Account login uses a dismissible dialog before the model onboarding credential e
75
77
 
76
78
  A terminal account-state stream failure appears in the sign-in dialog or Account settings. Plugin unload suppresses late failure reports.
77
79
 
78
- The balance card shows recharge funds and bonus credit in separate rows. The bonus row is present while signed in; without positive bonus credit it states that no bonus is available. A failed wallet read shows the existing unavailable copy as a link to Platform — the same destination and behavior as the Usage action, so the embedded page opens on Desktop and a new tab elsewhere — while the loading and empty states stay plain text. Currencies retain their own amounts, and a notice date is rendered only inside the server’s own message.
80
+ The balance card shows recharge funds and bonus credit in separate rows. While signed in, the bonus row appears during loading, after a failed wallet read, and when a wallet holds positive bonus credit; a successful read without positive bonus credit omits the row. A failed wallet read shows the existing unavailable copy as a link to Platform — the same destination and behavior as the Usage action, so the embedded page opens on Desktop and a new tab elsewhere — while the loading state stays plain text. Currencies retain their own amounts, and a notice date is rendered only inside the server’s own message.
79
81
 
80
82
 
81
83
  A successful login selects the first available `deepseek-account` model as the default when no other provider has a configured API key, even if a previous default was saved. Configured keys preserve the existing default even when their provider has no available models. Session-specific selections remain unchanged.
package/README.zh.md CHANGED
@@ -7,6 +7,8 @@ kind: "package-reference"
7
7
 
8
8
  [English](README.md) | 中文
9
9
 
10
+ 桌面端产品事件使用可选的[产品埋点服务](../product-analytics/README.zh.md),不包含普通 Web 交互。工作区内的登录弹窗不发送认证事件;认证埋点由原生欢迎页负责。
11
+
10
12
  账号凭据被服务端判定失效后,清空显示的账号详情,并弹出一次本地化的重新登录提示 toast;账号快照重放不会重复提示。
11
13
 
12
14
  ## 概述
@@ -38,11 +40,11 @@ Desktop 的用量、充值与引导充值操作在 48px 返回栏下方打开同
38
40
 
39
41
  Chat 通过 `shell.overlay` 中的宿主把已绑定 Session 的实时欠费交给全局 `shell.quota-notice` 链,提示的生命周期因此长于上报它的 Chat 面板。账号条目认领 `ACCOUNT_QUOTA`:已存储账号凭证且存在共享宿主条目时,Modal 提供取消和去充值。只要通过该共享请求通道请求的页面正在显示,原生视图就会盖住本页,因此该条目既不绘制 Modal 也不绘制 Toast。在 Account 设置页已打开页面的情况下新到达的欠费不会被保持:它仍受最新提示替换规则约束,返回后若该提示仍是最新一条就显示 Modal。该 Modal 报告的是原始请求的失败,而不是账号当前余额:返回时的重读是一次独立读取,返回本身既不证明支付成功,也不会自动撤下该提示。提示自身的去充值属于被保持的情形:它调用 `keepOpen()` 并通过共享请求通道申请 `top-up` 页面,使该提示与其页面在后续欠费期间保持挂载。存在共享宿主条目时,该条目会等待首个账号快照,而不是渲染一个可能被自身计时器丢弃的 Toast;快照报告未存储凭证,或账号流失败且无快照时,才由该条目自行渲染同一段中立警告 Toast,缺少该宿主条目时则立即渲染该 Toast,而不依赖 Chat 宿主回退。该条目持有保持与页面请求,并在自身卸载时释放二者,因此后续欠费会重新发布而不重放已丢弃的提示;关闭与退出登录也会清除保持和页面请求。关闭、取消、退出登录或离开该提示自己的内嵌页面都会撤下提示,且不会重试请求。
40
42
 
41
- 账号菜单的“意见反馈”入口在系统浏览器中打开飞书问卷。链接通过 prefill_* 参数填写已有的构建版本、界面语言和屏幕物理分辨率,并为所有上下文字段设置 hide_*=1;不传账号 UID、token 或联系方式。可在 ui-settings-account 插件配置 contactFormUrl,切换到另一个 HTTPS 问卷。问卷支持 Harness 来源选项前,contactSource 默认为空;OS 和设备字段沿用 Web 实现,保持未填写。
43
+ 账号菜单的“意见反馈”入口在系统浏览器中打开飞书问卷。每次点击都按当时的上下文取值:profile ready 且带 id 时的账号 UID、以 harness_version 表示的构建版本、界面语言、屏幕物理分辨率,以及 device_info。所有上下文字段同时设置 hide_*=1,配置的表单 URL 中这些字段的 stale prefill 参数先被清除,uid、device_info 与 harness_version 的隐藏参数不依赖配置 URL 的取值。不传 token 或脱敏联系方式;未登录、profile 仍在加载或读取失败时都不填写 prefill_uid。Desktop 桥接没有 deviceInfo 读取器时,打开的表单以 navigator.userAgent 作为 device_info。Desktop 端暴露可选的 dshDesktop.deviceInfo 读取器,其字段格式由 [Desktop README](../../../apps/desktop/README.zh.md) 负责;该读取器的结果取代 user-agent,读取失败时仍打开表单、仅 device_info 留空,而 device_info 描述的是上报的环境而非硬件型号。可在 ui-settings-account 插件配置 contactFormUrl,切换到另一个 HTTPS 问卷;问卷支持 Harness 来源选项前,contactSource 默认为空。
42
44
 
43
45
  账号资料与余额卡片共用[设置卡片材质与圆角](../../../docs/web-styling.zh.md#corner-radii-and-settings-cards)。用量与充值链接与标准 Button 尺寸一致;授权操作使用公共 Button。
44
46
 
45
- 侧边栏账号菜单使用公共 Menu 的表面和背景模糊。已登录菜单沿用公共菜单项排版;未登录菜单使用自己的较宽菜单项,并将“意见反馈”入口的文案改为“联系我们”。设置菜单项显示外壳传入的有效组合键。关闭设置后,焦点回到侧栏账号入口。
47
+ 侧边栏账号菜单使用公共 Menu 的表面和背景模糊。已登录菜单沿用公共菜单项排版;未登录菜单使用自己的较宽菜单项。两种菜单的问卷入口均为“意见反馈”。设置菜单项显示外壳传入的有效组合键。关闭设置后,焦点回到侧栏账号入口。
46
48
 
47
49
  账号卡片的“更多账号信息”链接不带下划线,通过系统浏览器打开 Host 提供的 Platform 用量 URL 的根路径,遵循 `platformOrigin` 配置。
48
50
 
@@ -75,7 +77,7 @@ Desktop preload 标记在账号凭证已存储后启用引导。进度属于本
75
77
 
76
78
  账户状态流的终止错误会显示在登录对话框或账户设置中。插件卸载后不再报告延迟到达的错误。
77
79
 
78
- 余额卡片分行展示充值余额与赠金余额。赠金行在登录态下常驻;没有正额赠金时显示暂无可用赠金。余额或赠金读取失败时,沿用既有的不可用文案并改为指向 Platform 的链接,目标与行为同“查询用量”一致:Desktop 打开内嵌页面,其它环境新开标签页;加载中与暂无赠金仍为纯文本。不同币种分别显示;日期只在服务端自己的消息中出现。
80
+ 余额卡片分行展示充值余额与赠金余额。登录态下,赠金行在加载中、余额读取失败以及存在正额赠金时显示;读取成功但没有正额赠金时不显示该行。余额或赠金读取失败时,沿用既有的不可用文案并改为指向 Platform 的链接,目标与行为同“查询用量”一致:Desktop 打开内嵌页面,其它环境新开标签页;加载中仍为纯文本。不同币种分别显示;日期只在服务端自己的消息中出现。
79
81
 
80
82
 
81
83
  登录成功时,若其他提供方均未配置 API key,则将 `deepseek-account` 的第一个可用模型设为默认值,即使此前保存过默认选择。其他提供方只要配置了 key,就保留原默认值,即使其没有可用模型。会话内的显式选择保持不变。
package/lib/client.js CHANGED
@@ -904,7 +904,7 @@ window.__ModuleLoader__.load({
904
904
  /** Public contact and bonus notice options shared by Host and Client. */
905
905
  /** Validate public questionnaire options. */
906
906
  const ContactConfigFields = {
907
- contactFormUrl: Schema.string().pattern(/^https:\/\/[^/\s]+\//).default("https://trtgsjkv6r.feishu.cn/share/base/form/shrcnlCoGElW7MQznGy9r3YYXcg"),
907
+ contactFormUrl: Schema.string().pattern(/^https:\/\/[^/\s]+\//).default("https://trtgsjkv6r.feishu.cn/share/base/form/shrcnlCoGElW7MQznGy9r3YYXcg?hide_uid=1&hide_device_info=1&hide_harness_version=1"),
908
908
  contactSource: Schema.string().default(""),
909
909
  bonusAckRetryDelayMs: Schema.number().min(1).default(1e3),
910
910
  bonusAckRetryMaxDelayMs: Schema.number().min(1).default(6e4)
@@ -916,7 +916,7 @@ window.__ModuleLoader__.load({
916
916
  /**
917
917
  * Build an external questionnaire URL without authentication credentials.
918
918
  * @param config - questionnaire destination and supported source option.
919
- * @param context - currently available build and browser environment.
919
+ * @param context - account, build and environment facts sampled by the caller.
920
920
  * @returns questionnaire URL with hidden, optionally prefilled context fields.
921
921
  */
922
922
  function contactUrl(config, context) {
@@ -925,11 +925,12 @@ window.__ModuleLoader__.load({
925
925
  const width = Math.round(context.width * ratio);
926
926
  const height = Math.round(context.height * ratio);
927
927
  const fields = {
928
+ uid: context.uid,
928
929
  source: config.contactSource,
929
- app_version: context.version,
930
+ harness_version: context.version,
930
931
  os_version: void 0,
931
932
  device_brand: void 0,
932
- device_model: void 0,
933
+ device_info: context.deviceInfo,
933
934
  app_locale: context.locale,
934
935
  screen_resolution: width > 0 && height > 0 ? `${width}x${height}` : void 0
935
936
  };
@@ -938,8 +939,10 @@ window.__ModuleLoader__.load({
938
939
  url.searchParams.delete(`prefill_${name}`);
939
940
  if (value) url.searchParams.set(`prefill_${name}`, value);
940
941
  }
941
- url.searchParams.delete("prefill_uid");
942
- url.searchParams.delete("hide_uid");
942
+ url.searchParams.delete("prefill_app_version");
943
+ url.searchParams.delete("hide_app_version");
944
+ url.searchParams.delete("prefill_device_model");
945
+ url.searchParams.delete("hide_device_model");
943
946
  return url.href;
944
947
  }
945
948
  //#endregion
@@ -1730,7 +1733,7 @@ window.__ModuleLoader__.load({
1730
1733
  },
1731
1734
  {
1732
1735
  id: "contact",
1733
- label: signedIn ? t("contactUs") : t("contactUsSignedOut"),
1736
+ label: t("contactUs"),
1734
1737
  icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPaperPlaneOutlineMedium, { size: 16 })
1735
1738
  },
1736
1739
  ...signedIn ? [{
@@ -2313,6 +2316,7 @@ window.__ModuleLoader__.load({
2313
2316
  const profile = details?.profile?.status === "ready" ? details.profile.value : void 0;
2314
2317
  const wallets = details?.balance?.status === "ready" ? details.balance.value : void 0;
2315
2318
  const bonusWallets = details?.balance?.status === "ready" ? details.balance.bonusWallets.filter((wallet) => new Big(wallet.balance).gt(0)) : [];
2319
+ const showBonusRow = details?.balance?.status !== "ready" || bonusWallets.length > 0;
2316
2320
  const attempt = state?.attempt;
2317
2321
  const active = attempt !== null && attempt !== void 0 && [
2318
2322
  "initializing",
@@ -2462,7 +2466,7 @@ window.__ModuleLoader__.load({
2462
2466
  children: t(!signedIn ? "balanceSignedOut" : "loading")
2463
2467
  }) : platformLink(t("balanceUnavailable"), AccountSection_module_css_default.unavailableLink)]
2464
2468
  }),
2465
- signedIn && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", { className: AccountSection_module_css_default.divider }), (0, react_jsx_runtime.jsxs)("div", {
2469
+ signedIn && showBonusRow && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", { className: AccountSection_module_css_default.divider }), (0, react_jsx_runtime.jsxs)("div", {
2466
2470
  className: AccountSection_module_css_default.row,
2467
2471
  children: [(0, react_jsx_runtime.jsx)("span", { children: t("bonusBalance") }), (0, react_jsx_runtime.jsx)("span", {
2468
2472
  className: AccountSection_module_css_default.bonusValue,
@@ -2472,10 +2476,7 @@ window.__ModuleLoader__.load({
2472
2476
  }) : details?.balance === void 0 ? (0, react_jsx_runtime.jsx)("span", {
2473
2477
  className: AccountSection_module_css_default.unavailable,
2474
2478
  children: t("loading")
2475
- }) : details.balance.status === "failed" ? platformLink(t("balanceUnavailable"), AccountSection_module_css_default.unavailableLink) : (0, react_jsx_runtime.jsx)("span", {
2476
- className: AccountSection_module_css_default.unavailable,
2477
- children: t("bonusEmpty")
2478
- })
2479
+ }) : platformLink(t("balanceUnavailable"), AccountSection_module_css_default.unavailableLink)
2479
2480
  })]
2480
2481
  })] }),
2481
2482
  (0, react_jsx_runtime.jsx)("div", { className: AccountSection_module_css_default.divider }),
@@ -2739,10 +2740,10 @@ window.__ModuleLoader__.load({
2739
2740
  onboardingBack: "上一步",
2740
2741
  onboardingSkip: "跳过",
2741
2742
  onboardingSkipTitle: "跳过设置?",
2742
- onboardingSkipDescription: "你可以随时前往 个人中心 → 通用设置 中调整工作过程、性能与用量展示方式或开启代码工作工具。",
2743
+ onboardingSkipDescription: "你可以随时前往 设置 → 通用设置 中调整工作过程、性能与用量展示方式或开启代码工作工具。",
2743
2744
  onboardingKeepSetting: "继续设置",
2744
2745
  onboardingNoCreditTitle: "暂时跳过充值?",
2745
- onboardingNoCreditDescription: "没有可用额度时,DeepSeek Harness 将无法开始新的任务。你可以稍后前往 个人中心 → 账号与余额 进行充值。",
2746
+ onboardingNoCreditDescription: "没有可用额度时,DeepSeek Harness 将无法开始新的任务。你可以稍后前往 设置 → 账号与余额 进行充值。",
2746
2747
  onboardingUnderstood: "我知道了",
2747
2748
  onboardingGoTopUp: "前往充值",
2748
2749
  onboardingSaveFailed: "未能保存设置,请重试。",
@@ -2786,10 +2787,10 @@ window.__ModuleLoader__.load({
2786
2787
  onboardingBack: "Back",
2787
2788
  onboardingSkip: "Skip",
2788
2789
  onboardingSkipTitle: "Skip setup?",
2789
- onboardingSkipDescription: "You can change how progress, performance, and usage are displayed, or enable Coding Tools, anytime in Profile → General Settings.",
2790
+ onboardingSkipDescription: "You can change how progress, performance, and usage are displayed, or enable Coding Tools, anytime in Settings → General.",
2790
2791
  onboardingKeepSetting: "Continue setup",
2791
2792
  onboardingNoCreditTitle: "Skip adding credits?",
2792
- onboardingNoCreditDescription: "DeepSeek Harness can’t start new tasks without credits. You can add them later in Profile → Accounts.",
2793
+ onboardingNoCreditDescription: "DeepSeek Harness can’t start new tasks without credits. You can add them later in Settings → Account.",
2793
2794
  onboardingUnderstood: "Got it",
2794
2795
  onboardingGoTopUp: "Add credits",
2795
2796
  onboardingSaveFailed: "Could not save settings. Try again.",
@@ -2815,7 +2816,6 @@ window.__ModuleLoader__.load({
2815
2816
  backToHarness: "Back to DeepSeek Harness",
2816
2817
  settings: "Settings",
2817
2818
  contactUs: "Feedback",
2818
- contactUsSignedOut: "Contact us",
2819
2819
  menu: "Account menu",
2820
2820
  nav: "Account",
2821
2821
  signedIn: "Signed in to DeepSeek",
@@ -2847,8 +2847,7 @@ window.__ModuleLoader__.load({
2847
2847
  quotaTitle: "No balance available",
2848
2848
  quotaDescription: "DeepSeek Harness cannot start a new task with this account when no balance is available. Would you like to top up? You can also top up later in Settings → Account.",
2849
2849
  quotaTopUp: "Top up",
2850
- bonusNoticeTitle: "Bonus credited",
2851
- bonusEmpty: "No bonus available"
2850
+ bonusNoticeTitle: "Bonus credited"
2852
2851
  };
2853
2852
  /** Chinese account settings copy. */
2854
2853
  const zh = {
@@ -2875,7 +2874,6 @@ window.__ModuleLoader__.load({
2875
2874
  backToHarness: "返回 DeepSeek Harness",
2876
2875
  settings: "设置",
2877
2876
  contactUs: "意见反馈",
2878
- contactUsSignedOut: "联系我们",
2879
2877
  menu: "账号菜单",
2880
2878
  nav: "账号与余额",
2881
2879
  signedIn: "已登录 DeepSeek",
@@ -2907,8 +2905,7 @@ window.__ModuleLoader__.load({
2907
2905
  quotaTitle: "当前无可用余额",
2908
2906
  quotaDescription: "没有可用额度时,DeepSeek Harness 无法开始新的任务,是否前往充值?或者可以稍后前往 设置 → 账号与余额 进行充值。",
2909
2907
  quotaTopUp: "去充值",
2910
- bonusNoticeTitle: "赠金已到账",
2911
- bonusEmpty: "暂无可用赠金"
2908
+ bonusNoticeTitle: "赠金已到账"
2912
2909
  };
2913
2910
  //#endregion
2914
2911
  //#region lib/types/client/AccountQuotaNotice.js
@@ -3783,7 +3780,7 @@ window.__ModuleLoader__.load({
3783
3780
  //#region lib/types/client/OnboardingConfirmation.js
3784
3781
  /** Credit and setup confirmations with contained keyboard focus. */
3785
3782
  /** @param props - confirmation action, localized copy and navigation callbacks. @returns a focus-contained dialog. */
3786
- function OnboardingConfirmation({ kind, t, busy, canRecharge, onClose, onContinue, onRecharge, onSkip }) {
3783
+ function OnboardingConfirmation({ kind, t, busy, canRecharge, onClose, onContinueSetup, onContinue, onRecharge, onSkip }) {
3787
3784
  const credit = kind !== "skip";
3788
3785
  const title = t(credit ? "onboardingNoCreditTitle" : "onboardingSkipTitle");
3789
3786
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
@@ -3812,7 +3809,7 @@ window.__ModuleLoader__.load({
3812
3809
  className: DesktopOnboarding_module_css_default.dialogButton,
3813
3810
  variant: "outline",
3814
3811
  disabled: busy,
3815
- onClick: kind === "credit-skip" ? onSkip : kind === "credit" ? onContinue : onClose,
3812
+ onClick: kind === "credit-skip" ? onSkip : kind === "credit" ? onContinue : onContinueSetup,
3816
3813
  children: t(credit ? "onboardingUnderstood" : "onboardingKeepSetting")
3817
3814
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3818
3815
  className: DesktopOnboarding_module_css_default.dialogButton,
@@ -3828,12 +3825,18 @@ window.__ModuleLoader__.load({
3828
3825
  }
3829
3826
  //#endregion
3830
3827
  //#region lib/types/client/DesktopOnboarding.js
3831
- /** Coordinates onboarding navigation, transitions and the shared native recharge page. */
3828
+ const onboardingPages = {
3829
+ welcome: "onboarding_welcome",
3830
+ credit: "onboarding_recharge",
3831
+ purpose: "onboarding_use_case",
3832
+ process: "onboarding_process",
3833
+ done: void 0
3834
+ };
3832
3835
  /**
3833
3836
  * @param props - durable choices, account state, localized copy and the shared recharge page channel.
3834
3837
  * @returns the active first-run page.
3835
3838
  */
3836
- function DesktopOnboarding({ state, account, openPlatformPage, update, complete, retry, t, locale, exiting = false }) {
3839
+ function DesktopOnboarding({ state, account, openPlatformPage, update, complete, retry, t, locale, track, exiting = false }) {
3837
3840
  const [dialog, setDialog] = (0, react.useState)(null);
3838
3841
  const heading = (0, react.useRef)(null);
3839
3842
  const page = (0, react.useRef)(null);
@@ -3872,12 +3875,69 @@ window.__ModuleLoader__.load({
3872
3875
  (0, react.useEffect)(() => {
3873
3876
  heading.current?.focus();
3874
3877
  }, [step]);
3878
+ const pageName = onboardingPages[step];
3879
+ const shownPage = (0, react.useRef)(null);
3880
+ (0, react.useEffect)(() => {
3881
+ if (!state.visible || pageName === void 0 || exiting) {
3882
+ shownPage.current = null;
3883
+ return;
3884
+ }
3885
+ if (state.status === "loading") return;
3886
+ if (shownPage.current === pageName) return;
3887
+ shownPage.current = pageName;
3888
+ track?.("onboarding_page_view", { page_name: pageName });
3889
+ }, [
3890
+ state.visible,
3891
+ state.status,
3892
+ step,
3893
+ pageName,
3894
+ exiting,
3895
+ track
3896
+ ]);
3897
+ const shownPopup = (0, react.useRef)(null);
3898
+ (0, react.useEffect)(() => {
3899
+ if (dialog === null || !state.visible || state.status === "loading" || step === "done") {
3900
+ shownPopup.current = null;
3901
+ return;
3902
+ }
3903
+ if (shownPopup.current === dialog) return;
3904
+ shownPopup.current = dialog;
3905
+ track?.("onboarding_popup_view", { popup_name: dialog === "skip" ? "skip_setting" : "skip_charge" });
3906
+ }, [
3907
+ dialog,
3908
+ track,
3909
+ state.visible,
3910
+ state.status,
3911
+ step
3912
+ ]);
3913
+ const popupClick = (button_name) => {
3914
+ track?.("onboarding_popup_click", {
3915
+ popup_name: dialog === "skip" ? "skip_setting" : "skip_charge",
3916
+ button_name
3917
+ });
3918
+ };
3875
3919
  if (state.visible && state.status === "loading") return (0, react_jsx_runtime.jsx)(OnboardingSurface, { children: (0, react_jsx_runtime.jsx)("div", {
3876
3920
  className: DesktopOnboarding_module_css_default.loading,
3877
3921
  role: "status",
3878
3922
  children: t("onboardingLoading")
3879
3923
  }) });
3880
- if (!state.visible || step === "done") return null;
3924
+ if (!state.visible || pageName === void 0) return null;
3925
+ const click = (button_name) => {
3926
+ const selected_content = step === "purpose" && progress.purpose !== null ? {
3927
+ office: "office",
3928
+ development: "code",
3929
+ both: "code_office"
3930
+ }[progress.purpose] : step === "process" && progress.process !== null ? {
3931
+ compact: "focus_result",
3932
+ standard: "key_detail",
3933
+ detailed: "full_process"
3934
+ }[progress.process] : void 0;
3935
+ track?.("onboarding_page_click", {
3936
+ page_name: pageName,
3937
+ button_name,
3938
+ ...selected_content === void 0 ? {} : { selected_content }
3939
+ });
3940
+ };
3881
3941
  const go = (next) => {
3882
3942
  update({ step: next });
3883
3943
  };
@@ -3914,6 +3974,7 @@ window.__ModuleLoader__.load({
3914
3974
  heading,
3915
3975
  busy,
3916
3976
  onStart: () => {
3977
+ click("next");
3917
3978
  go("credit");
3918
3979
  }
3919
3980
  }),
@@ -3925,10 +3986,17 @@ window.__ModuleLoader__.load({
3925
3986
  funded: state.creditFunded,
3926
3987
  canRecharge,
3927
3988
  onContinue: () => {
3989
+ click("continue");
3928
3990
  go("purpose");
3929
3991
  },
3930
- onRecharge: recharge,
3931
- onLater: later
3992
+ onRecharge: () => {
3993
+ click("charge");
3994
+ recharge();
3995
+ },
3996
+ onLater: () => {
3997
+ click("later");
3998
+ later();
3999
+ }
3932
4000
  }),
3933
4001
  step === "purpose" && (0, react_jsx_runtime.jsx)(OnboardingPurposeStep, {
3934
4002
  t,
@@ -3938,7 +4006,10 @@ window.__ModuleLoader__.load({
3938
4006
  onSelect: (purpose) => {
3939
4007
  update({ purpose });
3940
4008
  },
3941
- onContinue: purposeNext
4009
+ onContinue: () => {
4010
+ click("next");
4011
+ purposeNext();
4012
+ }
3942
4013
  }),
3943
4014
  step === "process" && (0, react_jsx_runtime.jsx)(OnboardingProcessStep, {
3944
4015
  t,
@@ -3949,6 +4020,7 @@ window.__ModuleLoader__.load({
3949
4020
  update({ process });
3950
4021
  },
3951
4022
  onComplete: () => {
4023
+ click("next");
3952
4024
  complete("completed");
3953
4025
  }
3954
4026
  }),
@@ -3969,6 +4041,7 @@ window.__ModuleLoader__.load({
3969
4041
  type: "button",
3970
4042
  disabled: busy,
3971
4043
  onClick: () => {
4044
+ click("back");
3972
4045
  go(step === "credit" ? "welcome" : step === "purpose" ? "credit" : "purpose");
3973
4046
  },
3974
4047
  children: [(0, react_jsx_runtime.jsx)("span", {
@@ -3980,6 +4053,7 @@ window.__ModuleLoader__.load({
3980
4053
  type: "button",
3981
4054
  disabled: busy,
3982
4055
  onClick: () => {
4056
+ click("skip");
3983
4057
  setDialog(step === "credit" ? "credit-skip" : "skip");
3984
4058
  },
3985
4059
  children: t("onboardingSkip")
@@ -3993,14 +4067,24 @@ window.__ModuleLoader__.load({
3993
4067
  busy,
3994
4068
  canRecharge,
3995
4069
  onClose: () => {
4070
+ popupClick("close");
4071
+ setDialog(null);
4072
+ },
4073
+ onContinueSetup: () => {
4074
+ popupClick("setting");
3996
4075
  setDialog(null);
3997
4076
  },
3998
4077
  onContinue: () => {
4078
+ popupClick("know");
3999
4079
  setDialog(null);
4000
4080
  go("purpose");
4001
4081
  },
4002
- onRecharge: recharge,
4082
+ onRecharge: () => {
4083
+ popupClick("charge");
4084
+ recharge();
4085
+ },
4003
4086
  onSkip: () => {
4087
+ popupClick(dialog === "skip" ? "enter" : "know");
4004
4088
  complete("skipped").then(() => {
4005
4089
  setDialog(null);
4006
4090
  });
@@ -4125,7 +4209,7 @@ window.__ModuleLoader__.load({
4125
4209
  for (const listener of listeners) listener();
4126
4210
  };
4127
4211
  /** @returns the client identity for one account call, read at call time so it carries the language and zone in effect then. */
4128
- const client = () => accountClientMetadata(ctx.locale.getSnapshot().active, "0.1.7-rc.2");
4212
+ const client = () => accountClientMetadata(ctx.locale.getSnapshot().active, "0.2.0-rc.2");
4129
4213
  const notices = createBonusNoticeController({
4130
4214
  ackRetryDelayMs: config.bonusAckRetryDelayMs,
4131
4215
  ackRetryMaxDelayMs: config.bonusAckRetryMaxDelayMs,
@@ -4255,14 +4339,33 @@ window.__ModuleLoader__.load({
4255
4339
  ...nativePlatform === void 0 ? {} : { openPlatformPage: platformPageOpener(refreshAccount) },
4256
4340
  refreshAccount,
4257
4341
  contactUs() {
4258
- const url = contactUrl(config, {
4259
- version: "0.1.7-rc.2",
4342
+ const profile = snapshot.details?.profile;
4343
+ const context = {
4344
+ uid: profile?.status === "ready" ? profile.value.id : null,
4345
+ version: "0.2.0-rc.2",
4260
4346
  locale: ctx.locale.getSnapshot().active === "zh" ? "zh-CN" : "en",
4261
4347
  width: window.screen.width,
4262
4348
  height: window.screen.height,
4263
4349
  pixelRatio: window.devicePixelRatio
4264
- });
4265
- window.open(url, "_blank", "noopener,noreferrer");
4350
+ };
4351
+ const openForm = (deviceInfo) => {
4352
+ window.open(contactUrl(config, {
4353
+ ...context,
4354
+ deviceInfo
4355
+ }), "_blank", "noopener,noreferrer");
4356
+ };
4357
+ const readDeviceInfo = globalThis.dshDesktop?.deviceInfo;
4358
+ if (readDeviceInfo === void 0) {
4359
+ openForm(navigator.userAgent);
4360
+ return;
4361
+ }
4362
+ (async () => {
4363
+ let deviceInfo = "";
4364
+ try {
4365
+ deviceInfo = await readDeviceInfo();
4366
+ } catch (_error) {}
4367
+ openForm(deviceInfo);
4368
+ })();
4266
4369
  },
4267
4370
  showLogin(visible) {
4268
4371
  publish({
@@ -4358,7 +4461,8 @@ window.__ModuleLoader__.load({
4358
4461
  ...nativePlatform === void 0 ? {} : { openPlatformPage: platformPageOpener(refresh) },
4359
4462
  update: (change) => controller.update(change),
4360
4463
  complete: (reason) => controller.complete(reason),
4361
- retry: () => controller.retry()
4464
+ retry: () => controller.retry(),
4465
+ track: (name, attributes) => ctx.get("productAnalytics")?.track(name, attributes)
4362
4466
  })
4363
4467
  }, DesktopOnboardingEntry));
4364
4468
  }
package/lib/index.js CHANGED
@@ -3,7 +3,7 @@ import z from "@deepseek-ai/schemastery";
3
3
  /** Public contact and bonus notice options shared by Host and Client. */
4
4
  /** Validate public questionnaire options. */
5
5
  const ContactConfigFields = {
6
- contactFormUrl: z.string().pattern(/^https:\/\/[^/\s]+\//).default("https://trtgsjkv6r.feishu.cn/share/base/form/shrcnlCoGElW7MQznGy9r3YYXcg"),
6
+ contactFormUrl: z.string().pattern(/^https:\/\/[^/\s]+\//).default("https://trtgsjkv6r.feishu.cn/share/base/form/shrcnlCoGElW7MQznGy9r3YYXcg?hide_uid=1&hide_device_info=1&hide_harness_version=1"),
7
7
  contactSource: z.string().default(""),
8
8
  bonusAckRetryDelayMs: z.number().min(1).default(1e3),
9
9
  bonusAckRetryMaxDelayMs: z.number().min(1).default(6e4)
@@ -46,7 +46,7 @@ export interface AccountSectionInjected {
46
46
  * @returns after both reads settle.
47
47
  */
48
48
  refreshAccount: () => Promise<void>;
49
- /** Open the external support questionnaire with the current build and browser environment. */
49
+ /** Open the external support questionnaire with the account, build and environment sampled by this click. */
50
50
  contactUs: () => void;
51
51
  /** Open or dismiss the login dialog. */
52
52
  showLogin: (visible: boolean) => void;
@@ -3,5 +3,5 @@ import type { DesktopOnboardingProps } from './onboarding-contract.ts';
3
3
  * @param props - durable choices, account state, localized copy and the shared recharge page channel.
4
4
  * @returns the active first-run page.
5
5
  */
6
- export declare function DesktopOnboarding({ state, account, openPlatformPage, update, complete, retry, t, locale, exiting, }: DesktopOnboardingProps): import("react").JSX.Element | null;
6
+ export declare function DesktopOnboarding({ state, account, openPlatformPage, update, complete, retry, t, locale, track, exiting, }: DesktopOnboardingProps): import("react").JSX.Element | null;
7
7
  //# sourceMappingURL=DesktopOnboarding.d.ts.map
@@ -2,11 +2,12 @@ import type { DesktopOnboardingProps } from './onboarding-contract.ts';
2
2
  /** The action requiring confirmation, including skipping directly from the credit page. */
3
3
  export type OnboardingConfirmationKind = 'credit' | 'credit-skip' | 'skip';
4
4
  /** @param props - confirmation action, localized copy and navigation callbacks. @returns a focus-contained dialog. */
5
- export declare function OnboardingConfirmation({ kind, t, busy, canRecharge, onClose, onContinue, onRecharge, onSkip }: Pick<DesktopOnboardingProps, 't'> & {
5
+ export declare function OnboardingConfirmation({ kind, t, busy, canRecharge, onClose, onContinueSetup, onContinue, onRecharge, onSkip }: Pick<DesktopOnboardingProps, 't'> & {
6
6
  kind: OnboardingConfirmationKind;
7
7
  busy: boolean;
8
8
  canRecharge: boolean;
9
9
  onClose: () => void;
10
+ onContinueSetup: () => void;
10
11
  onContinue: () => void;
11
12
  onRecharge: () => void;
12
13
  onSkip: () => void;
@@ -1,14 +1,17 @@
1
- /** Feishu questionnaire context follows the Platform Web ticket fields. */
1
+ /** Feishu questionnaire context: Harness build, locale, screen and reported environment. */
2
+ import type { AccountUserId } from '@deepseek-ai/dsh-deepseek-account/types';
2
3
  import type { ContactConfig } from '../contact-config.ts';
3
4
  /**
4
5
  * Build an external questionnaire URL without authentication credentials.
5
6
  * @param config - questionnaire destination and supported source option.
6
- * @param context - currently available build and browser environment.
7
+ * @param context - account, build and environment facts sampled by the caller.
7
8
  * @returns questionnaire URL with hidden, optionally prefilled context fields.
8
9
  */
9
10
  export declare function contactUrl(config: ContactConfig, context: {
11
+ uid: AccountUserId | null | undefined;
10
12
  version: string | undefined;
11
13
  locale: string;
14
+ deviceInfo: string;
12
15
  width: number;
13
16
  height: number;
14
17
  pixelRatio: number;
@@ -30,10 +30,10 @@ export declare const onboardingCopy: {
30
30
  readonly onboardingBack: "上一步";
31
31
  readonly onboardingSkip: "跳过";
32
32
  readonly onboardingSkipTitle: "跳过设置?";
33
- readonly onboardingSkipDescription: "你可以随时前往 个人中心 → 通用设置 中调整工作过程、性能与用量展示方式或开启代码工作工具。";
33
+ readonly onboardingSkipDescription: "你可以随时前往 设置 → 通用设置 中调整工作过程、性能与用量展示方式或开启代码工作工具。";
34
34
  readonly onboardingKeepSetting: "继续设置";
35
35
  readonly onboardingNoCreditTitle: "暂时跳过充值?";
36
- readonly onboardingNoCreditDescription: "没有可用额度时,DeepSeek Harness 将无法开始新的任务。你可以稍后前往 个人中心 → 账号与余额 进行充值。";
36
+ readonly onboardingNoCreditDescription: "没有可用额度时,DeepSeek Harness 将无法开始新的任务。你可以稍后前往 设置 → 账号与余额 进行充值。";
37
37
  readonly onboardingUnderstood: "我知道了";
38
38
  readonly onboardingGoTopUp: "前往充值";
39
39
  readonly onboardingSaveFailed: "未能保存设置,请重试。";
@@ -20,7 +20,6 @@ export declare const en: {
20
20
  readonly backToHarness: "Back to DeepSeek Harness";
21
21
  readonly settings: "Settings";
22
22
  readonly contactUs: "Feedback";
23
- readonly contactUsSignedOut: "Contact us";
24
23
  readonly menu: "Account menu";
25
24
  readonly nav: "Account";
26
25
  readonly signedIn: "Signed in to DeepSeek";
@@ -53,7 +52,6 @@ export declare const en: {
53
52
  readonly quotaDescription: "DeepSeek Harness cannot start a new task with this account when no balance is available. Would you like to top up? You can also top up later in Settings → Account.";
54
53
  readonly quotaTopUp: "Top up";
55
54
  readonly bonusNoticeTitle: "Bonus credited";
56
- readonly bonusEmpty: "No bonus available";
57
55
  readonly onboardingLater: string;
58
56
  readonly onboardingArtworkLocale: string;
59
57
  readonly onboardingWelcome: string;
@@ -1,4 +1,5 @@
1
1
  /** Pure view inputs for the desktop onboarding flow. */
2
+ import type { TrackProductEvent } from '@deepseek-ai/dsh-client-product-analytics/client';
2
3
  import type { OnboardingProgress } from '../onboarding-settings.ts';
3
4
  import type { AccountSnapshot } from './AccountSection.tsx';
4
5
  import type { PlatformPages } from './platform-pages.ts';
@@ -18,6 +19,8 @@ export type OnboardingChange = Partial<Pick<OnboardingProgress, 'step' | 'purpos
18
19
  export interface DesktopOnboardingProps {
19
20
  /** Keep the saved final step visible while revealing the workspace. */
20
21
  exiting?: boolean;
22
+ /** Desktop collection callback; absent when analytics is disabled. */
23
+ track?: TrackProductEvent;
21
24
  state: DesktopOnboardingState;
22
25
  account: AccountSnapshot;
23
26
  /** Desktop-only: show the shared native recharge page; absent in ordinary browsers. */
@@ -36,7 +36,7 @@ export declare class DesktopOnboardingController {
36
36
  * @param readApiKeyPresence - reads configured model-credential metadata without secrets.
37
37
  */
38
38
  constructor(progress: ConfigForm<OnboardingSettings>, chat: ConfigForm<{
39
- transcriptView: TranscriptViewMode;
39
+ transcriptView?: TranscriptViewMode | null;
40
40
  performanceUsage: 'compact' | 'detailed';
41
41
  }>, setDeveloperTools: (enabled: boolean) => Promise<void>, account: HostObservable<AccountSnapshot>, readApiKeyPresence: () => Promise<boolean>, settings: SettingsDescribeFace);
42
42
  /** Recheck credential metadata after a provider or credential invalidation. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-settings-account",
3
3
  "description": "Manage DeepSeek login and open Platform billing pages",
4
- "version": "0.1.7-rc.2",
4
+ "version": "0.2.0-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -51,21 +51,22 @@
51
51
  "@types/react-dom": "~18.3.0",
52
52
  "big.js": "^7.0.1",
53
53
  "@deepseek-ai/cordis": "~4.0.4",
54
- "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
55
- "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
56
- "@deepseek-ai/dsh-client-test-runtime": "0.1.7-rc.2",
57
- "@deepseek-ai/dsh-client-store": "0.1.7-rc.2",
58
- "@deepseek-ai/dsh-client-ui-chat": "0.1.7-rc.2",
59
- "@deepseek-ai/dsh-client-ui-layout": "0.1.7-rc.2",
60
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
61
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2",
62
- "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.2",
63
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
64
- "@deepseek-ai/dsh-client-ui-theme": "0.1.7-rc.2",
65
- "@deepseek-ai/dsh-deepseek-account": "0.1.7-rc.2",
66
- "@deepseek-ai/dsh-settings": "0.1.7-rc.2",
67
- "@deepseek-ai/dsh-client-ui-settings-models": "0.1.7-rc.2",
68
- "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.2"
54
+ "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.2",
55
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
56
+ "@deepseek-ai/dsh-client-store": "0.2.0-rc.2",
57
+ "@deepseek-ai/dsh-client-test-runtime": "0.2.0-rc.2",
58
+ "@deepseek-ai/dsh-client-ui-layout": "0.2.0-rc.2",
59
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2",
60
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
61
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
62
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
63
+ "@deepseek-ai/dsh-client-ui-theme": "0.2.0-rc.2",
64
+ "@deepseek-ai/dsh-deepseek-account": "0.2.0-rc.2",
65
+ "@deepseek-ai/dsh-client-ui-chat": "0.2.0-rc.2",
66
+ "@deepseek-ai/dsh-settings": "0.2.0-rc.2",
67
+ "@deepseek-ai/dsh-client-ui-settings-models": "0.2.0-rc.2",
68
+ "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
69
+ "@deepseek-ai/dsh-client-product-analytics": "0.2.0-rc.2"
69
70
  },
70
71
  "files": [
71
72
  "lib/index.js",