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

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
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
 
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
 
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 ? [{
@@ -2815,7 +2818,6 @@ window.__ModuleLoader__.load({
2815
2818
  backToHarness: "Back to DeepSeek Harness",
2816
2819
  settings: "Settings",
2817
2820
  contactUs: "Feedback",
2818
- contactUsSignedOut: "Contact us",
2819
2821
  menu: "Account menu",
2820
2822
  nav: "Account",
2821
2823
  signedIn: "Signed in to DeepSeek",
@@ -2875,7 +2877,6 @@ window.__ModuleLoader__.load({
2875
2877
  backToHarness: "返回 DeepSeek Harness",
2876
2878
  settings: "设置",
2877
2879
  contactUs: "意见反馈",
2878
- contactUsSignedOut: "联系我们",
2879
2880
  menu: "账号菜单",
2880
2881
  nav: "账号与余额",
2881
2882
  signedIn: "已登录 DeepSeek",
@@ -3783,7 +3784,7 @@ window.__ModuleLoader__.load({
3783
3784
  //#region lib/types/client/OnboardingConfirmation.js
3784
3785
  /** Credit and setup confirmations with contained keyboard focus. */
3785
3786
  /** @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 }) {
3787
+ function OnboardingConfirmation({ kind, t, busy, canRecharge, onClose, onContinueSetup, onContinue, onRecharge, onSkip }) {
3787
3788
  const credit = kind !== "skip";
3788
3789
  const title = t(credit ? "onboardingNoCreditTitle" : "onboardingSkipTitle");
3789
3790
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
@@ -3812,7 +3813,7 @@ window.__ModuleLoader__.load({
3812
3813
  className: DesktopOnboarding_module_css_default.dialogButton,
3813
3814
  variant: "outline",
3814
3815
  disabled: busy,
3815
- onClick: kind === "credit-skip" ? onSkip : kind === "credit" ? onContinue : onClose,
3816
+ onClick: kind === "credit-skip" ? onSkip : kind === "credit" ? onContinue : onContinueSetup,
3816
3817
  children: t(credit ? "onboardingUnderstood" : "onboardingKeepSetting")
3817
3818
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3818
3819
  className: DesktopOnboarding_module_css_default.dialogButton,
@@ -3828,12 +3829,18 @@ window.__ModuleLoader__.load({
3828
3829
  }
3829
3830
  //#endregion
3830
3831
  //#region lib/types/client/DesktopOnboarding.js
3831
- /** Coordinates onboarding navigation, transitions and the shared native recharge page. */
3832
+ const onboardingPages = {
3833
+ welcome: "onboarding_welcome",
3834
+ credit: "onboarding_recharge",
3835
+ purpose: "onboarding_use_case",
3836
+ process: "onboarding_process",
3837
+ done: void 0
3838
+ };
3832
3839
  /**
3833
3840
  * @param props - durable choices, account state, localized copy and the shared recharge page channel.
3834
3841
  * @returns the active first-run page.
3835
3842
  */
3836
- function DesktopOnboarding({ state, account, openPlatformPage, update, complete, retry, t, locale, exiting = false }) {
3843
+ function DesktopOnboarding({ state, account, openPlatformPage, update, complete, retry, t, locale, track, exiting = false }) {
3837
3844
  const [dialog, setDialog] = (0, react.useState)(null);
3838
3845
  const heading = (0, react.useRef)(null);
3839
3846
  const page = (0, react.useRef)(null);
@@ -3872,12 +3879,69 @@ window.__ModuleLoader__.load({
3872
3879
  (0, react.useEffect)(() => {
3873
3880
  heading.current?.focus();
3874
3881
  }, [step]);
3882
+ const pageName = onboardingPages[step];
3883
+ const shownPage = (0, react.useRef)(null);
3884
+ (0, react.useEffect)(() => {
3885
+ if (!state.visible || pageName === void 0 || exiting) {
3886
+ shownPage.current = null;
3887
+ return;
3888
+ }
3889
+ if (state.status === "loading") return;
3890
+ if (shownPage.current === pageName) return;
3891
+ shownPage.current = pageName;
3892
+ track?.("onboarding_page_view", { page_name: pageName });
3893
+ }, [
3894
+ state.visible,
3895
+ state.status,
3896
+ step,
3897
+ pageName,
3898
+ exiting,
3899
+ track
3900
+ ]);
3901
+ const shownPopup = (0, react.useRef)(null);
3902
+ (0, react.useEffect)(() => {
3903
+ if (dialog === null || !state.visible || state.status === "loading" || step === "done") {
3904
+ shownPopup.current = null;
3905
+ return;
3906
+ }
3907
+ if (shownPopup.current === dialog) return;
3908
+ shownPopup.current = dialog;
3909
+ track?.("onboarding_popup_view", { popup_name: dialog === "skip" ? "skip_setting" : "skip_charge" });
3910
+ }, [
3911
+ dialog,
3912
+ track,
3913
+ state.visible,
3914
+ state.status,
3915
+ step
3916
+ ]);
3917
+ const popupClick = (button_name) => {
3918
+ track?.("onboarding_popup_click", {
3919
+ popup_name: dialog === "skip" ? "skip_setting" : "skip_charge",
3920
+ button_name
3921
+ });
3922
+ };
3875
3923
  if (state.visible && state.status === "loading") return (0, react_jsx_runtime.jsx)(OnboardingSurface, { children: (0, react_jsx_runtime.jsx)("div", {
3876
3924
  className: DesktopOnboarding_module_css_default.loading,
3877
3925
  role: "status",
3878
3926
  children: t("onboardingLoading")
3879
3927
  }) });
3880
- if (!state.visible || step === "done") return null;
3928
+ if (!state.visible || pageName === void 0) return null;
3929
+ const click = (button_name) => {
3930
+ const selected_content = step === "purpose" && progress.purpose !== null ? {
3931
+ office: "office",
3932
+ development: "code",
3933
+ both: "code_office"
3934
+ }[progress.purpose] : step === "process" && progress.process !== null ? {
3935
+ compact: "focus_result",
3936
+ standard: "key_detail",
3937
+ detailed: "full_process"
3938
+ }[progress.process] : void 0;
3939
+ track?.("onboarding_page_click", {
3940
+ page_name: pageName,
3941
+ button_name,
3942
+ ...selected_content === void 0 ? {} : { selected_content }
3943
+ });
3944
+ };
3881
3945
  const go = (next) => {
3882
3946
  update({ step: next });
3883
3947
  };
@@ -3914,6 +3978,7 @@ window.__ModuleLoader__.load({
3914
3978
  heading,
3915
3979
  busy,
3916
3980
  onStart: () => {
3981
+ click("next");
3917
3982
  go("credit");
3918
3983
  }
3919
3984
  }),
@@ -3925,10 +3990,17 @@ window.__ModuleLoader__.load({
3925
3990
  funded: state.creditFunded,
3926
3991
  canRecharge,
3927
3992
  onContinue: () => {
3993
+ click("continue");
3928
3994
  go("purpose");
3929
3995
  },
3930
- onRecharge: recharge,
3931
- onLater: later
3996
+ onRecharge: () => {
3997
+ click("charge");
3998
+ recharge();
3999
+ },
4000
+ onLater: () => {
4001
+ click("later");
4002
+ later();
4003
+ }
3932
4004
  }),
3933
4005
  step === "purpose" && (0, react_jsx_runtime.jsx)(OnboardingPurposeStep, {
3934
4006
  t,
@@ -3938,7 +4010,10 @@ window.__ModuleLoader__.load({
3938
4010
  onSelect: (purpose) => {
3939
4011
  update({ purpose });
3940
4012
  },
3941
- onContinue: purposeNext
4013
+ onContinue: () => {
4014
+ click("next");
4015
+ purposeNext();
4016
+ }
3942
4017
  }),
3943
4018
  step === "process" && (0, react_jsx_runtime.jsx)(OnboardingProcessStep, {
3944
4019
  t,
@@ -3949,6 +4024,7 @@ window.__ModuleLoader__.load({
3949
4024
  update({ process });
3950
4025
  },
3951
4026
  onComplete: () => {
4027
+ click("next");
3952
4028
  complete("completed");
3953
4029
  }
3954
4030
  }),
@@ -3969,6 +4045,7 @@ window.__ModuleLoader__.load({
3969
4045
  type: "button",
3970
4046
  disabled: busy,
3971
4047
  onClick: () => {
4048
+ click("back");
3972
4049
  go(step === "credit" ? "welcome" : step === "purpose" ? "credit" : "purpose");
3973
4050
  },
3974
4051
  children: [(0, react_jsx_runtime.jsx)("span", {
@@ -3980,6 +4057,7 @@ window.__ModuleLoader__.load({
3980
4057
  type: "button",
3981
4058
  disabled: busy,
3982
4059
  onClick: () => {
4060
+ click("skip");
3983
4061
  setDialog(step === "credit" ? "credit-skip" : "skip");
3984
4062
  },
3985
4063
  children: t("onboardingSkip")
@@ -3993,14 +4071,24 @@ window.__ModuleLoader__.load({
3993
4071
  busy,
3994
4072
  canRecharge,
3995
4073
  onClose: () => {
4074
+ popupClick("close");
4075
+ setDialog(null);
4076
+ },
4077
+ onContinueSetup: () => {
4078
+ popupClick("setting");
3996
4079
  setDialog(null);
3997
4080
  },
3998
4081
  onContinue: () => {
4082
+ popupClick("know");
3999
4083
  setDialog(null);
4000
4084
  go("purpose");
4001
4085
  },
4002
- onRecharge: recharge,
4086
+ onRecharge: () => {
4087
+ popupClick("charge");
4088
+ recharge();
4089
+ },
4003
4090
  onSkip: () => {
4091
+ popupClick(dialog === "skip" ? "enter" : "know");
4004
4092
  complete("skipped").then(() => {
4005
4093
  setDialog(null);
4006
4094
  });
@@ -4125,7 +4213,7 @@ window.__ModuleLoader__.load({
4125
4213
  for (const listener of listeners) listener();
4126
4214
  };
4127
4215
  /** @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");
4216
+ const client = () => accountClientMetadata(ctx.locale.getSnapshot().active, "0.2.0-rc.1");
4129
4217
  const notices = createBonusNoticeController({
4130
4218
  ackRetryDelayMs: config.bonusAckRetryDelayMs,
4131
4219
  ackRetryMaxDelayMs: config.bonusAckRetryMaxDelayMs,
@@ -4255,14 +4343,33 @@ window.__ModuleLoader__.load({
4255
4343
  ...nativePlatform === void 0 ? {} : { openPlatformPage: platformPageOpener(refreshAccount) },
4256
4344
  refreshAccount,
4257
4345
  contactUs() {
4258
- const url = contactUrl(config, {
4259
- version: "0.1.7-rc.2",
4346
+ const profile = snapshot.details?.profile;
4347
+ const context = {
4348
+ uid: profile?.status === "ready" ? profile.value.id : null,
4349
+ version: "0.2.0-rc.1",
4260
4350
  locale: ctx.locale.getSnapshot().active === "zh" ? "zh-CN" : "en",
4261
4351
  width: window.screen.width,
4262
4352
  height: window.screen.height,
4263
4353
  pixelRatio: window.devicePixelRatio
4264
- });
4265
- window.open(url, "_blank", "noopener,noreferrer");
4354
+ };
4355
+ const openForm = (deviceInfo) => {
4356
+ window.open(contactUrl(config, {
4357
+ ...context,
4358
+ deviceInfo
4359
+ }), "_blank", "noopener,noreferrer");
4360
+ };
4361
+ const readDeviceInfo = globalThis.dshDesktop?.deviceInfo;
4362
+ if (readDeviceInfo === void 0) {
4363
+ openForm(navigator.userAgent);
4364
+ return;
4365
+ }
4366
+ (async () => {
4367
+ let deviceInfo = "";
4368
+ try {
4369
+ deviceInfo = await readDeviceInfo();
4370
+ } catch (_error) {}
4371
+ openForm(deviceInfo);
4372
+ })();
4266
4373
  },
4267
4374
  showLogin(visible) {
4268
4375
  publish({
@@ -4358,7 +4465,8 @@ window.__ModuleLoader__.load({
4358
4465
  ...nativePlatform === void 0 ? {} : { openPlatformPage: platformPageOpener(refresh) },
4359
4466
  update: (change) => controller.update(change),
4360
4467
  complete: (reason) => controller.complete(reason),
4361
- retry: () => controller.retry()
4468
+ retry: () => controller.retry(),
4469
+ track: (name, attributes) => ctx.get("productAnalytics")?.track(name, attributes)
4362
4470
  })
4363
4471
  }, DesktopOnboardingEntry));
4364
4472
  }
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;
@@ -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";
@@ -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.1",
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-client-locale": "0.2.0-rc.1",
55
+ "@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
56
+ "@deepseek-ai/dsh-client-test-runtime": "0.2.0-rc.1",
57
+ "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.1",
58
+ "@deepseek-ai/dsh-client-ui-chat": "0.2.0-rc.1",
59
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
60
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1",
61
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
62
+ "@deepseek-ai/dsh-client-ui-theme": "0.2.0-rc.1",
63
+ "@deepseek-ai/dsh-deepseek-account": "0.2.0-rc.1",
64
+ "@deepseek-ai/dsh-settings": "0.2.0-rc.1",
65
+ "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.1",
66
+ "@deepseek-ai/dsh-client-product-analytics": "0.2.0-rc.1",
67
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.1",
68
+ "@deepseek-ai/dsh-client-ui-layout": "0.2.0-rc.1",
69
+ "@deepseek-ai/dsh-client-ui-settings-models": "0.2.0-rc.1"
69
70
  },
70
71
  "files": [
71
72
  "lib/index.js",