better-dsh 0.0.0 → 0.2.2-a

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.
Files changed (142) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +294 -4
  3. package/control-prompt.md +37 -0
  4. package/cordis.patch.yml +53 -0
  5. package/docs/00_adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
  6. package/docs/00_adr/0002-masking-is-presentation-only.md +15 -0
  7. package/docs/10_plans/A2A-messaging-channel-test-archive.md +256 -0
  8. package/docs/10_plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
  9. package/docs/10_plans/dashr-blueprint-review.md +201 -0
  10. package/docs/10_plans/dashr-blueprint.md +561 -0
  11. package/docs/10_plans/dashr-compaction-window-and-archive.md +307 -0
  12. package/docs/10_plans/dashr-profile-layer-feasibility.md +367 -0
  13. package/docs/10_plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
  14. package/docs/10_plans/dashr-security-sandbox-analysis.md +187 -0
  15. package/docs/10_plans/dashr-surface-invariant-and-omp-imports.md +97 -0
  16. package/docs/10_plans/ipython-kernel-interactive-interface-test-report.md +152 -0
  17. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
  18. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
  19. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
  20. package/docs/10_plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
  21. package/docs/10_plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
  22. package/docs/10_plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
  23. package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
  24. package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
  25. package/docs/10_plans/recallable-compaction.md +147 -0
  26. package/docs/10_plans/spike-tag-repro.mjs +102 -0
  27. package/docs/10_plans/upstream-analysis.md +128 -0
  28. package/docs/50_test-reports/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
  29. package/docs/50_test-reports/kernel-provisioning.md +44 -0
  30. package/docs/50_test-reports/repl-kernel-provisioning-test-report.md +87 -0
  31. package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-local-test-report.md +81 -0
  32. package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-report.md +93 -0
  33. package/docs/50_test-reports/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
  34. package/docs/50_test-reports/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
  35. package/docs/50_test-reports/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
  36. package/docs/50_test-reports/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
  37. package/docs/50_test-reports/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
  38. package/docs/50_test-reports/v0.1.8d_artifacts/README.md +138 -0
  39. package/docs/50_test-reports/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
  40. package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
  41. package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
  42. package/docs/50_test-reports/v0.1.8d_artifacts/functions.json +592 -0
  43. package/docs/50_test-reports/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
  44. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
  45. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
  46. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
  47. package/docs/50_test-reports/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
  48. package/docs/50_test-reports/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
  49. package/docs/50_test-reports/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
  50. package/docs/50_test-reports/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
  51. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
  52. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
  53. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
  54. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
  55. package/docs/50_test-reports/v0.2.0b_artifacts/hashline-probe.md +5 -0
  56. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
  57. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
  58. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
  59. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
  60. package/docs/50_test-reports/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
  61. package/docs/50_test-reports/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
  62. package/docs/50_test-reports/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
  63. package/docs/50_test-reports/v0.2.1d-/345/256/236/346/265/213/346/212/245/345/221/212.md +67 -0
  64. package/docs/50_test-reports/v0.2.1e-P1-/345/256/236/346/265/213/346/212/245/345/221/212.md +136 -0
  65. package/docs/50_test-reports/v0.2.1ef-dev-audit-report.md +73 -0
  66. package/docs/50_test-reports/v0.2.1f-plugin-shipped-ui-patches/345/256/236/346/265/213/346/212/245/345/221/212.md +102 -0
  67. package/docs/60_exploration-and-research/cordis-research.md +350 -0
  68. package/docs/60_exploration-and-research/dsh-web-profile-package-map.md +186 -0
  69. package/docs/60_exploration-and-research/dsh-web-ui-slot-system-research.md +310 -0
  70. package/docs/60_exploration-and-research/dsh-webui-strip-boundary-research.md +300 -0
  71. package/docs/60_exploration-and-research/ios-chat-app-bridge-research.md +324 -0
  72. package/docs/60_exploration-and-research/web-frontend-composability-research.md +191 -0
  73. package/docs/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
  74. package/docs/adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
  75. package/docs/adr/0002-masking-is-presentation-only.md +15 -0
  76. package/docs/distro-blueprint.md +81 -0
  77. package/docs/dsh-webUI-with-rlm-mode.png +0 -0
  78. package/docs/plans/A2A-messaging-channel-test-archive.md +256 -0
  79. package/docs/plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
  80. package/docs/plans/dashr-blueprint-review.md +201 -0
  81. package/docs/plans/dashr-blueprint.md +561 -0
  82. package/docs/plans/dashr-compaction-window-and-archive.md +307 -0
  83. package/docs/plans/dashr-profile-layer-feasibility.md +367 -0
  84. package/docs/plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
  85. package/docs/plans/dashr-security-sandbox-analysis.md +187 -0
  86. package/docs/plans/dashr-surface-invariant-and-omp-imports.md +97 -0
  87. package/docs/plans/ipython-kernel-interactive-interface-test-report.md +152 -0
  88. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
  89. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
  90. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
  91. package/docs/plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
  92. package/docs/plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
  93. package/docs/plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
  94. package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
  95. package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
  96. package/docs/plans/recallable-compaction.md +147 -0
  97. package/docs/plans/spike-tag-repro.mjs +102 -0
  98. package/docs/plans/upstream-analysis.md +128 -0
  99. package/docs/repositioning-and-rebranding.md +102 -0
  100. package/docs/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
  101. package/docs/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
  102. package/docs/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
  103. package/docs/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
  104. package/docs/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
  105. package/docs/v0.1.8d_artifacts/README.md +138 -0
  106. package/docs/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
  107. package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
  108. package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
  109. package/docs/v0.1.8d_artifacts/functions.json +592 -0
  110. package/docs/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
  111. package/docs/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
  112. package/docs/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
  113. package/docs/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
  114. package/docs/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
  115. package/docs/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
  116. package/docs/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
  117. package/docs/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
  118. package/docs/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
  119. package/docs/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
  120. package/docs/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
  121. package/docs/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
  122. package/docs/v0.2.0b_artifacts/hashline-probe.md +5 -0
  123. package/docs/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
  124. package/docs/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
  125. package/docs/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
  126. package/docs/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
  127. package/docs/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
  128. package/docs/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
  129. package/docs/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
  130. package/lib/client/index.js +473 -0
  131. package/lib/index.d.ts +736 -0
  132. package/lib/index.js +11518 -0
  133. package/lib/kernel-env-hxaihi9C.js +195 -0
  134. package/lib/kernel-env.d.ts +80 -0
  135. package/lib/kernel-env.js +3 -0
  136. package/lib/py-sdk-BCaOGYz7.d.ts +125 -0
  137. package/lib/py-sdk-CbgYiX8O.js +691 -0
  138. package/lib/py-sdk.d.ts +2 -0
  139. package/lib/py-sdk.js +3 -0
  140. package/package.json +325 -4
  141. package/scripts/kernel-provision.mjs +35 -0
  142. package/index.js +0 -3
@@ -0,0 +1,473 @@
1
+ window.__ModuleLoader__.load({ id: "better-dsh", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ //#region rolldown:runtime
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
21
+ value: mod,
22
+ enumerable: true
23
+ }) : target, mod));
24
+
25
+ //#endregion
26
+ let react = require("react");
27
+ react = __toESM(react);
28
+ let react_jsx_runtime = require("react/jsx-runtime");
29
+ react_jsx_runtime = __toESM(react_jsx_runtime);
30
+
31
+ //#region src/failover/config.ts
32
+ /**
33
+ * The `failover` general-fallback config (host-plane, per-turn latch).
34
+ *
35
+ * Pure module — no `@deepseek-ai/*` value imports, so both the host module and
36
+ * the client half may import it (the client type-only) without dragging a host
37
+ * runtime dependency into the browser bundle.
38
+ *
39
+ * A route is a `provider/model` string (e.g. `deepseek/deepseek-v4-flash`).
40
+ * The empty string `''` means "not set" — the slot is skipped.
41
+ *
42
+ * @module dashr/failover/config
43
+ */
44
+ /** The settings namespace the General row reads and writes. */
45
+ const FAILOVER_SETTINGS_NS = "failover";
46
+
47
+ //#endregion
48
+ //#region src/failover/client/locales.ts
49
+ /**
50
+ * Client locale dictionary for the failover General row.
51
+ * @module dashr/failover/client/locales
52
+ */
53
+ const NS = "failover";
54
+ const en = {
55
+ "title": "Model failover",
56
+ "fallback1": "Fallback 1",
57
+ "fallback2": "Fallback 2",
58
+ "not-set": "— not set —",
59
+ "loading": "Loading…",
60
+ "error": "Save failed: {{message}}"
61
+ };
62
+ const zh = {
63
+ "title": "模型故障转移",
64
+ "fallback1": "备用模型 1",
65
+ "fallback2": "备用模型 2",
66
+ "not-set": "— 不设置 —",
67
+ "loading": "加载中…",
68
+ "error": "保存失败:{{message}}"
69
+ };
70
+
71
+ //#endregion
72
+ //#region \0dsh-css:/home/u1/workspaces/dashr/dashr/src/failover/client/FailoverRow.module.css.mjs
73
+ const css = "._440e1d7b_row {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px 0;\n}\n\n._9865b509_title {\n font-weight: 600;\n font-size: 14px;\n}\n\n._3cfec826_slots {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n._70954771_slot {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n._ba1fd839_slotLabel {\n min-width: 88px;\n flex-shrink: 0;\n font-size: 13px;\n color: var(--dsw-alias-text-secondary, #666);\n}\n\n._11c2662d_select {\n flex: 1;\n max-width: 280px;\n min-width: 0;\n}\n\n._b7c358f9_alert {\n color: var(--dsw-alias-danger, #c0392b);\n font-size: 12px;\n}\n";
74
+ const tagId = "better-dsh/FailoverRow.module.css";
75
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
76
+ const tag = document.createElement("style");
77
+ tag.dataset.plugin = "better-dsh";
78
+ tag.dataset.pluginCss = tagId;
79
+ tag.textContent = css;
80
+ document.head.appendChild(tag);
81
+ }
82
+ var FailoverRow_module_css_default = {
83
+ "row": "_440e1d7b_row",
84
+ "title": "_9865b509_title",
85
+ "slots": "_3cfec826_slots",
86
+ "slot": "_70954771_slot",
87
+ "slotLabel": "_ba1fd839_slotLabel",
88
+ "select": "_11c2662d_select",
89
+ "alert": "_b7c358f9_alert"
90
+ };
91
+
92
+ //#endregion
93
+ //#region src/failover/client/FailoverRow.tsx
94
+ /** Render the failover row: title + two model selectors. */
95
+ function FailoverRow({ catalog, loadConfig, save, t }) {
96
+ const [loaded, setLoaded] = (0, react.useState)(null);
97
+ const [error, setError] = (0, react.useState)(null);
98
+ const [saving, setSaving] = (0, react.useState)(false);
99
+ (0, react.useEffect)(() => {
100
+ let alive = true;
101
+ (async () => {
102
+ try {
103
+ const [routes$1, cfg] = await Promise.all([catalog(), loadConfig()]);
104
+ if (!alive) return;
105
+ setLoaded({
106
+ routes: routes$1,
107
+ config: cfg ?? {
108
+ fallback1: "",
109
+ fallback2: ""
110
+ },
111
+ revision: cfg?.revision
112
+ });
113
+ } catch (err) {
114
+ if (alive) setError(err instanceof Error ? err.message : String(err));
115
+ }
116
+ })();
117
+ return () => {
118
+ alive = false;
119
+ };
120
+ }, [catalog, loadConfig]);
121
+ const select = async (slot, value) => {
122
+ if (loaded === null || saving) return;
123
+ setSaving(true);
124
+ setError(null);
125
+ try {
126
+ const nextRevision = await save({ [slot]: value }, loaded.revision);
127
+ setLoaded({
128
+ ...loaded,
129
+ config: {
130
+ ...loaded.config,
131
+ [slot]: value
132
+ },
133
+ revision: nextRevision
134
+ });
135
+ } catch (err) {
136
+ setError(err instanceof Error ? err.message : String(err));
137
+ } finally {
138
+ setSaving(false);
139
+ }
140
+ };
141
+ const routes = loaded?.routes ?? [];
142
+ const renderSelect = (slot, label) => {
143
+ const value = loaded?.config[slot] ?? "";
144
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
145
+ className: FailoverRow_module_css_default.slot,
146
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
147
+ className: FailoverRow_module_css_default.slotLabel,
148
+ children: label
149
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
150
+ className: FailoverRow_module_css_default.select,
151
+ value,
152
+ disabled: saving || loaded === null,
153
+ onChange: (event) => {
154
+ select(slot, event.target.value);
155
+ },
156
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
157
+ value: "",
158
+ children: t("not-set")
159
+ }), routes.map((route) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
160
+ value: route,
161
+ children: route
162
+ }, route))]
163
+ })]
164
+ });
165
+ };
166
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
167
+ className: FailoverRow_module_css_default.row,
168
+ children: [
169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
170
+ className: FailoverRow_module_css_default.title,
171
+ children: t("title")
172
+ }),
173
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
174
+ className: FailoverRow_module_css_default.alert,
175
+ role: "alert",
176
+ children: t("error", { message: error })
177
+ }) : null,
178
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
179
+ className: FailoverRow_module_css_default.slots,
180
+ children: [renderSelect("fallback1", t("fallback1")), renderSelect("fallback2", t("fallback2"))]
181
+ })
182
+ ]
183
+ });
184
+ }
185
+
186
+ //#endregion
187
+ //#region src/mobile/gesture.ts
188
+ /**
189
+ * Resolved defaults — the `1706b81` constants (120 / viewport÷4 / 40 / 1.3 /
190
+ * 768) plus the one addition, the velocity gate. A slow text-selection drag
191
+ * runs ~0.13 px/ms; 0.15 px/ms filters those while any comfortable sweep
192
+ * (0.4 px/ms and up) passes.
193
+ */
194
+ const DEFAULT_SWIPE_THRESHOLDS = {
195
+ breakpoint: 768,
196
+ swipeDistancePx: 40,
197
+ dominanceRatio: 1.3,
198
+ leftEdgeBandPx: 120,
199
+ rightZoneRatio: .25,
200
+ swipeVelocityPxPerMs: .15
201
+ };
202
+ /**
203
+ * Whether one completed gesture's viewport is in the gesture band.
204
+ *
205
+ * @param viewportWidth - viewport width at gesture time (px).
206
+ * @param thresholds - resolved recognition thresholds (`.breakpoint`).
207
+ * @returns `true` when `viewportWidth` is strictly below the breakpoint.
208
+ */
209
+ function isNarrowViewport(viewportWidth, thresholds) {
210
+ return viewportWidth < thresholds.breakpoint;
211
+ }
212
+ /**
213
+ * Whether a pointerdown may START a gesture — the source's pointerdown
214
+ * gate, verbatim: with both panels closed, only the left band (X120) or
215
+ * the right three quarters of the screen admit; with a panel open, any
216
+ * position admits (that swipe is a dismiss).
217
+ *
218
+ * @param x - pointerdown client X.
219
+ * @param viewportWidth - viewport width at gesture time (px).
220
+ * @param panels - panel state at pointerdown.
221
+ * @param thresholds - resolved recognition thresholds.
222
+ * @returns `true` when the origin is admitted into tracking.
223
+ */
224
+ function admitsSwipeStart(x, viewportWidth, panels, thresholds) {
225
+ if (!(panels.leftCollapsed && !panels.rightOpen)) return true;
226
+ return x <= thresholds.leftEdgeBandPx || x >= viewportWidth * thresholds.rightZoneRatio;
227
+ }
228
+ /**
229
+ * Classify one in-flight drag into a panel action — the source's
230
+ * pointermove decision, verbatim, plus the velocity gate. Callers fire
231
+ * ONCE (then drop the drag): a `null` here means "not yet / not this
232
+ * gesture", and the same drag may classify on a LATER move event as its
233
+ * displacement or velocity grows.
234
+ *
235
+ * @param progress - the drag's displacement and elapsed time so far.
236
+ * @param panels - panel state read live at this event.
237
+ * @param sessionLive - whether a session is current (gates opening the
238
+ * right panel, mirroring the source's `detailsSession !== undefined`).
239
+ * @param thresholds - resolved recognition thresholds.
240
+ * @returns the action the drag maps to, or `null` when no panel admits
241
+ * it yet.
242
+ */
243
+ function classifySwipeProgress(progress, panels, sessionLive, thresholds) {
244
+ const adx = Math.abs(progress.dx);
245
+ const ady = Math.abs(progress.dy);
246
+ if (adx < thresholds.swipeDistancePx) return null;
247
+ if (adx <= ady * thresholds.dominanceRatio) return null;
248
+ if (thresholds.swipeVelocityPxPerMs > 0) {
249
+ if (progress.dtMs <= 0) return null;
250
+ if (adx / progress.dtMs < thresholds.swipeVelocityPxPerMs) return null;
251
+ }
252
+ if (progress.dx < 0) {
253
+ if (!panels.leftCollapsed) return "close-left";
254
+ if (sessionLive && !panels.rightOpen) return "open-right";
255
+ return null;
256
+ }
257
+ if (panels.rightOpen) return "close-right";
258
+ if (panels.leftCollapsed) return "open-left";
259
+ return null;
260
+ }
261
+ /**
262
+ * Merge the host-injected page config over the defaults. An absent config
263
+ * (host feature off, or an old cached page) resolves to enabled=false — the
264
+ * client half is inert unless the host opted the page in.
265
+ *
266
+ * @param pageConfig - `window.__DASHR_MOBILE__` as left by the boot script.
267
+ * @returns resolved thresholds plus the enable flag.
268
+ */
269
+ function resolveMobileConfig(pageConfig) {
270
+ if (pageConfig === void 0 || pageConfig.enabled !== true) return {
271
+ enabled: false,
272
+ ...DEFAULT_SWIPE_THRESHOLDS
273
+ };
274
+ const n = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
275
+ const v = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
276
+ return {
277
+ enabled: true,
278
+ breakpoint: n(pageConfig.breakpoint, DEFAULT_SWIPE_THRESHOLDS.breakpoint),
279
+ swipeDistancePx: n(pageConfig.swipeDistancePx, DEFAULT_SWIPE_THRESHOLDS.swipeDistancePx),
280
+ dominanceRatio: n(pageConfig.dominanceRatio, DEFAULT_SWIPE_THRESHOLDS.dominanceRatio),
281
+ leftEdgeBandPx: n(pageConfig.leftEdgeBandPx, DEFAULT_SWIPE_THRESHOLDS.leftEdgeBandPx),
282
+ rightZoneRatio: n(pageConfig.rightZoneRatio, DEFAULT_SWIPE_THRESHOLDS.rightZoneRatio),
283
+ swipeVelocityPxPerMs: v(pageConfig.swipeVelocityPxPerMs, DEFAULT_SWIPE_THRESHOLDS.swipeVelocityPxPerMs)
284
+ };
285
+ }
286
+
287
+ //#endregion
288
+ //#region src/mobile/client/index.ts
289
+ /** Left sidebar state, live off AppFrame's semantic attribute. */
290
+ function readLeftCollapsed() {
291
+ return document.querySelector("[data-sidebar-collapsed]") !== null;
292
+ }
293
+ /**
294
+ * Better Sidebar's right-panel state, live off the body attribute the
295
+ * plugin itself publishes (collapsed = closed). Read SYNCHRONOUSLY in the
296
+ * handlers — a cached mirror lags the panel's own DOM write by a render,
297
+ * and a close-swipe issued right after an open-swipe would misroute.
298
+ */
299
+ function readRightOpen() {
300
+ return !document.body.hasAttribute("data-dsh-sidebar-collapsed");
301
+ }
302
+ /**
303
+ * Whether a session is current — the plugin-side stand-in for the source's
304
+ * `detailsSession !== undefined` guard (the right panel opens in a session
305
+ * only). Better Sidebar's own shipped CSS keys off the same slot selector,
306
+ * so it is load-bearing beyond this feature.
307
+ */
308
+ function readSessionLive() {
309
+ return document.querySelector("[data-slot=\"conversation.session.header\"]") !== null;
310
+ }
311
+ /** Panel state snapshot, both sources live. */
312
+ function readPanelState() {
313
+ return {
314
+ leftCollapsed: readLeftCollapsed(),
315
+ rightOpen: readRightOpen()
316
+ };
317
+ }
318
+ /**
319
+ * Toggle Better Sidebar's right panel through its persistent DOM: the
320
+ * plugin exposes no JS toggle on its client service (its open/close
321
+ * reducer is store-internal), so the swipe reaches it the same way the
322
+ * source did — clicking the LAST button of its always-rendered
323
+ * `[data-dsh-toggle-cluster]` (the bottom-panel button precedes it and is
324
+ * absent below the plugin's 768px narrow breakpoint). Absent cluster or
325
+ * buttons: a no-op, never a crash.
326
+ */
327
+ function toggleBetterSidebar() {
328
+ const buttons = document.querySelector("[data-dsh-toggle-cluster]")?.querySelectorAll("button");
329
+ (buttons?.[buttons.length - 1])?.click();
330
+ }
331
+ /**
332
+ * The narrow-viewport CSS: zero-width sidebar track under the breakpoint,
333
+ * keyed to AppFrame's semantic attribute (survives class-hash churn).
334
+ * Rendered with the breakpoint baked in (media queries cannot read JS
335
+ * config); the tag carries the plugin-owned dataset so the loader's
336
+ * style-claim machinery removes it on unload, like module CSS.
337
+ */
338
+ function mobileCss(breakpointPx) {
339
+ const wide = Math.max(1, Math.floor(breakpointPx) - .02);
340
+ return [
341
+ `@media (max-width: ${String(wide)}px) {`,
342
+ ` [data-sidebar-collapsed] {`,
343
+ ` grid-template-columns: 0px minmax(0, 1fr) 0px !important;`,
344
+ ` }`,
345
+ `}`
346
+ ].join("\n");
347
+ }
348
+ /**
349
+ * Mount the mobile feature: style injection plus the swipe listeners.
350
+ * Inert unless the host's boot script opted the page in.
351
+ *
352
+ * @param ctx - client root context.
353
+ * @returns the effect disposer (style tag + listeners removed on unload).
354
+ */
355
+ function setupMobileLayout(ctx) {
356
+ const pageConfig = globalThis.__DASHR_MOBILE__;
357
+ const config = resolveMobileConfig(pageConfig);
358
+ if (!config.enabled) return;
359
+ const styleTagId = "better-dsh/mobile";
360
+ ctx.effect(() => {
361
+ const tag = document.createElement("style");
362
+ tag.dataset.plugin = "better-dsh";
363
+ tag.dataset.pluginCss = styleTagId;
364
+ tag.textContent = mobileCss(config.breakpoint);
365
+ document.head.append(tag);
366
+ const offLayout = ctx.inject(["layout"], (layoutCtx) => {
367
+ const layout = layoutCtx.get("layout");
368
+ if (layout === void 0) return;
369
+ let start;
370
+ const onPointerDown = (event) => {
371
+ start = void 0;
372
+ const viewport = window.innerWidth;
373
+ if (!isNarrowViewport(viewport, config)) return;
374
+ if (!admitsSwipeStart(event.clientX, viewport, readPanelState(), config)) return;
375
+ start = {
376
+ x: event.clientX,
377
+ y: event.clientY,
378
+ t: event.timeStamp
379
+ };
380
+ };
381
+ const onPointerMove = (event) => {
382
+ const origin = start;
383
+ if (origin === void 0) return;
384
+ const action = classifySwipeProgress({
385
+ dx: event.clientX - origin.x,
386
+ dy: event.clientY - origin.y,
387
+ dtMs: event.timeStamp - origin.t
388
+ }, readPanelState(), readSessionLive(), config);
389
+ if (action === null) return;
390
+ start = void 0;
391
+ if (action === "open-left" || action === "close-left") layout.toggleSidebar();
392
+ else toggleBetterSidebar();
393
+ };
394
+ const onPointerEnd = () => {
395
+ start = void 0;
396
+ };
397
+ document.addEventListener("pointerdown", onPointerDown, true);
398
+ document.addEventListener("pointermove", onPointerMove, true);
399
+ document.addEventListener("pointerup", onPointerEnd, true);
400
+ document.addEventListener("pointercancel", onPointerEnd, true);
401
+ return () => {
402
+ document.removeEventListener("pointerdown", onPointerDown, true);
403
+ document.removeEventListener("pointermove", onPointerMove, true);
404
+ document.removeEventListener("pointerup", onPointerEnd, true);
405
+ document.removeEventListener("pointercancel", onPointerEnd, true);
406
+ };
407
+ });
408
+ return () => {
409
+ tag.remove();
410
+ Promise.resolve(offLayout.dispose());
411
+ };
412
+ }, "dashr: mobile layout");
413
+ }
414
+
415
+ //#endregion
416
+ //#region src/failover/client/index.ts
417
+ /** Required services (cordis fiber inject). */
418
+ const inject = [
419
+ "slots",
420
+ "locale",
421
+ "remote",
422
+ "remote.settings",
423
+ "remote.session"
424
+ ];
425
+ /**
426
+ * Register the `failover` dictionaries and the General settings row.
427
+ * @param ctx - client root context.
428
+ */
429
+ function apply(ctx) {
430
+ ctx.effect(() => ctx.locale.register(NS, {
431
+ zh,
432
+ en
433
+ }), "llm-failover: dictionaries");
434
+ setupMobileLayout(ctx);
435
+ ctx.slots.inject("settings.general.item", function* () {
436
+ yield ctx.slots.register({
437
+ name: "settings.general.item",
438
+ id: "failover",
439
+ order: 100,
440
+ locale: NS,
441
+ inject: () => ({
442
+ catalog: async () => {
443
+ const response = await ctx.remote.session.modelCatalog();
444
+ if (!response.ok) throw new Error(`${response.error.code}: ${response.error.message}`);
445
+ return response.value.groups.flatMap((group) => group.models.map((model) => `${group.id}/${model.id}`));
446
+ },
447
+ loadConfig: async () => {
448
+ const response = await ctx.remote.settings.describe();
449
+ if (!response.ok) throw new Error(`${response.error.code}: ${response.error.message}`);
450
+ const view = response.value.namespaces.find((entry) => entry.ns === FAILOVER_SETTINGS_NS);
451
+ if (view === void 0) return null;
452
+ const value = view.value;
453
+ return {
454
+ fallback1: typeof value.fallback1 === "string" ? value.fallback1 : "",
455
+ fallback2: typeof value.fallback2 === "string" ? value.fallback2 : "",
456
+ revision: view.revision
457
+ };
458
+ },
459
+ save: async (patch, revision) => {
460
+ const response = await ctx.remote.settings.update(FAILOVER_SETTINGS_NS, patch, revision);
461
+ if (!response.ok) throw new Error(`${response.error.code}: ${response.error.message}`);
462
+ return response.value.revision;
463
+ }
464
+ })
465
+ }, FailoverRow);
466
+ });
467
+ }
468
+
469
+ //#endregion
470
+ exports.FailoverRow = FailoverRow;
471
+ exports.apply = apply;
472
+ exports.inject = inject;
473
+ return module.exports; } });