dsh-workbuddy-bridge 0.3.0 → 0.4.0
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.md +17 -14
- package/README_en.md +22 -19
- package/lib/bin.js +8 -7
- package/lib/client.js +669 -408
- package/lib/{variants-3SmUZ0e_.js → heartbeat-CP6YM98x.js} +137 -104
- package/lib/index.d.ts +12 -3
- package/lib/index.js +90 -10
- package/package.json +14 -13
- package/locale/README.md +0 -10
package/lib/client.js
CHANGED
|
@@ -31,16 +31,6 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
timeStyle: "short"
|
|
32
32
|
}).format(new Date(ms));
|
|
33
33
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Locale-formatted cycle-reset time, falling back to the wire string.
|
|
36
|
-
*
|
|
37
|
-
* The host forwards the upstream's own timestamp; when it is not a date this
|
|
38
|
-
* plugin can parse, the raw text is still more useful than nothing.
|
|
39
|
-
*/
|
|
40
|
-
function formatCycleReset(time) {
|
|
41
|
-
const parsed = Date.parse(time);
|
|
42
|
-
return Number.isNaN(parsed) ? time : formatTime(parsed);
|
|
43
|
-
}
|
|
44
34
|
/** Locale-formatted percentage, at most one fraction digit. */
|
|
45
35
|
function formatPercent(percent) {
|
|
46
36
|
return new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(percent);
|
|
@@ -65,52 +55,115 @@ window.__ModuleLoader__.load({
|
|
|
65
55
|
return credit.toFixed(2).replace(/\.?0+$/u, "");
|
|
66
56
|
}
|
|
67
57
|
//#endregion
|
|
68
|
-
//#region \0workbuddy-css
|
|
69
|
-
const css$
|
|
70
|
-
const tagId$
|
|
71
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
58
|
+
//#region \0workbuddy-css:D:\ProjectSomething\dsh-plugins\dsh-workbuddy-bridge\src\client\workbuddy.module.css.js
|
|
59
|
+
const css$4 = "._1kHyqG_page,._1kHyqG_cards{flex-direction:column;gap:12px;display:flex}._1kHyqG_toggleRow{border-top:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;padding:12px 0;font-size:13px;line-height:1.5;display:flex}._1kHyqG_toggleLabel{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}._1kHyqG_toggleHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}._1kHyqG_body{flex-direction:column;gap:12px;padding:4px 0 12px;display:flex}._1kHyqG_section{flex-direction:column;display:flex}._1kHyqG_section>*+*{margin-top:12px}._1kHyqG_cardActions{align-items:center;gap:8px;display:flex}._1kHyqG_field{flex-direction:column;gap:6px;display:flex}._1kHyqG_head{align-items:center;gap:8px;display:flex}._1kHyqG_main{flex-wrap:wrap;flex:1;align-items:baseline;gap:8px;min-width:0;display:flex}._1kHyqG_action{flex:none;align-items:center;gap:8px;display:inline-flex}._1kHyqG_note{flex-wrap:wrap;align-items:baseline;gap:8px;min-width:0;display:flex}._1kHyqG_part{flex-wrap:wrap;align-items:baseline;gap:8px;min-width:0;font-size:13px;line-height:1.5;display:inline-flex}._1kHyqG_caption{color:var(--dsw-alias-label-tertiary)}._1kHyqG_figure{min-width:0;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;align-items:baseline;gap:6px;font-weight:500;display:inline-flex}._1kHyqG_sectionActions{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;gap:8px;padding-top:10px;display:flex}._1kHyqG_title{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:500;line-height:1.5}._1kHyqG_summaryRow{flex-wrap:wrap;gap:4px;height:auto;min-height:28px}._1kHyqG_summaryTitle{flex:1;min-width:0}._1kHyqG_statusLine{color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;font-size:12px;line-height:1.5;display:inline-flex}._1kHyqG_text{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:1.5}._1kHyqG_dim{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}._1kHyqG_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}._1kHyqG_package{flex-direction:column;gap:8px;padding:8px 0;display:flex}._1kHyqG_package+._1kHyqG_package{border-top:.5px solid var(--dsw-alias-border-l2)}._1kHyqG_packageLabel{justify-content:space-between;align-items:baseline;gap:8px;font-size:13px;line-height:1.5;display:flex}._1kHyqG_track{corner-shape:round;background:var(--dsw-alias-border-l3);border-radius:999px;height:8px;overflow:hidden}._1kHyqG_fill{border-radius:inherit;background:var(--dsw-alias-brand-primary);height:100%}._1kHyqG_panel{flex-direction:column;gap:12px;height:380px;display:flex}._1kHyqG_panel>*{flex:none}._1kHyqG_list{border:.5px solid var(--dsw-alias-border-l1);border-radius:10px;gap:0;min-width:0;margin:0;padding:6px 14px;display:grid;overflow:auto}._1kHyqG_panel>._1kHyqG_list{flex:auto;min-height:0}._1kHyqG_listHeader{border-bottom:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin:0;padding:6px 0 8px;font-size:12px;line-height:1.5}._1kHyqG_modelRow{justify-content:space-between;align-items:center;gap:8px;padding:8px 0;display:flex}._1kHyqG_modelRow+._1kHyqG_modelRow{border-top:.5px solid var(--dsw-alias-border-l2)}._1kHyqG_modelMain{align-items:center;gap:8px;min-width:0;display:flex}._1kHyqG_modelCheck{font-size:13px;line-height:1.5}._1kHyqG_modelStack{flex-direction:column;gap:2px;min-width:0;display:flex}._1kHyqG_name{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5}._1kHyqG_modelEnd{text-align:right;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-direction:column;gap:2px;font-size:12px;line-height:1.5;display:flex}._1kHyqG_meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}._1kHyqG_badges{flex-wrap:wrap;align-items:center;gap:6px;display:flex}._1kHyqG_probeRow{justify-content:space-between;align-items:center;gap:8px;padding:8px 0;display:flex}._1kHyqG_modelStack+._1kHyqG_modelStack{border-top:.5px solid var(--dsw-alias-border-l2)}._1kHyqG_probeEnd{flex:none;align-items:center;gap:8px;display:inline-flex}._1kHyqG_assist{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:8px;padding:12px;display:flex}._1kHyqG_prompt{min-width:0;color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;flex:220px;margin:0;font-size:12px;line-height:1.6}._1kHyqG_promptRow{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-bg-layer-3);flex-wrap:wrap;align-items:flex-start;gap:8px;padding:8px 9px 8px 11px;display:flex}";
|
|
60
|
+
const tagId$4 = "dsh-workbuddy-bridge/workbuddy.module.css";
|
|
61
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
|
|
72
62
|
const tag = document.createElement("style");
|
|
73
63
|
tag.dataset.plugin = "dsh-workbuddy-bridge";
|
|
74
|
-
tag.dataset.pluginCss = tagId$
|
|
75
|
-
tag.textContent = css$
|
|
64
|
+
tag.dataset.pluginCss = tagId$4;
|
|
65
|
+
tag.textContent = css$4;
|
|
76
66
|
document.head.appendChild(tag);
|
|
77
67
|
}
|
|
78
68
|
var workbuddy_module_css_default = {
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
69
|
+
"action": "_1kHyqG_action",
|
|
70
|
+
"assist": "_1kHyqG_assist",
|
|
71
|
+
"badges": "_1kHyqG_badges",
|
|
72
|
+
"body": "_1kHyqG_body",
|
|
73
|
+
"caption": "_1kHyqG_caption",
|
|
74
|
+
"cardActions": "_1kHyqG_cardActions",
|
|
75
|
+
"cards": "_1kHyqG_cards",
|
|
76
|
+
"dim": "_1kHyqG_dim",
|
|
77
|
+
"error": "_1kHyqG_error",
|
|
78
|
+
"field": "_1kHyqG_field",
|
|
79
|
+
"figure": "_1kHyqG_figure",
|
|
80
|
+
"fill": "_1kHyqG_fill",
|
|
81
|
+
"head": "_1kHyqG_head",
|
|
82
|
+
"list": "_1kHyqG_list",
|
|
83
|
+
"listHeader": "_1kHyqG_listHeader",
|
|
84
|
+
"main": "_1kHyqG_main",
|
|
85
|
+
"meta": "_1kHyqG_meta",
|
|
86
|
+
"modelCheck": "_1kHyqG_modelCheck",
|
|
87
|
+
"modelEnd": "_1kHyqG_modelEnd",
|
|
88
|
+
"modelMain": "_1kHyqG_modelMain",
|
|
89
|
+
"modelRow": "_1kHyqG_modelRow",
|
|
90
|
+
"modelStack": "_1kHyqG_modelStack",
|
|
91
|
+
"name": "_1kHyqG_name",
|
|
92
|
+
"note": "_1kHyqG_note",
|
|
93
|
+
"package": "_1kHyqG_package",
|
|
94
|
+
"packageLabel": "_1kHyqG_packageLabel",
|
|
95
|
+
"page": "_1kHyqG_page",
|
|
96
|
+
"panel": "_1kHyqG_panel",
|
|
97
|
+
"part": "_1kHyqG_part",
|
|
98
|
+
"probeEnd": "_1kHyqG_probeEnd",
|
|
99
|
+
"probeRow": "_1kHyqG_probeRow",
|
|
100
|
+
"prompt": "_1kHyqG_prompt",
|
|
101
|
+
"promptRow": "_1kHyqG_promptRow",
|
|
102
|
+
"section": "_1kHyqG_section",
|
|
103
|
+
"sectionActions": "_1kHyqG_sectionActions",
|
|
104
|
+
"statusLine": "_1kHyqG_statusLine",
|
|
105
|
+
"summaryRow": "_1kHyqG_summaryRow",
|
|
106
|
+
"summaryTitle": "_1kHyqG_summaryTitle",
|
|
107
|
+
"text": "_1kHyqG_text",
|
|
108
|
+
"title": "_1kHyqG_title",
|
|
109
|
+
"toggleHint": "_1kHyqG_toggleHint",
|
|
110
|
+
"toggleLabel": "_1kHyqG_toggleLabel",
|
|
111
|
+
"toggleRow": "_1kHyqG_toggleRow",
|
|
112
|
+
"track": "_1kHyqG_track"
|
|
112
113
|
};
|
|
113
114
|
//#endregion
|
|
115
|
+
//#region src/client/field.tsx
|
|
116
|
+
/**
|
|
117
|
+
* Render one fact: a main line with an optional control, and an optional note.
|
|
118
|
+
*
|
|
119
|
+
* @param props - see {@link FieldProps}.
|
|
120
|
+
*/
|
|
121
|
+
function Field({ main, note, action }) {
|
|
122
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
123
|
+
className: workbuddy_module_css_default.field,
|
|
124
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
125
|
+
className: workbuddy_module_css_default.head,
|
|
126
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
127
|
+
className: workbuddy_module_css_default.main,
|
|
128
|
+
children: main
|
|
129
|
+
}), action === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
130
|
+
className: workbuddy_module_css_default.action,
|
|
131
|
+
children: action
|
|
132
|
+
})]
|
|
133
|
+
}), note === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
134
|
+
className: workbuddy_module_css_default.note,
|
|
135
|
+
children: note
|
|
136
|
+
})]
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Render one line of tiered text: `caption value after`.
|
|
141
|
+
*
|
|
142
|
+
* Omit `children` for a line that is pure copy — a caption alone renders as the
|
|
143
|
+
* grey sentence it is, which is how the note under the detection list works.
|
|
144
|
+
*
|
|
145
|
+
* @param props - see {@link PartProps}.
|
|
146
|
+
*/
|
|
147
|
+
function Part({ caption, children, after }) {
|
|
148
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
149
|
+
className: workbuddy_module_css_default.part,
|
|
150
|
+
children: [
|
|
151
|
+
caption === void 0 || caption === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
152
|
+
className: workbuddy_module_css_default.caption,
|
|
153
|
+
children: caption
|
|
154
|
+
}),
|
|
155
|
+
children === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
156
|
+
className: workbuddy_module_css_default.figure,
|
|
157
|
+
children
|
|
158
|
+
}),
|
|
159
|
+
after === void 0 || after === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
160
|
+
className: workbuddy_module_css_default.caption,
|
|
161
|
+
children: after
|
|
162
|
+
})
|
|
163
|
+
]
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
114
167
|
//#region src/client/panels.tsx
|
|
115
168
|
/**
|
|
116
169
|
* The card's three panels and the Agent assist block.
|
|
@@ -168,6 +221,23 @@ window.__ModuleLoader__.load({
|
|
|
168
221
|
if (badge === "Free now") return t("badgeFreeNow");
|
|
169
222
|
return badge;
|
|
170
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Where the model list on screen came from — the source, as a value.
|
|
226
|
+
*
|
|
227
|
+
* Lives here rather than in the card header: the answer describes the state of
|
|
228
|
+
* the catalog, and the catalog is this panel's subject. It sat in the account
|
|
229
|
+
* block only because that block had room, which made a fact about the model list
|
|
230
|
+
* read as a fact about the account.
|
|
231
|
+
*
|
|
232
|
+
* Only the source. The moment it was read is a *dynamic* value and is rendered
|
|
233
|
+
* as its own element beside this one — an interpolated sentence would carry a
|
|
234
|
+
* localized date whose length changes with the locale, and the label above it
|
|
235
|
+
* would have to move to keep up.
|
|
236
|
+
*/
|
|
237
|
+
function catalogSourceText(catalog, t) {
|
|
238
|
+
if (catalog.source === "live") return t("catalogSourceLive");
|
|
239
|
+
return catalog.source === "saved" ? t("catalogSourceSaved") : t("catalogSourceFallback");
|
|
240
|
+
}
|
|
171
241
|
/** One model's promotional badges, plus `Free` when the upstream says so. */
|
|
172
242
|
function ModelBadges({ model, t }) {
|
|
173
243
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -196,7 +266,13 @@ window.__ModuleLoader__.load({
|
|
|
196
266
|
className: workbuddy_module_css_default.package,
|
|
197
267
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
198
268
|
className: workbuddy_module_css_default.packageLabel,
|
|
199
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
269
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
270
|
+
className: workbuddy_module_css_default.caption,
|
|
271
|
+
children: label
|
|
272
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
273
|
+
className: workbuddy_module_css_default.figure,
|
|
274
|
+
children: quota
|
|
275
|
+
})]
|
|
200
276
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
201
277
|
className: workbuddy_module_css_default.track,
|
|
202
278
|
role: "progressbar",
|
|
@@ -204,45 +280,55 @@ window.__ModuleLoader__.load({
|
|
|
204
280
|
"aria-valuetext": quota
|
|
205
281
|
})]
|
|
206
282
|
});
|
|
207
|
-
const
|
|
208
|
-
const
|
|
283
|
+
const percent = size > 0 ? remain / size * 100 : void 0;
|
|
284
|
+
const reading = percent === void 0 ? t("creditPackageUnknownSize", { remain: formatNumber(remain) }) : t("packageRemaining", {
|
|
209
285
|
remain: formatNumber(remain),
|
|
210
|
-
size: formatNumber(size)
|
|
211
|
-
|
|
212
|
-
|
|
286
|
+
size: formatNumber(size),
|
|
287
|
+
percent: formatPercent(percent)
|
|
288
|
+
});
|
|
213
289
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
214
290
|
className: workbuddy_module_css_default.package,
|
|
215
|
-
children: [
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
221
|
-
className: workbuddy_module_css_default.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
children: detail
|
|
291
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
292
|
+
className: workbuddy_module_css_default.packageLabel,
|
|
293
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
294
|
+
className: workbuddy_module_css_default.caption,
|
|
295
|
+
children: label
|
|
296
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
297
|
+
className: workbuddy_module_css_default.figure,
|
|
298
|
+
children: reading
|
|
299
|
+
})]
|
|
300
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
301
|
+
className: workbuddy_module_css_default.track,
|
|
302
|
+
role: "progressbar",
|
|
303
|
+
"aria-label": label,
|
|
304
|
+
...percent === void 0 ? { "aria-valuetext": reading } : {
|
|
305
|
+
"aria-valuemin": 0,
|
|
306
|
+
"aria-valuemax": 100,
|
|
307
|
+
"aria-valuenow": percent
|
|
308
|
+
},
|
|
309
|
+
children: percent === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
310
|
+
className: workbuddy_module_css_default.fill,
|
|
311
|
+
style: { width: `${Math.max(0, Math.min(100, percent))}%` }
|
|
237
312
|
})
|
|
238
|
-
]
|
|
313
|
+
})]
|
|
239
314
|
});
|
|
240
315
|
}
|
|
241
|
-
/**
|
|
316
|
+
/**
|
|
317
|
+
* The per-package credit breakdown, under the card's own "Credits" tab.
|
|
318
|
+
*
|
|
319
|
+
* Rendered into the **same scroll container the other two panels use**. It
|
|
320
|
+
* originally rendered straight into the panel with no container at all, so while
|
|
321
|
+
* the models and detection tabs were capped at 280px this one grew to whatever
|
|
322
|
+
* the account had — 11 packages on the maintainer's account, roughly three times
|
|
323
|
+
* the height of the other two tabs (2026-10-02). Switching tabs resized the card
|
|
324
|
+
* and only this tab had no scrollbar; now all three are one geometry.
|
|
325
|
+
*/
|
|
242
326
|
function CreditsPanel({ credits, t }) {
|
|
327
|
+
const shown = credits.accounts.filter((account) => account.packageName === "enterprise" || account.remain > 0 || account.unlimited === true);
|
|
328
|
+
if (shown.length === 0) return null;
|
|
243
329
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
244
|
-
className: workbuddy_module_css_default.
|
|
245
|
-
children:
|
|
330
|
+
className: workbuddy_module_css_default.list,
|
|
331
|
+
children: shown.map((account, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditBar, {
|
|
246
332
|
label: account.packageName === "enterprise" ? t("packageEnterprise") : account.packageName,
|
|
247
333
|
remain: account.remain,
|
|
248
334
|
size: account.size,
|
|
@@ -269,22 +355,34 @@ window.__ModuleLoader__.load({
|
|
|
269
355
|
* budget actually requested, while the larger value is a ceiling the upstream
|
|
270
356
|
* would accept.
|
|
271
357
|
*/
|
|
272
|
-
function ModelsPanel({ models, visibility, toggling, disabled, onToggle, t }) {
|
|
358
|
+
function ModelsPanel({ models, visibility, toggling, disabled, catalog, onToggle, t }) {
|
|
273
359
|
const rows = [...models ?? []].sort((a, b) => {
|
|
274
360
|
if (a.contextWindow === void 0) return b.contextWindow === void 0 ? 0 : 1;
|
|
275
361
|
if (b.contextWindow === void 0) return -1;
|
|
276
362
|
return b.contextWindow - a.contextWindow;
|
|
277
363
|
});
|
|
278
|
-
if (rows.length === 0) return null;
|
|
279
364
|
const hidden = new Set(visibility?.hidden ?? []);
|
|
280
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
365
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
366
|
+
catalog === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
367
|
+
main: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, {
|
|
368
|
+
caption: t("catalogSourceFrom"),
|
|
369
|
+
children: catalogSourceText(catalog, t)
|
|
370
|
+
}),
|
|
371
|
+
note: catalog.fetchedAt === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, {
|
|
372
|
+
caption: t("catalogUpdatedAt"),
|
|
373
|
+
children: formatTime(catalog.fetchedAt)
|
|
374
|
+
})
|
|
375
|
+
}),
|
|
376
|
+
catalog?.error === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
377
|
+
className: workbuddy_module_css_default.error,
|
|
378
|
+
children: t("catalogError", { message: catalog.error })
|
|
379
|
+
}),
|
|
380
|
+
rows.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
286
381
|
className: workbuddy_module_css_default.list,
|
|
287
|
-
children:
|
|
382
|
+
children: [visibility === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
383
|
+
className: workbuddy_module_css_default.listHeader,
|
|
384
|
+
children: t("visibilityIntro")
|
|
385
|
+
}), rows.map((model) => {
|
|
288
386
|
const capacity = model.contextWindow;
|
|
289
387
|
const alternative = capacity !== void 0 && model.maxContextWindow !== void 0 && model.maxContextWindow > capacity ? model.maxContextWindow : void 0;
|
|
290
388
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -298,6 +396,7 @@ window.__ModuleLoader__.load({
|
|
|
298
396
|
checked: !hidden.has(model.id),
|
|
299
397
|
disabled: disabled || toggling.has(model.id),
|
|
300
398
|
label: model.name,
|
|
399
|
+
className: workbuddy_module_css_default.modelCheck,
|
|
301
400
|
onChange: (visible) => {
|
|
302
401
|
onToggle(model.id, visible, visibility.account);
|
|
303
402
|
}
|
|
@@ -334,9 +433,9 @@ window.__ModuleLoader__.load({
|
|
|
334
433
|
]
|
|
335
434
|
})]
|
|
336
435
|
}, model.id);
|
|
337
|
-
})
|
|
338
|
-
})
|
|
339
|
-
});
|
|
436
|
+
})]
|
|
437
|
+
})
|
|
438
|
+
] });
|
|
340
439
|
}
|
|
341
440
|
/**
|
|
342
441
|
* Reasoning levels: one row per reasoning model, and what its switch does.
|
|
@@ -360,7 +459,7 @@ window.__ModuleLoader__.load({
|
|
|
360
459
|
*
|
|
361
460
|
* The tab bar owns the heading, so this panel renders no heading of its own.
|
|
362
461
|
*/
|
|
363
|
-
function ProbePanel({ probe, models, busy, onDetect, onClear, t }) {
|
|
462
|
+
function ProbePanel$1({ probe, models, busy, onDetect, onClear, t }) {
|
|
364
463
|
const [runningModel, setRunningModel] = (0, react.useState)();
|
|
365
464
|
const armed = (0, react.useRef)(false);
|
|
366
465
|
(0, react.useEffect)(() => {
|
|
@@ -382,59 +481,57 @@ window.__ModuleLoader__.load({
|
|
|
382
481
|
children: t("probeResultEmpty")
|
|
383
482
|
});
|
|
384
483
|
const detected = probe.models.filter((entry) => entry.probedAt !== void 0);
|
|
385
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
484
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
485
|
+
main: detected.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, { caption: t("probeDetectedNone") }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, {
|
|
486
|
+
caption: t("probeDetectedCaption"),
|
|
487
|
+
after: t("probeDetectedUnit"),
|
|
488
|
+
children: detected.length
|
|
489
|
+
}),
|
|
490
|
+
note: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, { caption: t("probeCostNote") }),
|
|
491
|
+
action: detected.length === 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
492
|
+
size: "sm",
|
|
493
|
+
disabled: busy,
|
|
494
|
+
onClick: onClear,
|
|
495
|
+
children: t("probeClear")
|
|
496
|
+
})
|
|
497
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
498
|
+
className: workbuddy_module_css_default.list,
|
|
499
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
500
|
+
className: workbuddy_module_css_default.listHeader,
|
|
501
|
+
children: t("probeListIntro")
|
|
502
|
+
}), probe.models.map((entry) => {
|
|
503
|
+
const id = entry.id;
|
|
504
|
+
const name = models?.find((model) => model.id === id)?.name ?? entry.name ?? id;
|
|
505
|
+
const hasLevels = entry.efforts.length > 0;
|
|
506
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
507
|
+
className: workbuddy_module_css_default.modelStack,
|
|
508
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
509
|
+
className: workbuddy_module_css_default.probeRow,
|
|
510
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
511
|
+
className: workbuddy_module_css_default.name,
|
|
512
|
+
children: name
|
|
513
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
514
|
+
className: workbuddy_module_css_default.probeEnd,
|
|
515
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
516
|
+
tone: hasLevels ? "success" : "neutral",
|
|
517
|
+
children: hasLevels ? entry.efforts.join(" / ") : t(entry.detectable ? entry.validation === "non-validating" ? "probeResultNotValidating" : "probeResultUnknown" : "probeResultDeclaredNone")
|
|
518
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
519
|
+
size: "sm",
|
|
520
|
+
disabled: busy || probe.running || !entry.detectable,
|
|
521
|
+
onClick: () => {
|
|
522
|
+
setRunningModel(id);
|
|
523
|
+
onDetect(id);
|
|
524
|
+
},
|
|
525
|
+
children: runningModel === id && entry.detectable ? t("probeRunning", { model: name }) : !entry.detectable ? t("probeActionDeclared") : t(entry.probedAt === void 0 ? "probeStart" : "probeRedetect")
|
|
423
526
|
})]
|
|
424
|
-
}
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
onClick: onClear,
|
|
433
|
-
children: t("probeClear")
|
|
434
|
-
})
|
|
435
|
-
})
|
|
436
|
-
]
|
|
437
|
-
});
|
|
527
|
+
})]
|
|
528
|
+
}), entry.probedAt === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
529
|
+
className: workbuddy_module_css_default.meta,
|
|
530
|
+
children: t("probeResultAt", { time: formatTime(entry.probedAt) })
|
|
531
|
+
})]
|
|
532
|
+
}, id);
|
|
533
|
+
})]
|
|
534
|
+
})] });
|
|
438
535
|
}
|
|
439
536
|
/**
|
|
440
537
|
* The Agent assist block for a path failure: what is wrong, one copyable
|
|
@@ -499,8 +596,156 @@ window.__ModuleLoader__.load({
|
|
|
499
596
|
});
|
|
500
597
|
}
|
|
501
598
|
//#endregion
|
|
599
|
+
//#region src/client/PanelBoundary.tsx
|
|
600
|
+
/**
|
|
601
|
+
* A boundary that keeps one panel's crash from taking the whole card.
|
|
602
|
+
*
|
|
603
|
+
* The host renders each slot under its own error boundary, and that boundary
|
|
604
|
+
* **latches**: once a child throws, the region stays gone for the life of the
|
|
605
|
+
* mount. The user's only way back is to disable and re-enable the plugin. So a
|
|
606
|
+
* throw anywhere inside this card does not cost one panel — it costs the entire
|
|
607
|
+
* configuration area (2026-10-02: `probe.models` was not an array, and switching
|
|
608
|
+
* to the detection tab blanked everything below the plugin's own switch).
|
|
609
|
+
*
|
|
610
|
+
* React's rule is that an error boundary must be a **class** — `getDerivedStateFromError`
|
|
611
|
+
* and `componentDidCatch` have no hook equivalent. That is the only reason this
|
|
612
|
+
* file is not a function component.
|
|
613
|
+
*
|
|
614
|
+
* What it is *not*: a substitute for validating inputs. The boundary is the last
|
|
615
|
+
* line of defence for the failure nobody predicted; the shape guard in
|
|
616
|
+
* `status-document.ts` is what keeps malformed documents from getting this far.
|
|
617
|
+
* Both exist because they fail differently — the guard degrades to "nothing to
|
|
618
|
+
* show", the boundary degrades to "this block says it broke".
|
|
619
|
+
*/
|
|
620
|
+
/**
|
|
621
|
+
* Catch a render error in one panel and render a local fallback instead.
|
|
622
|
+
*
|
|
623
|
+
* The fallback is deliberately plain: a block that broke cannot be trusted to
|
|
624
|
+
* render its own recovery UI, and the one thing the user needs is a way to try
|
|
625
|
+
* again — which is what `reset` gives, by clearing the caught error so the
|
|
626
|
+
* children mount afresh.
|
|
627
|
+
*/
|
|
628
|
+
var PanelBoundary = class extends react.Component {
|
|
629
|
+
state = { message: void 0 };
|
|
630
|
+
static getDerivedStateFromError(error) {
|
|
631
|
+
return { message: error instanceof Error ? error.message : String(error) };
|
|
632
|
+
}
|
|
633
|
+
componentDidCatch(error, info) {
|
|
634
|
+
console.error(`dsh-workbuddy-bridge: ${this.props.label} failed to render`, error, info);
|
|
635
|
+
}
|
|
636
|
+
render() {
|
|
637
|
+
const { message } = this.state;
|
|
638
|
+
if (message === void 0) return this.props.children;
|
|
639
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
640
|
+
className: workbuddy_module_css_default.section,
|
|
641
|
+
role: "alert",
|
|
642
|
+
children: [
|
|
643
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
644
|
+
className: workbuddy_module_css_default.error,
|
|
645
|
+
children: this.props.t("panelCrashed", { panel: this.props.label })
|
|
646
|
+
}),
|
|
647
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
648
|
+
className: workbuddy_module_css_default.dim,
|
|
649
|
+
children: message
|
|
650
|
+
}),
|
|
651
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
652
|
+
className: workbuddy_module_css_default.sectionActions,
|
|
653
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
654
|
+
size: "sm",
|
|
655
|
+
onClick: () => {
|
|
656
|
+
this.setState({ message: void 0 });
|
|
657
|
+
},
|
|
658
|
+
children: this.props.t("panelRetry")
|
|
659
|
+
})
|
|
660
|
+
})
|
|
661
|
+
]
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
//#endregion
|
|
666
|
+
//#region \0workbuddy-css:D:\ProjectSomething\dsh-plugins\dsh-workbuddy-bridge\src\client\coin-glyph.module.css.js
|
|
667
|
+
const css$3 = ".sapSKa_glyph{flex:none;align-self:center}";
|
|
668
|
+
const tagId$3 = "dsh-workbuddy-bridge/coin-glyph.module.css";
|
|
669
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
670
|
+
const tag = document.createElement("style");
|
|
671
|
+
tag.dataset.plugin = "dsh-workbuddy-bridge";
|
|
672
|
+
tag.dataset.pluginCss = tagId$3;
|
|
673
|
+
tag.textContent = css$3;
|
|
674
|
+
document.head.appendChild(tag);
|
|
675
|
+
}
|
|
676
|
+
var coin_glyph_module_css_default = { "glyph": "sapSKa_glyph" };
|
|
677
|
+
//#endregion
|
|
678
|
+
//#region src/client/coin-glyph.tsx
|
|
679
|
+
/** Render the coin-stack glyph. Decorative: the caller supplies the accessible name. */
|
|
680
|
+
function CoinGlyph() {
|
|
681
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
682
|
+
width: "16",
|
|
683
|
+
height: "16",
|
|
684
|
+
viewBox: "0 0 16 16",
|
|
685
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
686
|
+
fill: "none",
|
|
687
|
+
stroke: "currentColor",
|
|
688
|
+
strokeWidth: "1",
|
|
689
|
+
"aria-hidden": "true",
|
|
690
|
+
className: coin_glyph_module_css_default.glyph,
|
|
691
|
+
children: [
|
|
692
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ellipse", {
|
|
693
|
+
cx: "8",
|
|
694
|
+
cy: "4.7",
|
|
695
|
+
rx: "4.7",
|
|
696
|
+
ry: "1.25"
|
|
697
|
+
}),
|
|
698
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.3 4.7V10.7A4.7 1.25 0 0 0 12.7 10.7V4.7" }),
|
|
699
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.3 7.7A4.7 1.25 0 0 0 12.7 7.7" })
|
|
700
|
+
]
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
//#endregion
|
|
502
704
|
//#region src/client/status-document.ts
|
|
503
705
|
/**
|
|
706
|
+
* Whether one probe row is safe to read.
|
|
707
|
+
*
|
|
708
|
+
* `efforts` is the field the readers actually dereference (`.length`, `.join`),
|
|
709
|
+
* so it is the one that must be an array — a row whose `efforts` is absent or a
|
|
710
|
+
* string would throw inside the panel rather than degrade.
|
|
711
|
+
*/
|
|
712
|
+
function isEffortRow(value) {
|
|
713
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
714
|
+
const row = value;
|
|
715
|
+
return typeof row["id"] === "string" && Array.isArray(row["efforts"]);
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Whether the `probe` section is safe to read.
|
|
719
|
+
*
|
|
720
|
+
* Validated to the depth the readers go, and no further. `consent` and `running`
|
|
721
|
+
* are only ever compared, so a missing value degrades correctly on its own;
|
|
722
|
+
* `models` is iterated and each row's `efforts` is measured, so those two must
|
|
723
|
+
* actually be arrays.
|
|
724
|
+
*
|
|
725
|
+
* The depth matters in both directions. Too shallow and a malformed document
|
|
726
|
+
* throws inside the panel — which the host's slot boundary turns into a
|
|
727
|
+
* *latched* failure, so the whole configuration area disappears until the plugin
|
|
728
|
+
* is toggled (2026-10-02, reached through a client-bundle hot reload that
|
|
729
|
+
* changed the document shape under a mounted component). Too deep and the guard
|
|
730
|
+
* starts rejecting documents the host legitimately omits fields from.
|
|
731
|
+
*/
|
|
732
|
+
function isProbeSection(value) {
|
|
733
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
734
|
+
const models = value["models"];
|
|
735
|
+
return Array.isArray(models) && models.every(isEffortRow);
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Whether the `visibility` section is safe to read.
|
|
739
|
+
*
|
|
740
|
+
* `hidden` is spread into a `Set` by the models panel, which throws on a
|
|
741
|
+
* non-iterable; the account key is only compared, so it is left alone.
|
|
742
|
+
*/
|
|
743
|
+
function isVisibilitySection(value) {
|
|
744
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
745
|
+
const hidden = value["hidden"];
|
|
746
|
+
return hidden === void 0 || Array.isArray(hidden) && hidden.every((id) => typeof id === "string");
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
504
749
|
* Whether a parsed status response really is a status document.
|
|
505
750
|
*
|
|
506
751
|
* A 200 is not a promise about the body: it may be empty, literal `null`, a
|
|
@@ -508,9 +753,12 @@ window.__ModuleLoader__.load({
|
|
|
508
753
|
* read the same route, so both must agree on what is valid — storing an
|
|
509
754
|
* unreadable value puts something in state that the next render dereferences.
|
|
510
755
|
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
756
|
+
* Beyond the discriminator this validates the two nested structures a reader
|
|
757
|
+
* iterates **without** a guard: `probe.models` and `visibility.hidden`. Those
|
|
758
|
+
* are the ones that turn a malformed document into a thrown render rather than
|
|
759
|
+
* a degraded one. Everything else stays optional on purpose — validating
|
|
760
|
+
* optional fields would reject documents the host legitimately omits fields
|
|
761
|
+
* from, and a reader that only compares a value degrades correctly without help.
|
|
514
762
|
*
|
|
515
763
|
* `reasonCode` is therefore *not* rejected here — a card renders `reason`
|
|
516
764
|
* either way — but every reader must narrow it with
|
|
@@ -521,8 +769,12 @@ window.__ModuleLoader__.load({
|
|
|
521
769
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
522
770
|
const wrapped = value;
|
|
523
771
|
const status = wrapped["status"];
|
|
524
|
-
if (status === "
|
|
525
|
-
|
|
772
|
+
if (status === "error") return typeof wrapped["message"] === "string";
|
|
773
|
+
if (status !== "signed-out" && status !== "signed-in") return false;
|
|
774
|
+
const probe = wrapped["probe"];
|
|
775
|
+
if (probe !== void 0 && !isProbeSection(probe)) return false;
|
|
776
|
+
const visibility = wrapped["visibility"];
|
|
777
|
+
return visibility === void 0 || isVisibilitySection(visibility);
|
|
526
778
|
}
|
|
527
779
|
/**
|
|
528
780
|
* Whether a parsed credit response really is a credit document.
|
|
@@ -719,22 +971,33 @@ window.__ModuleLoader__.load({
|
|
|
719
971
|
controller.abort();
|
|
720
972
|
};
|
|
721
973
|
}, [read]);
|
|
974
|
+
const refresh = (0, react.useCallback)(async () => {
|
|
975
|
+
setBusy(true);
|
|
976
|
+
const controller = track();
|
|
977
|
+
try {
|
|
978
|
+
await read(controller.signal);
|
|
979
|
+
} finally {
|
|
980
|
+
inFlight.current.delete(controller);
|
|
981
|
+
if (mounted.current) setBusy(false);
|
|
982
|
+
}
|
|
983
|
+
}, [read, track]);
|
|
722
984
|
return {
|
|
723
985
|
status,
|
|
724
986
|
readFailure,
|
|
725
987
|
busy,
|
|
726
988
|
toggling,
|
|
727
|
-
refresh
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
} finally {
|
|
733
|
-
inFlight.current.delete(controller);
|
|
734
|
-
if (mounted.current) setBusy(false);
|
|
989
|
+
refresh,
|
|
990
|
+
refreshAll: (0, react.useCallback)(async () => {
|
|
991
|
+
if ((status?.status === "signed-in" ? status.probeKey : void 0) === void 0) {
|
|
992
|
+
await refresh();
|
|
993
|
+
return;
|
|
735
994
|
}
|
|
736
|
-
|
|
737
|
-
|
|
995
|
+
await control({ action: "refresh" });
|
|
996
|
+
}, [
|
|
997
|
+
control,
|
|
998
|
+
refresh,
|
|
999
|
+
status
|
|
1000
|
+
]),
|
|
738
1001
|
detect: (0, react.useCallback)((model) => control({
|
|
739
1002
|
action: "probe",
|
|
740
1003
|
model
|
|
@@ -771,6 +1034,18 @@ window.__ModuleLoader__.load({
|
|
|
771
1034
|
* reasoning-effort detection.
|
|
772
1035
|
*/
|
|
773
1036
|
/**
|
|
1037
|
+
* Locale key per tab, so the crash fallback can name the block it replaced.
|
|
1038
|
+
*
|
|
1039
|
+
* The tabs' own `label` field is a `ReactNode` (the host's `SegmentedTab` allows
|
|
1040
|
+
* a node), so it cannot be fed back to `t()`. This map is the one place that
|
|
1041
|
+
* knows both the tab identity and the key behind its label.
|
|
1042
|
+
*/
|
|
1043
|
+
const TAB_LABEL_KEY = {
|
|
1044
|
+
credits: "tabCredits",
|
|
1045
|
+
models: "tabModels",
|
|
1046
|
+
probe: "tabProbe"
|
|
1047
|
+
};
|
|
1048
|
+
/**
|
|
774
1049
|
* The state dot's semantic.
|
|
775
1050
|
*
|
|
776
1051
|
* Takes `'loading'` as well as the document's own states: before the first
|
|
@@ -783,23 +1058,42 @@ window.__ModuleLoader__.load({
|
|
|
783
1058
|
if (status.status === "signed-in") return "done";
|
|
784
1059
|
return status.status === "error" ? "error" : "idle";
|
|
785
1060
|
}
|
|
786
|
-
/**
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1061
|
+
/**
|
|
1062
|
+
* What the account state says, in one place.
|
|
1063
|
+
*
|
|
1064
|
+
* **One home, because two homes already disagreed.** The collapsed header renders
|
|
1065
|
+
* this as one string and the expanded block renders it as a caption plus a value;
|
|
1066
|
+
* when each derived the line itself, the body branched on *having an identity*
|
|
1067
|
+
* instead of on the sign-in state — and since a signed-out document has no
|
|
1068
|
+
* identity either, a signed-out card read 未登录 in the header and 已登录 in the
|
|
1069
|
+
* body, with the state dot correctly unlit beside them (reported 2026-10-03).
|
|
1070
|
+
*
|
|
1071
|
+
* The identity is the nickname when the desktop app reports one, otherwise the
|
|
1072
|
+
* account id: the credential does not always carry a nickname, while the id is
|
|
1073
|
+
* what the per-account state (hidden models, probe records) is keyed by, so it is
|
|
1074
|
+
* the one name that is always there.
|
|
1075
|
+
*/
|
|
1076
|
+
function accountLine(status, t) {
|
|
1077
|
+
if (status === void 0) return { caption: t("loading") };
|
|
1078
|
+
if (status.status === "signed-in") {
|
|
1079
|
+
const identity = status.nickname ?? status.uid;
|
|
1080
|
+
return identity === void 0 ? { caption: t("signedIn") } : {
|
|
1081
|
+
caption: t("signedInLabel"),
|
|
1082
|
+
value: identity
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
return { caption: status.status === "error" ? t("requestFailed") : t("signedOut") };
|
|
791
1086
|
}
|
|
792
|
-
/**
|
|
793
|
-
function
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
return catalog.appVersion === void 0 ? line : `${line} · ${t("catalogAppVersion", { version: catalog.appVersion })}`;
|
|
1087
|
+
/** The same line flattened for the collapsed header, where it is one string. */
|
|
1088
|
+
function accountLabel(status, t) {
|
|
1089
|
+
const { caption, value } = accountLine(status, t);
|
|
1090
|
+
return value === void 0 ? caption : `${caption} ${value}`;
|
|
797
1091
|
}
|
|
798
1092
|
/** Render one variant's live status card. */
|
|
799
1093
|
function WorkBuddyCard({ variant, t }) {
|
|
800
1094
|
const [open, setOpen] = (0, react.useState)(false);
|
|
801
1095
|
const [tab, setTab] = (0, react.useState)("credits");
|
|
802
|
-
const { status, readFailure, busy, toggling, refresh,
|
|
1096
|
+
const { status, readFailure, busy, toggling, refresh, refreshAll, detect, clearDetections, setVisibility } = useWorkBuddyStatus(variant, t);
|
|
803
1097
|
const baseId = (0, react.useId)();
|
|
804
1098
|
const creditsTab = {
|
|
805
1099
|
value: "credits",
|
|
@@ -832,6 +1126,7 @@ window.__ModuleLoader__.load({
|
|
|
832
1126
|
*/
|
|
833
1127
|
const assistCode = status?.status === "signed-out" ? assistCodeFor(status.reasonCode) : void 0;
|
|
834
1128
|
const signedIn = status?.status === "signed-in" ? status : void 0;
|
|
1129
|
+
const account = accountLine(status, t);
|
|
835
1130
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
|
|
836
1131
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: dotState(status) }),
|
|
837
1132
|
title: t(variant.titleKey),
|
|
@@ -852,78 +1147,48 @@ window.__ModuleLoader__.load({
|
|
|
852
1147
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
853
1148
|
className: workbuddy_module_css_default.body,
|
|
854
1149
|
children: [
|
|
1150
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1151
|
+
className: workbuddy_module_css_default.cardActions,
|
|
1152
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1153
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {}),
|
|
1154
|
+
disabled: busy,
|
|
1155
|
+
onClick: () => {
|
|
1156
|
+
refreshAll();
|
|
1157
|
+
},
|
|
1158
|
+
children: busy ? t("refreshingAll") : t("refreshAll")
|
|
1159
|
+
})
|
|
1160
|
+
}),
|
|
855
1161
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
856
1162
|
className: workbuddy_module_css_default.section,
|
|
857
|
-
children: [
|
|
858
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
859
|
-
|
|
860
|
-
children:
|
|
861
|
-
}),
|
|
862
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
863
|
-
className: workbuddy_module_css_default.row,
|
|
864
|
-
children: assistCode === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
865
|
-
size: "sm",
|
|
866
|
-
disabled: busy,
|
|
867
|
-
onClick: () => {
|
|
868
|
-
refresh();
|
|
869
|
-
},
|
|
870
|
-
children: busy ? t("refreshing") : t("refresh")
|
|
871
|
-
}) : null
|
|
1163
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1164
|
+
main: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, {
|
|
1165
|
+
caption: account.caption,
|
|
1166
|
+
children: account.value === void 0 ? void 0 : account.value
|
|
872
1167
|
}),
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
children:
|
|
876
|
-
}),
|
|
877
|
-
signedIn?.expiresAt === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
878
|
-
className: workbuddy_module_css_default.text,
|
|
879
|
-
children: t("accessTokenExpires", { time: formatTime(signedIn.expiresAt) })
|
|
1168
|
+
note: signedIn?.expiresAt === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Part, {
|
|
1169
|
+
caption: t("sessionExpiryLabel"),
|
|
1170
|
+
children: formatTime(signedIn.expiresAt)
|
|
880
1171
|
})
|
|
881
|
-
|
|
882
|
-
}),
|
|
883
|
-
signedIn === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
884
|
-
signedIn.catalog === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
885
|
-
className: workbuddy_module_css_default.row,
|
|
886
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
887
|
-
className: workbuddy_module_css_default.text,
|
|
888
|
-
children: catalogProvenance(signedIn.catalog, t)
|
|
889
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
890
|
-
size: "sm",
|
|
891
|
-
disabled: busy,
|
|
892
|
-
onClick: () => {
|
|
893
|
-
refreshModels();
|
|
894
|
-
},
|
|
895
|
-
children: busy ? t("refreshingModels") : t("refreshModels")
|
|
896
|
-
})]
|
|
897
|
-
}),
|
|
898
|
-
signedIn.catalog?.error === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1172
|
+
}), readFailure === void 0 || status === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
899
1173
|
className: workbuddy_module_css_default.error,
|
|
900
|
-
children: t("
|
|
901
|
-
})
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1174
|
+
children: t("statusRefreshFailed", { message: readFailure })
|
|
1175
|
+
})]
|
|
1176
|
+
}),
|
|
1177
|
+
signedIn === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
|
|
1178
|
+
items: tabs,
|
|
1179
|
+
value: tab,
|
|
1180
|
+
onChange: setTab,
|
|
1181
|
+
label: t("tabLabel")
|
|
1182
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelBoundary, {
|
|
1183
|
+
label: t(TAB_LABEL_KEY[tab]),
|
|
1184
|
+
t,
|
|
1185
|
+
children: tab === "credits" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1186
|
+
className: workbuddy_module_css_default.panel,
|
|
910
1187
|
id: creditsTab.panelId,
|
|
911
1188
|
role: "tabpanel",
|
|
912
1189
|
"aria-labelledby": creditsTab.id,
|
|
913
1190
|
children: [
|
|
914
|
-
signedIn.credits === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
915
|
-
className: workbuddy_module_css_default.section,
|
|
916
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
917
|
-
className: workbuddy_module_css_default.row,
|
|
918
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
919
|
-
className: workbuddy_module_css_default.title,
|
|
920
|
-
children: signedIn.credits.unlimited === true ? t("creditsTotalUnlimited") : t("creditsTotal", { total: formatNumber(signedIn.credits.total) })
|
|
921
|
-
})
|
|
922
|
-
}), signedIn.credits.cycleResetTime === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
923
|
-
className: workbuddy_module_css_default.dim,
|
|
924
|
-
children: t("cycleResetAt", { time: formatCycleReset(signedIn.credits.cycleResetTime) })
|
|
925
|
-
})]
|
|
926
|
-
}),
|
|
1191
|
+
signedIn.credits === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, { main: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Part, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CoinGlyph, {}), signedIn.credits.unlimited === true ? t("creditsTotalUnlimitedValue") : formatNumber(signedIn.credits.total)] }) }),
|
|
927
1192
|
signedIn.credits === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditsPanel, {
|
|
928
1193
|
credits: signedIn.credits,
|
|
929
1194
|
t
|
|
@@ -934,7 +1199,7 @@ window.__ModuleLoader__.load({
|
|
|
934
1199
|
})
|
|
935
1200
|
]
|
|
936
1201
|
}) : tab === "models" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
937
|
-
className: workbuddy_module_css_default.
|
|
1202
|
+
className: workbuddy_module_css_default.panel,
|
|
938
1203
|
id: modelsTab.panelId,
|
|
939
1204
|
role: "tabpanel",
|
|
940
1205
|
"aria-labelledby": modelsTab.id,
|
|
@@ -943,17 +1208,18 @@ window.__ModuleLoader__.load({
|
|
|
943
1208
|
visibility: signedIn.visibility,
|
|
944
1209
|
toggling,
|
|
945
1210
|
disabled: busy,
|
|
1211
|
+
catalog: signedIn.catalog,
|
|
946
1212
|
t,
|
|
947
1213
|
onToggle: (model, visible, account) => {
|
|
948
1214
|
setVisibility(model, visible, account);
|
|
949
1215
|
}
|
|
950
1216
|
})
|
|
951
1217
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
952
|
-
className: workbuddy_module_css_default.
|
|
1218
|
+
className: workbuddy_module_css_default.panel,
|
|
953
1219
|
id: probeTab.panelId,
|
|
954
1220
|
role: "tabpanel",
|
|
955
1221
|
"aria-labelledby": probeTab.id,
|
|
956
|
-
children: signedIn.probe === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProbePanel, {
|
|
1222
|
+
children: signedIn.probe === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProbePanel$1, {
|
|
957
1223
|
probe: signedIn.probe,
|
|
958
1224
|
models: signedIn.models,
|
|
959
1225
|
busy,
|
|
@@ -966,7 +1232,7 @@ window.__ModuleLoader__.load({
|
|
|
966
1232
|
}
|
|
967
1233
|
})
|
|
968
1234
|
})
|
|
969
|
-
] }),
|
|
1235
|
+
}, tab)] }),
|
|
970
1236
|
status?.status === "signed-out" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
971
1237
|
className: status.reason === void 0 ? workbuddy_module_css_default.text : workbuddy_module_css_default.error,
|
|
972
1238
|
children: status.reason ?? t(variant.signedOutKey)
|
|
@@ -1068,39 +1334,32 @@ window.__ModuleLoader__.load({
|
|
|
1068
1334
|
signedOutHint: "Sign in once in the WorkBuddy desktop app; this plugin follows that sign-in automatically.",
|
|
1069
1335
|
signedOutHintAI: "Sign in once in the WorkBuddy AI desktop app; this plugin follows that sign-in automatically.",
|
|
1070
1336
|
signedIn: "Signed in",
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
accountHeading: "Account",
|
|
1337
|
+
signedInLabel: "Signed in as",
|
|
1338
|
+
sessionExpiryLabel: "Expires",
|
|
1074
1339
|
requestFailed: "Request failed",
|
|
1075
1340
|
statusRefreshFailed: "Refresh failed: {message} — showing the last known state",
|
|
1076
1341
|
statusResponseInvalid: "WorkBuddy returned an unreadable status reply",
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1342
|
+
catalogSourceFrom: "From",
|
|
1343
|
+
catalogSourceLive: "the app",
|
|
1344
|
+
catalogSourceSaved: "a saved copy",
|
|
1345
|
+
catalogSourceFallback: "the built-in list",
|
|
1346
|
+
catalogUpdatedAt: "Updated",
|
|
1080
1347
|
catalogError: "Last update failed: {message}",
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
refreshing: "Refreshing…",
|
|
1084
|
-
refreshModels: "Refresh model list",
|
|
1085
|
-
refreshingModels: "Refreshing models…",
|
|
1348
|
+
refreshAll: "Refresh all",
|
|
1349
|
+
refreshingAll: "Refreshing…",
|
|
1086
1350
|
tabLabel: "WorkBuddy detail",
|
|
1087
1351
|
tabCredits: "Credits",
|
|
1088
1352
|
tabModels: "Models",
|
|
1089
1353
|
tabProbe: "Detection",
|
|
1090
|
-
|
|
1091
|
-
creditsTotalUnlimited: "Total: Unlimited",
|
|
1354
|
+
creditsTotalUnlimitedValue: "Unlimited",
|
|
1092
1355
|
unlimitedQuota: "Unlimited",
|
|
1093
1356
|
packageEnterprise: "Enterprise quota",
|
|
1094
|
-
|
|
1095
|
-
percentRemaining: "{percent}% remaining",
|
|
1096
|
-
percentUnknown: "Remaining share unknown",
|
|
1097
|
-
exactRemaining: "{remain} / {size} remaining",
|
|
1357
|
+
packageRemaining: "{remain} / {size} left ({percent}%)",
|
|
1098
1358
|
creditPackageUnknownSize: "{remain} remaining",
|
|
1099
1359
|
creditsError: "Credit unavailable: {message}",
|
|
1100
1360
|
creditConsumed: "Used {credit}",
|
|
1101
1361
|
creditConsumedTitle: "Credit this message consumed, as reported by WorkBuddy",
|
|
1102
1362
|
creditRemainingUnlimited: "Unlimited",
|
|
1103
|
-
creditRemainingUnknown: "Credit unknown",
|
|
1104
1363
|
creditBalanceTitle: "Remaining credit on your {product} account",
|
|
1105
1364
|
freeModel: "Free",
|
|
1106
1365
|
badgeLimitedFree: "Limited-time free",
|
|
@@ -1113,7 +1372,13 @@ window.__ModuleLoader__.load({
|
|
|
1113
1372
|
contextUnknown: "no declared context window",
|
|
1114
1373
|
visibilityIntro: "Uncheck a model to hide it from the picker. The choice is saved per signed-in account; chats already using a hidden model keep working.",
|
|
1115
1374
|
visibilityStaleAccount: "The signed-in account changed — this change was not saved.",
|
|
1116
|
-
|
|
1375
|
+
probeDetectedCaption: "Detected",
|
|
1376
|
+
probeDetectedUnit: "",
|
|
1377
|
+
probeDetectedNone: "Nothing detected yet",
|
|
1378
|
+
/** Why the list contains models that need no detection — the list's own header. */
|
|
1379
|
+
probeListIntro: "Some models reason but declare no selectable effort levels.",
|
|
1380
|
+
/** What a run costs — the explanation belonging to the action. */
|
|
1381
|
+
probeCostNote: "Detecting sends a few real requests to one model and may consume a small amount of credit.",
|
|
1117
1382
|
probeStart: "Detect",
|
|
1118
1383
|
probeRedetect: "Detect again",
|
|
1119
1384
|
probeRunning: "Detecting {model}…",
|
|
@@ -1124,7 +1389,6 @@ window.__ModuleLoader__.load({
|
|
|
1124
1389
|
probeResultAt: "Detected {time}",
|
|
1125
1390
|
probeResultEmpty: "No reasoning models are being served right now.",
|
|
1126
1391
|
probeActionDeclared: "Declared",
|
|
1127
|
-
probeFailed: "Detection failed: {message}",
|
|
1128
1392
|
probeLabel: "Reasoning levels",
|
|
1129
1393
|
probePanelLevels: "Supported levels",
|
|
1130
1394
|
probePanelNoLevels: "No level can be selected",
|
|
@@ -1136,6 +1400,8 @@ window.__ModuleLoader__.load({
|
|
|
1136
1400
|
probePanelNotValidating: "This model does not check the effort parameter.",
|
|
1137
1401
|
probePanelDeclaredNone: "This model declares no selectable levels.",
|
|
1138
1402
|
probePanelFailed: "Detection did not finish. You can run it again.",
|
|
1403
|
+
panelCrashed: "The {panel} section stopped working.",
|
|
1404
|
+
panelRetry: "Try again",
|
|
1139
1405
|
probeTooltipIdle: "This model offers no levels yet — click to detect them",
|
|
1140
1406
|
probeTooltipRunning: "Detecting…",
|
|
1141
1407
|
probeTooltipLevels: "Detected levels: {levels}",
|
|
@@ -1183,39 +1449,32 @@ window.__ModuleLoader__.load({
|
|
|
1183
1449
|
signedOutHint: "在 WorkBuddy 桌面 App 里登录一次即可,插件会自动跟随当前登录的账号。",
|
|
1184
1450
|
signedOutHintAI: "在 WorkBuddy AI 国际版桌面 App 里登录一次即可,插件会自动跟随当前登录的账号。",
|
|
1185
1451
|
signedIn: "已登录",
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1452
|
+
signedInLabel: "已登录",
|
|
1453
|
+
sessionExpiryLabel: "有效期至",
|
|
1454
|
+
catalogSourceFrom: "来自",
|
|
1455
|
+
catalogSourceLive: "客户端实时读取",
|
|
1456
|
+
catalogSourceSaved: "已保存的副本",
|
|
1457
|
+
catalogSourceFallback: "内置列表",
|
|
1458
|
+
catalogUpdatedAt: "更新于",
|
|
1189
1459
|
requestFailed: "请求失败",
|
|
1190
1460
|
statusRefreshFailed: "刷新失败:{message} — 当前显示的是上次成功获取的状态",
|
|
1191
1461
|
statusResponseInvalid: "WorkBuddy 返回的状态数据无法识别",
|
|
1192
|
-
catalogLive: "模型列表更新于 {time}",
|
|
1193
|
-
catalogSaved: "当前显示已保存的模型列表,更新于 {time}",
|
|
1194
|
-
catalogFallback: "当前显示内置模型列表(尚未从 WorkBuddy 更新)",
|
|
1195
1462
|
catalogError: "上次更新失败:{message}",
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
refreshing: "正在刷新…",
|
|
1199
|
-
refreshModels: "刷新模型列表",
|
|
1200
|
-
refreshingModels: "正在刷新模型…",
|
|
1463
|
+
refreshAll: "刷新全部",
|
|
1464
|
+
refreshingAll: "正在刷新…",
|
|
1201
1465
|
tabLabel: "WorkBuddy 详情",
|
|
1202
1466
|
tabCredits: "积分",
|
|
1203
1467
|
tabModels: "模型",
|
|
1204
1468
|
tabProbe: "检测",
|
|
1205
|
-
|
|
1206
|
-
creditsTotalUnlimited: "合计:不限额",
|
|
1469
|
+
creditsTotalUnlimitedValue: "不限额",
|
|
1207
1470
|
unlimitedQuota: "不限额",
|
|
1208
1471
|
packageEnterprise: "企业额度",
|
|
1209
|
-
|
|
1210
|
-
percentRemaining: "剩余 {percent}%",
|
|
1211
|
-
percentUnknown: "剩余占比未知",
|
|
1212
|
-
exactRemaining: "剩余 {remain} / {size}",
|
|
1472
|
+
packageRemaining: "剩余 {remain} / {size}({percent}%)",
|
|
1213
1473
|
creditPackageUnknownSize: "剩余 {remain}",
|
|
1214
1474
|
creditsError: "积分查询失败:{message}",
|
|
1215
1475
|
creditConsumed: "共消耗 {credit}",
|
|
1216
1476
|
creditConsumedTitle: "本条消息消耗的积分(由 WorkBuddy 返回)",
|
|
1217
1477
|
creditRemainingUnlimited: "不限额",
|
|
1218
|
-
creditRemainingUnknown: "积分未知",
|
|
1219
1478
|
creditBalanceTitle: "{product} 账号剩余积分",
|
|
1220
1479
|
freeModel: "免费",
|
|
1221
1480
|
badgeLimitedFree: "限时免费",
|
|
@@ -1228,7 +1487,11 @@ window.__ModuleLoader__.load({
|
|
|
1228
1487
|
contextUnknown: "未声明上下文窗口",
|
|
1229
1488
|
visibilityIntro: "取消勾选即可将该模型从选择器中隐藏;按登录账号分别保存,已在用该模型的会话不受影响。",
|
|
1230
1489
|
visibilityStaleAccount: "登录账号已切换——本次修改未保存。",
|
|
1231
|
-
|
|
1490
|
+
probeDetectedCaption: "已检测",
|
|
1491
|
+
probeDetectedUnit: "个模型",
|
|
1492
|
+
probeDetectedNone: "尚未检测",
|
|
1493
|
+
probeListIntro: "部分模型具备思考能力,但没有声明可选档位。",
|
|
1494
|
+
probeCostNote: "检测会向一个模型发送少量真实请求以确认可用档位,可能消耗少量积分。",
|
|
1232
1495
|
probeStart: "开始检测",
|
|
1233
1496
|
probeRedetect: "重新检测",
|
|
1234
1497
|
probeRunning: "正在检测 {model}…",
|
|
@@ -1239,7 +1502,6 @@ window.__ModuleLoader__.load({
|
|
|
1239
1502
|
probeResultAt: "检测于 {time}",
|
|
1240
1503
|
probeResultEmpty: "当前没有提供可选档位的推理模型。",
|
|
1241
1504
|
probeActionDeclared: "已声明",
|
|
1242
|
-
probeFailed: "检测失败:{message}",
|
|
1243
1505
|
probeLabel: "推理档位",
|
|
1244
1506
|
probePanelLevels: "支持的档位",
|
|
1245
1507
|
probePanelNoLevels: "无可选档位",
|
|
@@ -1251,6 +1513,8 @@ window.__ModuleLoader__.load({
|
|
|
1251
1513
|
probePanelNotValidating: "该模型不校验档位参数。",
|
|
1252
1514
|
probePanelDeclaredNone: "上游未声明可选档位。",
|
|
1253
1515
|
probePanelFailed: "检测未完成,可以再检测一次。",
|
|
1516
|
+
panelCrashed: "{panel}这一块无法显示。",
|
|
1517
|
+
panelRetry: "重试",
|
|
1254
1518
|
probeTooltipIdle: "该模型暂无档位,点击可检测",
|
|
1255
1519
|
probeTooltipRunning: "正在检测…",
|
|
1256
1520
|
probeTooltipLevels: "检测出的档位:{levels}",
|
|
@@ -1399,8 +1663,8 @@ window.__ModuleLoader__.load({
|
|
|
1399
1663
|
});
|
|
1400
1664
|
}
|
|
1401
1665
|
//#endregion
|
|
1402
|
-
//#region \0workbuddy-css
|
|
1403
|
-
const css$2 = ".
|
|
1666
|
+
//#region \0workbuddy-css:D:\ProjectSomething\dsh-plugins\dsh-workbuddy-bridge\src\client\probe-control.module.css.js
|
|
1667
|
+
const css$2 = ".Ivd5xG_wrapper{align-items:center;display:inline-flex;position:relative}.Ivd5xG_trigger{corner-shape:round;cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-secondary);background:0 0;border:none;border-radius:999px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex;position:relative}.Ivd5xG_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Ivd5xG_trigger:disabled{cursor:default;color:var(--dsw-alias-label-dimmed)}.Ivd5xG_trigger:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}.Ivd5xG_panel{isolation:isolate;z-index:1100;box-sizing:border-box;border-radius:var(--dsw-radius-lg);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:max-content;min-width:min(280px,100vw - 24px);max-width:min(360px,100vw - 24px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;border:0;padding:12px;font-size:12px;line-height:1.5;position:fixed}.Ivd5xG_panel:before{z-index:-1;border-radius:inherit;background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);content:\"\";pointer-events:none;position:absolute;inset:0}.Ivd5xG_panelTitle{color:var(--dsw-alias-label-primary);align-items:center;gap:8px;font-size:13px;font-weight:500;line-height:1.5;display:flex}.Ivd5xG_panelTitleIcon{color:var(--dsw-alias-label-secondary);flex:none;align-items:center;display:inline-flex}.Ivd5xG_panelTitleText{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Ivd5xG_titleRule{border-top:.5px solid var(--dsw-alias-border-l2);margin:8px 0 10px}.Ivd5xG_levelsLabel{color:var(--dsw-alias-label-tertiary);margin:0 0 2px;font-size:12px;line-height:1.5}.Ivd5xG_levels{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:13px;font-weight:500;line-height:1.5}.Ivd5xG_note,.Ivd5xG_dim{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.6}.Ivd5xG_dim{margin-top:2px}.Ivd5xG_panelActions{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}";
|
|
1404
1668
|
const tagId$2 = "dsh-workbuddy-bridge/probe-control.module.css";
|
|
1405
1669
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
1406
1670
|
const tag = document.createElement("style");
|
|
@@ -1410,18 +1674,18 @@ window.__ModuleLoader__.load({
|
|
|
1410
1674
|
document.head.appendChild(tag);
|
|
1411
1675
|
}
|
|
1412
1676
|
var probe_control_module_css_default = {
|
|
1413
|
-
"dim": "
|
|
1414
|
-
"levels": "
|
|
1415
|
-
"levelsLabel": "
|
|
1416
|
-
"note": "
|
|
1417
|
-
"panel": "
|
|
1418
|
-
"panelActions": "
|
|
1419
|
-
"panelTitle": "
|
|
1420
|
-
"panelTitleIcon": "
|
|
1421
|
-
"panelTitleText": "
|
|
1422
|
-
"titleRule": "
|
|
1423
|
-
"trigger": "
|
|
1424
|
-
"wrapper": "
|
|
1677
|
+
"dim": "Ivd5xG_dim",
|
|
1678
|
+
"levels": "Ivd5xG_levels",
|
|
1679
|
+
"levelsLabel": "Ivd5xG_levelsLabel",
|
|
1680
|
+
"note": "Ivd5xG_note",
|
|
1681
|
+
"panel": "Ivd5xG_panel",
|
|
1682
|
+
"panelActions": "Ivd5xG_panelActions",
|
|
1683
|
+
"panelTitle": "Ivd5xG_panelTitle",
|
|
1684
|
+
"panelTitleIcon": "Ivd5xG_panelTitleIcon",
|
|
1685
|
+
"panelTitleText": "Ivd5xG_panelTitleText",
|
|
1686
|
+
"titleRule": "Ivd5xG_titleRule",
|
|
1687
|
+
"trigger": "Ivd5xG_trigger",
|
|
1688
|
+
"wrapper": "Ivd5xG_wrapper"
|
|
1425
1689
|
};
|
|
1426
1690
|
//#endregion
|
|
1427
1691
|
//#region src/client/probe-control.tsx
|
|
@@ -1724,69 +1988,115 @@ window.__ModuleLoader__.load({
|
|
|
1724
1988
|
},
|
|
1725
1989
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProbeIcon, { lit })
|
|
1726
1990
|
})
|
|
1727
|
-
}), open ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1728
|
-
|
|
1729
|
-
className: probe_control_module_css_default.panel,
|
|
1991
|
+
}), open ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProbePanel, {
|
|
1992
|
+
panelRef,
|
|
1730
1993
|
style: position ?? MEASURE_STYLE,
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1745
|
-
className: probe_control_module_css_default.titleRule,
|
|
1746
|
-
"aria-hidden": true
|
|
1747
|
-
}),
|
|
1748
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1749
|
-
className: probe_control_module_css_default.levelsLabel,
|
|
1750
|
-
children: t("probePanelLevels")
|
|
1751
|
-
}),
|
|
1752
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1753
|
-
className: probe_control_module_css_default.levels,
|
|
1754
|
-
role: "status",
|
|
1755
|
-
"aria-live": "polite",
|
|
1756
|
-
children: levels ?? t("probePanelNoLevels")
|
|
1757
|
-
}),
|
|
1758
|
-
notValidating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1759
|
-
className: probe_control_module_css_default.dim,
|
|
1760
|
-
children: t("probePanelNotValidating")
|
|
1761
|
-
}) : null,
|
|
1762
|
-
!notValidating && levels === void 0 && !detectable && shown !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1763
|
-
className: probe_control_module_css_default.dim,
|
|
1764
|
-
children: t("probePanelDeclaredNone")
|
|
1765
|
-
}) : null,
|
|
1766
|
-
failed && shown === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1767
|
-
className: probe_control_module_css_default.dim,
|
|
1768
|
-
children: t("probePanelFailed")
|
|
1769
|
-
}) : null,
|
|
1770
|
-
detectable && levels === void 0 && !notValidating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1771
|
-
className: probe_control_module_css_default.note,
|
|
1772
|
-
children: t("probePanelNote")
|
|
1773
|
-
}) : null,
|
|
1774
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1775
|
-
className: probe_control_module_css_default.panelActions,
|
|
1776
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1777
|
-
size: "sm",
|
|
1778
|
-
variant: "primary",
|
|
1779
|
-
disabled: actionDisabled,
|
|
1780
|
-
onClick: () => {
|
|
1781
|
-
detect();
|
|
1782
|
-
},
|
|
1783
|
-
children: busy ? t("probePanelDetecting") : !detectable ? t("probePanelNotNeeded") : levels === void 0 ? t("probePanelDetect") : t("probePanelRedetect")
|
|
1784
|
-
})
|
|
1785
|
-
})
|
|
1786
|
-
]
|
|
1994
|
+
model,
|
|
1995
|
+
lit,
|
|
1996
|
+
levels,
|
|
1997
|
+
notValidating,
|
|
1998
|
+
detectable,
|
|
1999
|
+
failed,
|
|
2000
|
+
shown,
|
|
2001
|
+
busy,
|
|
2002
|
+
actionDisabled,
|
|
2003
|
+
onDetect: () => {
|
|
2004
|
+
detect();
|
|
2005
|
+
},
|
|
2006
|
+
t
|
|
1787
2007
|
}), document.body) : null]
|
|
1788
2008
|
});
|
|
1789
2009
|
}
|
|
2010
|
+
/**
|
|
2011
|
+
* The open popover's contents.
|
|
2012
|
+
*
|
|
2013
|
+
* Split out of {@link ModelProbe} because the panel is a self-contained reading
|
|
2014
|
+
* of one model — a title, the levels, why there are none, and the one action —
|
|
2015
|
+
* while the parent is a state machine (reads, races, an anchored portal). The
|
|
2016
|
+
* boundary is *what the panel needs to know*, not a slice of the parent's state:
|
|
2017
|
+
* every prop here is already computed by the time the panel renders, and the
|
|
2018
|
+
* panel holds none of its own. That is what keeps the split from moving the
|
|
2019
|
+
* implicit constraints the parent carries.
|
|
2020
|
+
*/
|
|
2021
|
+
function ProbePanel({ panelRef, style, model, lit, levels, notValidating, detectable, failed, shown, busy, actionDisabled, onDetect, t }) {
|
|
2022
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2023
|
+
ref: panelRef,
|
|
2024
|
+
className: probe_control_module_css_default.panel,
|
|
2025
|
+
style,
|
|
2026
|
+
role: "dialog",
|
|
2027
|
+
"aria-label": t("probeLabel"),
|
|
2028
|
+
children: [
|
|
2029
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2030
|
+
className: probe_control_module_css_default.panelTitle,
|
|
2031
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2032
|
+
className: probe_control_module_css_default.panelTitleIcon,
|
|
2033
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProbeIcon, { lit })
|
|
2034
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2035
|
+
className: probe_control_module_css_default.panelTitleText,
|
|
2036
|
+
children: model
|
|
2037
|
+
})]
|
|
2038
|
+
}),
|
|
2039
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2040
|
+
className: probe_control_module_css_default.titleRule,
|
|
2041
|
+
"aria-hidden": true
|
|
2042
|
+
}),
|
|
2043
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2044
|
+
className: probe_control_module_css_default.levelsLabel,
|
|
2045
|
+
children: t("probePanelLevels")
|
|
2046
|
+
}),
|
|
2047
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2048
|
+
className: probe_control_module_css_default.levels,
|
|
2049
|
+
role: "status",
|
|
2050
|
+
"aria-live": "polite",
|
|
2051
|
+
children: levels ?? t("probePanelNoLevels")
|
|
2052
|
+
}),
|
|
2053
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelReason, {
|
|
2054
|
+
notValidating,
|
|
2055
|
+
levels,
|
|
2056
|
+
detectable,
|
|
2057
|
+
shown,
|
|
2058
|
+
failed,
|
|
2059
|
+
t
|
|
2060
|
+
}),
|
|
2061
|
+
detectable && levels === void 0 && !notValidating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2062
|
+
className: probe_control_module_css_default.note,
|
|
2063
|
+
children: t("probePanelNote")
|
|
2064
|
+
}) : null,
|
|
2065
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2066
|
+
className: probe_control_module_css_default.panelActions,
|
|
2067
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2068
|
+
size: "sm",
|
|
2069
|
+
variant: "primary",
|
|
2070
|
+
disabled: actionDisabled,
|
|
2071
|
+
onClick: onDetect,
|
|
2072
|
+
children: busy ? t("probePanelDetecting") : !detectable ? t("probePanelNotNeeded") : levels === void 0 ? t("probePanelDetect") : t("probePanelRedetect")
|
|
2073
|
+
})
|
|
2074
|
+
})
|
|
2075
|
+
]
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* The one line explaining *why* there are no levels, when that is the answer.
|
|
2080
|
+
*
|
|
2081
|
+
* Three facts, kept apart on purpose — see the call site. Extracted so the three
|
|
2082
|
+
* mutually exclusive branches read as one decision rather than three adjacent
|
|
2083
|
+
* conditionals interleaved with unrelated markup.
|
|
2084
|
+
*/
|
|
2085
|
+
function PanelReason({ notValidating, levels, detectable, shown, failed, t }) {
|
|
2086
|
+
if (notValidating) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2087
|
+
className: probe_control_module_css_default.dim,
|
|
2088
|
+
children: t("probePanelNotValidating")
|
|
2089
|
+
});
|
|
2090
|
+
if (levels === void 0 && !detectable && shown !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2091
|
+
className: probe_control_module_css_default.dim,
|
|
2092
|
+
children: t("probePanelDeclaredNone")
|
|
2093
|
+
});
|
|
2094
|
+
if (failed && shown === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2095
|
+
className: probe_control_module_css_default.dim,
|
|
2096
|
+
children: t("probePanelFailed")
|
|
2097
|
+
});
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
1790
2100
|
/** The bulb's body — the maintainer's artwork, one filled path with the base cut out. */
|
|
1791
2101
|
const BULB_BODY = "M496 64C681.6 64 832 208.896 832 387.648c0 124.544-73.152 232.704-180.352 286.784v24.256c0 6.912-0.64 13.76-1.856 20.288a56.32 56.32 0 0 1 20.672 20.416 54.848 54.848 0 0 1 7.552 27.712v37.312c0 29.312-23.04 53.312-52.288 55.808l-2.816 0.192h-23.04c0 54.976-46.336 99.584-103.424 99.584-57.024 0-103.296-44.544-103.296-99.584h-19.776l-2.24-0.128h-3.84a58.24 58.24 0 0 1-36.48-18.432 55.808 55.808 0 0 1-14.72-37.44v-37.312c0-20.16 11.008-37.888 27.328-47.744a104.064 104.064 0 0 1-1.984-20.672v-23.744C233.6 621.056 160 512.576 160 387.584 160.064 208.96 310.4 64 496 64z m-45.632 796.288c0 24.064 20.48 43.712 46.08 43.712 25.728 0 46.144-19.712 46.208-43.52v-0.192H450.368z m-76.992-56h247.296l0.064-37.056-0.512-0.32H373.632l-0.256 37.376zM496 120.064c-154.112 0-278.656 120-278.656 267.52 0 100.8 58.624 191.68 150.208 237.44l31.104 15.68 0.064 50.56c0 3.968 0.384 7.552 0.896 10.816l0.576 1.984H467.84V704h70.4v-0.128l55.488-0.32 0.512-1.472c0.64-3.776 0.96-7.552 0.96-11.328l-0.96-50.56 31.04-15.616c91.2-45.952 149.312-136.576 149.312-236.992 0-147.584-124.544-267.648-278.656-267.648v0.128z";
|
|
1792
2102
|
/** The bolt drawn inside the bulb once a detection has landed. */
|
|
@@ -1907,8 +2217,8 @@ window.__ModuleLoader__.load({
|
|
|
1907
2217
|
return { credits };
|
|
1908
2218
|
}
|
|
1909
2219
|
//#endregion
|
|
1910
|
-
//#region \0workbuddy-css
|
|
1911
|
-
const css$1 = ".
|
|
2220
|
+
//#region \0workbuddy-css:D:\ProjectSomething\dsh-plugins\dsh-workbuddy-bridge\src\client\credit-label.module.css.js
|
|
2221
|
+
const css$1 = ".VopAXG_label{white-space:nowrap;font-size:calc(var(--dsh-content-font-size-secondary,13px) - 1px);color:var(--dsw-alias-label-tertiary);padding-left:4px;line-height:1}";
|
|
1912
2222
|
const tagId$1 = "dsh-workbuddy-bridge/credit-label.module.css";
|
|
1913
2223
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
1914
2224
|
const tag = document.createElement("style");
|
|
@@ -1917,7 +2227,7 @@ window.__ModuleLoader__.load({
|
|
|
1917
2227
|
tag.textContent = css$1;
|
|
1918
2228
|
document.head.appendChild(tag);
|
|
1919
2229
|
}
|
|
1920
|
-
var credit_label_module_css_default = { "label": "
|
|
2230
|
+
var credit_label_module_css_default = { "label": "VopAXG_label" };
|
|
1921
2231
|
//#endregion
|
|
1922
2232
|
//#region src/client/credit-label.tsx
|
|
1923
2233
|
/**
|
|
@@ -1965,8 +2275,8 @@ window.__ModuleLoader__.load({
|
|
|
1965
2275
|
});
|
|
1966
2276
|
}
|
|
1967
2277
|
//#endregion
|
|
1968
|
-
//#region \0workbuddy-css
|
|
1969
|
-
const css = ".
|
|
2278
|
+
//#region \0workbuddy-css:D:\ProjectSomething\dsh-plugins\dsh-workbuddy-bridge\src\client\credit-balance.module.css.js
|
|
2279
|
+
const css = ".zUqKXG_readout{white-space:nowrap;height:28px;color:var(--dsw-alias-label-tertiary);align-items:center;gap:4px;display:inline-flex}.zUqKXG_amount{font-size:calc(var(--dsh-content-font-size-secondary,13px) - 1px);font-variant-numeric:tabular-nums;line-height:1}";
|
|
1970
2280
|
const tagId = "dsh-workbuddy-bridge/credit-balance.module.css";
|
|
1971
2281
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1972
2282
|
const tag = document.createElement("style");
|
|
@@ -1976,9 +2286,8 @@ window.__ModuleLoader__.load({
|
|
|
1976
2286
|
document.head.appendChild(tag);
|
|
1977
2287
|
}
|
|
1978
2288
|
var credit_balance_module_css_default = {
|
|
1979
|
-
"amount": "
|
|
1980
|
-
"
|
|
1981
|
-
"readout": "Rbiksq_readout"
|
|
2289
|
+
"amount": "zUqKXG_amount",
|
|
2290
|
+
"readout": "zUqKXG_readout"
|
|
1982
2291
|
};
|
|
1983
2292
|
//#endregion
|
|
1984
2293
|
//#region src/client/credit-balance.tsx
|
|
@@ -2098,54 +2407,6 @@ window.__ModuleLoader__.load({
|
|
|
2098
2407
|
})]
|
|
2099
2408
|
});
|
|
2100
2409
|
}
|
|
2101
|
-
/**
|
|
2102
|
-
* The credit glyph: a stack of three coins, drawn as outlines.
|
|
2103
|
-
*
|
|
2104
|
-
* This repository draws its own ink when the host has nothing to lend, and the
|
|
2105
|
-
* host's 188 icons contain no coin, credit, wallet or currency shape at all
|
|
2106
|
-
* (checked against the installed `dsh-client-ui-primitives`) — so this is
|
|
2107
|
-
* artwork of ours, exactly as the reasoning-level bulb beside it is.
|
|
2108
|
-
*
|
|
2109
|
-
* **Stroked, not filled.** A filled stack was drawn first and rejected on
|
|
2110
|
-
* sight: the bulb reads as a thin outline even though it is one filled path, so
|
|
2111
|
-
* a solid glyph beside it looked like a different icon set. The line width is
|
|
2112
|
-
* the host's own `1` on this grid, which is what makes the two read as peers.
|
|
2113
|
-
*
|
|
2114
|
-
* **Flatter than a cylinder.** The construction is the host's `database` idiom —
|
|
2115
|
-
* a full top ellipse, straight walls, and a *front-half* arc per level below —
|
|
2116
|
-
* so the ellipse's minor axis is what separates "a stack of coins" from "a
|
|
2117
|
-
* database". At `ry = 1.25` it reads as coins; at `1.6` it reads as the
|
|
2118
|
-
* database glyph with extra lines (both were rendered at 64px to check).
|
|
2119
|
-
*
|
|
2120
|
-
* Drawn on the host's own 16-unit grid with `viewBox="0 0 16 16"`, at the same
|
|
2121
|
-
* 16px as the bulb, because the two sit in one row and are read together: a
|
|
2122
|
-
* glyph at a different size would make the row look assembled from two sources.
|
|
2123
|
-
* `currentColor` throughout, so both themes come from the row's colour token —
|
|
2124
|
-
* no literal colour and no `[data-ds-dark-theme]` branch here.
|
|
2125
|
-
*/
|
|
2126
|
-
function CoinGlyph() {
|
|
2127
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
2128
|
-
width: "16",
|
|
2129
|
-
height: "16",
|
|
2130
|
-
viewBox: "0 0 16 16",
|
|
2131
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
2132
|
-
fill: "none",
|
|
2133
|
-
stroke: "currentColor",
|
|
2134
|
-
strokeWidth: "1",
|
|
2135
|
-
"aria-hidden": "true",
|
|
2136
|
-
className: credit_balance_module_css_default.glyph,
|
|
2137
|
-
children: [
|
|
2138
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ellipse", {
|
|
2139
|
-
cx: "8",
|
|
2140
|
-
cy: "4.7",
|
|
2141
|
-
rx: "4.7",
|
|
2142
|
-
ry: "1.25"
|
|
2143
|
-
}),
|
|
2144
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.3 4.7V10.7A4.7 1.25 0 0 0 12.7 10.7V4.7" }),
|
|
2145
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.3 7.7A4.7 1.25 0 0 0 12.7 7.7" })
|
|
2146
|
-
]
|
|
2147
|
-
});
|
|
2148
|
-
}
|
|
2149
2410
|
//#endregion
|
|
2150
2411
|
//#region src/client/config-controller.ts
|
|
2151
2412
|
/**
|