dsh-mobile 0.6.9 → 0.6.10

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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  Notable changes are recorded here. GitHub Releases provide the downloadable packages and generated commit notes.
4
4
 
5
+ ## 0.6.10 - 2026-10-16
6
+
7
+ - Preserve the first Funnel failure and its validated official authorization URL instead of replacing them with a later process-exit error. Discard queued events from the failed connection while allowing an explicit reconnect to start a new one. Failed resource cleanup remains visible and can be retried without discarding owned resources.
8
+ - Keep unmapped remote-controller error codes visible in localized diagnostics instead of rendering an empty error description. Thanks @Anyways366 for the detailed report and reproduction in [#223](https://github.com/saya-ch/dsh-mobile/issues/223).
9
+ - Clarify that custom file drops need iterable file items as well as files, and that successful event dispatch is not confirmation that DSH added the attachment. Thanks @Void-LifeStream for the extension findings and follow-up verification in [#205](https://github.com/saya-ch/dsh-mobile/issues/205).
10
+ - Android App remains independently published as 0.6.4 (build 80); these plugin changes do not require another APK.
11
+
5
12
  ## 0.6.9 - 2026-10-15
6
13
 
7
14
  - Enable optional managed Caddy installation on Windows/Linux x64 with independently verified official component URLs, lengths and SHA-256 pins. Tencent Cloud DNSPod credentials, a domain and reachable public ingress are required; existing Cloudflared tunnels and external proxies remain available. Thanks @abworks-dev for the original managed-Caddy contributions in [#176](https://github.com/saya-ch/dsh-mobile/pull/176), [#184](https://github.com/saya-ch/dsh-mobile/pull/184), [#185](https://github.com/saya-ch/dsh-mobile/pull/185) and [#190](https://github.com/saya-ch/dsh-mobile/pull/190).
package/CONTRIBUTORS.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # 贡献者 / Contributors
2
2
 
3
- GitHub 的 [Contributors 图表](https://github.com/saya-ch/dsh-mobile/graphs/contributors) 按进入默认分支的提交自动统计,无法手动加入仅提交 issue 或 PR 提案的成员。本页按截至 2026-10-14 的实际参与方式感谢社区成员;仓库维护者与自动依赖更新仍可在 GitHub 历史记录中查看。
3
+ GitHub 的 [Contributors 图表](https://github.com/saya-ch/dsh-mobile/graphs/contributors) 按进入默认分支的提交自动统计,无法手动加入仅提交 issue 或 PR 提案的成员。本页按截至 2026-10-16 的实际参与方式感谢社区成员;仓库维护者与自动依赖更新仍可在 GitHub 历史记录中查看。
4
4
 
5
- GitHub's Contributors graph counts commits on the default branch; issue reports and PR proposals cannot be manually added to it. This page credits community members by how they contributed, through 2026-10-14. The repository maintainer and automated dependency updates remain visible in GitHub's history.
5
+ GitHub's Contributors graph counts commits on the default branch; issue reports and PR proposals cannot be manually added to it. This page credits community members by how they contributed, through 2026-10-16. The repository maintainer and automated dependency updates remain visible in GitHub's history.
6
6
 
7
7
  ## 0.6.7 代码贡献 / Code contributions in 0.6.7
8
8
 
@@ -64,6 +64,8 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
64
64
 
65
65
  ## 问题反馈与建议 / Issue reports and ideas
66
66
 
67
+ 感谢 [@Anyways366](https://github.com/Anyways366) 在 [#223](https://github.com/saya-ch/dsh-mobile/issues/223) 提供 Funnel 错误覆盖和诊断信息缺失的详细复现与修正建议。 / Thanks [@Anyways366](https://github.com/Anyways366) for the detailed Funnel error-overwrite and missing-diagnostic reproduction and proposed corrections in [#223](https://github.com/saya-ch/dsh-mobile/issues/223).
68
+
67
69
  感谢 [@Yurzi](https://github.com/Yurzi) 在 [#213](https://github.com/saya-ch/dsh-mobile/issues/213) 报告不同电脑的远程配对记录互相覆盖。 / Thanks [@Yurzi](https://github.com/Yurzi) for reporting remote pairing records on different computers overwriting one another in [#213](https://github.com/saya-ch/dsh-mobile/issues/213).
68
70
 
69
71
  感谢 [@Dantezcx](https://github.com/Dantezcx) 在 [#209](https://github.com/saya-ch/dsh-mobile/issues/209) 和 [#210](https://github.com/saya-ch/dsh-mobile/issues/210) 提供侧栏命中、短屏布局和定制资源加载的详细诊断。 / Thanks [@Dantezcx](https://github.com/Dantezcx) for the detailed sidebar hit-testing, short-viewport and customization-loading diagnostics in [#209](https://github.com/saya-ch/dsh-mobile/issues/209) and [#210](https://github.com/saya-ch/dsh-mobile/issues/210).
@@ -80,6 +82,7 @@ Thanks [@xhwxt](https://github.com/xhwxt) for the document-picker proposal in [#
80
82
  | [@2647954284](https://github.com/2647954284) | [#199](https://github.com/saya-ch/dsh-mobile/issues/199) |
81
83
  | [@abworks-dev](https://github.com/abworks-dev) | [#174](https://github.com/saya-ch/dsh-mobile/issues/174) |
82
84
  | [@Ann-luo](https://github.com/Ann-luo) | [#150](https://github.com/saya-ch/dsh-mobile/issues/150) |
85
+ | [@Anyways366](https://github.com/Anyways366) | [#223](https://github.com/saya-ch/dsh-mobile/issues/223) |
83
86
  | [@azri57806-design](https://github.com/azri57806-design) | [#97](https://github.com/saya-ch/dsh-mobile/issues/97) |
84
87
  | [@BrainZombie](https://github.com/BrainZombie) | [#128](https://github.com/saya-ch/dsh-mobile/issues/128) |
85
88
  | [@CESAEREE](https://github.com/CESAEREE) | [#1](https://github.com/saya-ch/dsh-mobile/issues/1) |
package/README.en.md CHANGED
@@ -25,13 +25,13 @@
25
25
  <a href="#security">Security</a> ·
26
26
  <a href="#compatibility">Compatibility</a> ·
27
27
  <a href="#contributors">Contributors</a> ·
28
- <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.9">Release notes</a> ·
28
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.10">Release notes</a> ·
29
29
  <a href="README.md">简体中文</a>
30
30
  </p>
31
31
 
32
32
  > DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
33
33
  >
34
- > **Current stable release: 0.6.9**. Enable optional managed Caddy installation on Windows/Linux x64, improve connection shutdown and component cleanup, and add custom-style troubleshooting guidance. Existing remote channels and pairings are retained; no Android app update is required. [Release notes and downloads](https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.9) · [Full changelog](CHANGELOG.md).
34
+ > **Current stable release: 0.6.10**. Preserve Tailscale Funnel's specific failure and authorization entry when its process exits, restore error codes and actionable guidance in all three diagnostic languages, and clarify extension file delivery. Existing remote channels and pairings are retained; no Android app update is required. [Release notes and downloads](https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.10) · [Full changelog](CHANGELOG.md).
35
35
  >
36
36
  > **Version policy**: since plugin **0.6.2**, the Android app and plugin use independent version numbers and releases. Their numbers do not need to match, and a plugin update does not imply an app update. [Compatibility notes](#compatibility).
37
37
 
@@ -226,6 +226,8 @@ Extension manifests, scripts, styles, and assets are revisioned. When the plugin
226
226
 
227
227
  An extension action's `input` may use a callable Schemastery schema such as `api.schema.object(...)` or an adapter with `parse(value)`; mobile `api.host.invoke()` sends JSON explicitly, and the input is validated and normalized before the computer-side action runs.
228
228
 
229
+ Prefer DSH's built-in file upload for attachments. If an extension must simulate a drop, its `dataTransfer` needs iterable `items` (file items) as well as `files`; a `files` array alone is insufficient. Some WebViews have incomplete native drag-and-drop constructors; see the [plugin's file-delivery implementation](src/native-mobile.ts) for compatibility handling. An accepted `dragover` or successfully dispatched event does not confirm attachment delivery: check the composer's attachments and previews.
230
+
229
231
  The 0.6.3 release adds optional [Worker execution](docs/EXTENSION_WORKERS.en.md) for trusted local JavaScript hosts. It is disabled by default, selectable by extension, and recovers explicitly without replaying interrupted actions. It is not a permission sandbox and does not require a matching App version.
230
232
 
231
233
  <sub>You can even use an extension to connect to SillyTavern running on the same computer, give it a lightweight mobile frontend, and open it from the same app.</sub>
package/README.md CHANGED
@@ -25,13 +25,13 @@
25
25
  <a href="#安全">安全</a> ·
26
26
  <a href="#兼容性">兼容性</a> ·
27
27
  <a href="#贡献者">贡献者</a> ·
28
- <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.9">更新记录</a> ·
28
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.10">更新记录</a> ·
29
29
  <a href="README.en.md">English</a>
30
30
  </p>
31
31
 
32
32
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
33
33
  >
34
- > **当前正式版本:0.6.9**。开放 Windows/Linux x64 的托管 Caddy 按需安装,改善连接停止与组件清理,并补充自定义样式排障建议。已有远程通道和配对保留,无需更新 Android App。[更新与下载](https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.9) · [完整更新记录](CHANGELOG.md)。
34
+ > **当前正式版本:0.6.10**。修复 Tailscale Funnel 的具体错误与授权入口被退出通知覆盖,补齐三语诊断中的错误码和操作说明,并完善扩展文件投递指南。已有远程通道和配对保留,无需更新 Android App。[更新与下载](https://github.com/saya-ch/dsh-mobile/releases/tag/v0.6.10) · [完整更新记录](CHANGELOG.md)。
35
35
  >
36
36
  > **版本说明**:自插件 **0.6.2** 起,Android App 与插件独立编号、独立发布,版本号无需一致;插件升级不代表 App 需要同步升级。[兼容说明](#兼容性)。
37
37
 
@@ -226,6 +226,8 @@ Funnel 的运行组件把公开监听生命周期绑定到父进程和受限控
226
226
 
227
227
  扩展动作的 `input` 可以直接使用 `api.schema.object(...)` 等 Schemastery schema,也可以使用带 `parse(value)` 的适配器;手机端 `api.host.invoke()` 会按 JSON 请求发送,输入会在电脑端动作执行前完成校验和规范化。
228
228
 
229
+ 附件功能优先复用 DSH 自带的文件上传。扩展若需模拟拖放,`dataTransfer` 除了 `files`,还须提供可迭代的 `items`(文件项列表),不能只拼一个 `files` 数组。部分 WebView 的原生拖放构造不完整,兼容处理可参考[插件内的文件投递实现](src/native-mobile.ts);`dragover` 接受或事件派发成功不代表附件已加入,应检查输入框中的附件与预览。
230
+
229
231
  0.6.3 新增可选的 [Worker 执行模式](docs/EXTENSION_WORKERS.md),用于约束可信本地扩展的 JavaScript 阻塞;默认关闭,按扩展选择,故障后显式恢复,不自动重放操作。这不是权限沙箱,也不要求 App 同步版本。
230
232
 
231
233
  <sub>你甚至可以通过扩展连接电脑上运行的酒馆,并从同一 App 打开它的简易移动前端。</sub>
package/lib/client.js CHANGED
@@ -7564,9 +7564,60 @@ window.__ModuleLoader__.load({
7564
7564
  /** Resolve the next-step text for a remote-controller diagnostic. */
7565
7565
  function diagnosticControllerAction(code, locale, fallback) {
7566
7566
  if (typeof code !== "string") return fallback;
7567
- const key = DIAGNOSTIC_CONTROLLER_ACTION_OVERRIDES[code] ?? (DIAGNOSTIC_CONTROLLER_ACTION_CODES.has(code) ? REMOTE_ERROR_MESSAGE_KEYS[code] : void 0);
7567
+ const key = (Object.prototype.hasOwnProperty.call(DIAGNOSTIC_CONTROLLER_ACTION_OVERRIDES, code) ? DIAGNOSTIC_CONTROLLER_ACTION_OVERRIDES[code] : void 0) ?? (DIAGNOSTIC_CONTROLLER_ACTION_CODES.has(code) ? REMOTE_ERROR_MESSAGE_KEYS[code] : void 0);
7568
7568
  return key === void 0 ? fallback : controlTranslator(locale)(key);
7569
7569
  }
7570
+ /**
7571
+ * Localize a diagnostic entry, retaining Host text for unknown diagnostic reasons.
7572
+ * @param entry Diagnostic fields received from the control API.
7573
+ * @param locale Language of the mounted control panel.
7574
+ * @param versions Optional version fields from the diagnostic response.
7575
+ * @returns Detail and next-step text shared by the visible card and copied report.
7576
+ */
7577
+ function localizedDiagnosticEntryCopy(entry, locale, versions) {
7578
+ const t = controlTranslator(locale);
7579
+ const localeTag = locale === "it" ? "it-IT" : locale === "zh" ? "zh-CN" : "en-US";
7580
+ const serverCopy = diagnosticServerCopy(entry);
7581
+ const reason = typeof entry.reason === "string" ? entry.reason : "";
7582
+ const facts = entry.facts !== null && typeof entry.facts === "object" ? entry.facts : {};
7583
+ const copyReason = facts.viaProxy === true && (reason === "remote-ready" || reason === "remote-rate-limited") ? `${reason}-via-proxy` : reason;
7584
+ const catalog = DIAGNOSTIC_REASON_MESSAGES[locale];
7585
+ const templates = Object.prototype.hasOwnProperty.call(catalog, copyReason) ? catalog[copyReason] : void 0;
7586
+ if (templates === void 0) return serverCopy;
7587
+ const providerNames = {
7588
+ tailscale: "Tailscale Funnel",
7589
+ cpolar: "cpolar",
7590
+ cloudflared: "cloudflared",
7591
+ frp: t("frpName"),
7592
+ origin: t("originName")
7593
+ };
7594
+ const providerId = typeof facts.provider === "string" ? facts.provider : "";
7595
+ const controllerCode = typeof facts.controllerCode === "string" ? facts.controllerCode : "";
7596
+ const controllerKey = Object.prototype.hasOwnProperty.call(REMOTE_ERROR_MESSAGE_KEYS, controllerCode) ? REMOTE_ERROR_MESSAGE_KEYS[controllerCode] : void 0;
7597
+ const values = {
7598
+ provider: providerNames[providerId] ?? "",
7599
+ latencyMs: typeof facts.latencyMs === "number" && Number.isFinite(facts.latencyMs) ? new Intl.NumberFormat(localeTag).format(facts.latencyMs) : "",
7600
+ interfaceName: typeof facts.interfaceName === "string" ? facts.interfaceName : "",
7601
+ endpointSuffix: typeof facts.endpointSuffix === "string" ? facts.endpointSuffix : "",
7602
+ controllerCode
7603
+ };
7604
+ const interpolate = (template) => template.replace(/\{(\w+)\}/gu, (_match, key) => values[key] ?? "");
7605
+ let detail = reason === "remote-controller-error" && controllerCode === "" ? t("remoteError") : interpolate(templates[0]);
7606
+ let action = interpolate(templates[1]);
7607
+ if (reason === "versions-current") {
7608
+ const fields = versions !== null && typeof versions === "object" ? versions : {};
7609
+ if ([
7610
+ fields.plugin,
7611
+ fields.dsh,
7612
+ fields.minimumAndroidApp
7613
+ ].every((value) => typeof value === "string")) detail += ` plugin ${String(fields.plugin)}, DSH ${String(fields.dsh)}, Android ${String(fields.minimumAndroidApp)}.`;
7614
+ }
7615
+ if (reason === "remote-controller-error") action = diagnosticControllerAction(controllerCode, locale, controllerKey === void 0 ? action : t(controllerKey));
7616
+ return {
7617
+ detail,
7618
+ action
7619
+ };
7620
+ }
7570
7621
  function installControl() {
7571
7622
  /** The table above, translated, for the status repaint. */
7572
7623
  const translatedRemoteErrors = () => Object.fromEntries(Object.entries(REMOTE_ERROR_MESSAGE_KEYS).map(([code, key]) => [code, t(key)]));
@@ -10697,46 +10748,7 @@ window.__ModuleLoader__.load({
10697
10748
  "phone-network": "diagnosticLabelPhone"
10698
10749
  };
10699
10750
  const statusOf = (entry) => normalizeDiagnosticStatus(entry.status);
10700
- const localizedEntryCopy = (entry) => {
10701
- const serverCopy = diagnosticServerCopy(entry);
10702
- const reason = typeof entry.reason === "string" ? entry.reason : "";
10703
- const facts = entry.facts !== null && typeof entry.facts === "object" ? entry.facts : {};
10704
- const copyReason = facts.viaProxy === true && (reason === "remote-ready" || reason === "remote-rate-limited") ? `${reason}-via-proxy` : reason;
10705
- const templates = DIAGNOSTIC_REASON_MESSAGES[locale][copyReason];
10706
- if (templates === void 0) return serverCopy;
10707
- const providerNames = {
10708
- tailscale: "Tailscale Funnel",
10709
- cpolar: "cpolar",
10710
- cloudflared: "cloudflared",
10711
- frp: t("frpName"),
10712
- origin: t("originName")
10713
- };
10714
- const providerId = typeof facts.provider === "string" ? facts.provider : "";
10715
- const controllerKey = typeof facts.controllerCode === "string" ? REMOTE_ERROR_MESSAGE_KEYS[facts.controllerCode] : void 0;
10716
- const values = {
10717
- provider: providerNames[providerId] ?? "",
10718
- latencyMs: typeof facts.latencyMs === "number" && Number.isFinite(facts.latencyMs) ? new Intl.NumberFormat(localeTag).format(facts.latencyMs) : "",
10719
- interfaceName: typeof facts.interfaceName === "string" ? facts.interfaceName : "",
10720
- endpointSuffix: typeof facts.endpointSuffix === "string" ? facts.endpointSuffix : "",
10721
- controllerCode: controllerKey === void 0 ? "" : t(controllerKey)
10722
- };
10723
- const interpolate = (template) => template.replace(/\{(\w+)\}/gu, (_match, key) => values[key] ?? "");
10724
- let detail = interpolate(templates[0]);
10725
- let action = interpolate(templates[1]);
10726
- if (reason === "versions-current") {
10727
- const versions = data.versions !== null && typeof data.versions === "object" ? data.versions : {};
10728
- if ([
10729
- versions.plugin,
10730
- versions.dsh,
10731
- versions.minimumAndroidApp
10732
- ].every((value) => typeof value === "string")) detail += ` plugin ${String(versions.plugin)}, DSH ${String(versions.dsh)}, Android ${String(versions.minimumAndroidApp)}.`;
10733
- }
10734
- if (reason === "remote-controller-error") action = diagnosticControllerAction(facts.controllerCode, locale, action);
10735
- return {
10736
- detail,
10737
- action
10738
- };
10739
- };
10751
+ const localizedEntryCopy = (entry) => localizedDiagnosticEntryCopy(entry, locale, data.versions);
10740
10752
  const appendGroup = (label, groupEntries) => {
10741
10753
  if (groupEntries.length === 0) return;
10742
10754
  const group = element("section", "dsh-mobile-control__diagnostic-group");
@@ -12368,6 +12380,7 @@ window.__ModuleLoader__.load({
12368
12380
  exports.installCustomAssets = installCustomAssets;
12369
12381
  exports.installDshLanguageBoundSurface = installDshLanguageBoundSurface;
12370
12382
  exports.installMobileNativeBack = installMobileNativeBack;
12383
+ exports.localizedDiagnosticEntryCopy = localizedDiagnosticEntryCopy;
12371
12384
  exports.mobileBackBlockedMessage = mobileBackBlockedMessage;
12372
12385
  exports.normalizeDiagnosticOverall = normalizeDiagnosticOverall;
12373
12386
  exports.normalizeDiagnosticStatus = normalizeDiagnosticStatus;