@huanlin/dsh-plugin-preface-context 0.1.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 +113 -0
- package/cordis.patch.yml +11 -0
- package/lib/client.js +794 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +127 -0
- package/lib/types/client/bind-snapshot-selector.d.ts +7 -0
- package/lib/types/client/bind-snapshot-selector.js +19 -0
- package/lib/types/client/client/bind-snapshot-selector.d.ts +7 -0
- package/lib/types/client/client/bind-snapshot-selector.js +19 -0
- package/lib/types/client/client/index.d.ts +39 -0
- package/lib/types/client/client/index.js +50 -0
- package/lib/types/client/client/locales.d.ts +7 -0
- package/lib/types/client/client/locales.js +41 -0
- package/lib/types/client/client/preface-card-controller.d.ts +94 -0
- package/lib/types/client/client/preface-card-controller.js +181 -0
- package/lib/types/client/client/preface-card.css.d.ts +53 -0
- package/lib/types/client/client/preface-card.css.js +327 -0
- package/lib/types/client/client/preface-card.d.ts +27 -0
- package/lib/types/client/client/preface-card.js +41 -0
- package/lib/types/client/config.d.ts +41 -0
- package/lib/types/client/config.js +42 -0
- package/lib/types/client/index.d.ts +39 -0
- package/lib/types/client/index.js +50 -0
- package/lib/types/client/locales.d.ts +7 -0
- package/lib/types/client/locales.js +41 -0
- package/lib/types/client/preface-card-controller.d.ts +94 -0
- package/lib/types/client/preface-card-controller.js +181 -0
- package/lib/types/client/preface-card.css.d.ts +53 -0
- package/lib/types/client/preface-card.css.js +327 -0
- package/lib/types/client/preface-card.d.ts +27 -0
- package/lib/types/client/preface-card.js +41 -0
- package/lib/types/config.d.ts +40 -0
- package/lib/types/config.js +42 -0
- package/lib/types/index.d.ts +46 -0
- package/lib/types/index.js +64 -0
- package/lib/types/settings.d.ts +50 -0
- package/lib/types/settings.js +85 -0
- package/package.json +130 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: "@huanlin/dsh-plugin-preface-context", 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 __deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
29
|
+
__deepseek_ai_dsh_client_ui_primitives = __toESM(__deepseek_ai_dsh_client_ui_primitives);
|
|
30
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
react_jsx_runtime = __toESM(react_jsx_runtime);
|
|
32
|
+
|
|
33
|
+
//#region node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
34
|
+
function r(e) {
|
|
35
|
+
var t, f, n = "";
|
|
36
|
+
if ("string" == typeof e || "number" == typeof e) n += e;
|
|
37
|
+
else if ("object" == typeof e) if (Array.isArray(e)) {
|
|
38
|
+
var o = e.length;
|
|
39
|
+
for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
|
|
40
|
+
} else for (f in e) e[f] && (n && (n += " "), n += f);
|
|
41
|
+
return n;
|
|
42
|
+
}
|
|
43
|
+
function clsx() {
|
|
44
|
+
for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
var clsx_default = clsx;
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/client/preface-card.css.ts
|
|
51
|
+
/**
|
|
52
|
+
* Card styles + runtime style injection for the preface-context settings
|
|
53
|
+
* card.
|
|
54
|
+
*
|
|
55
|
+
* The DSH client loader never serves `.css` artifacts — every style must be
|
|
56
|
+
* injected inside the bundle's factory closure (the same contract the
|
|
57
|
+
* upstream tsdown.client preset implements with lightningcss). A plain
|
|
58
|
+
* template-string stylesheet installed once at plugin activation is the slim
|
|
59
|
+
* equivalent for a hand-rolled bundle: static, prefixed class names
|
|
60
|
+
* (`dsh-pfc-*`, unique in the document) replace the hashed CSS-modules map,
|
|
61
|
+
* and the `<style data-plugin-css>` tag is removed when the plugin unloads.
|
|
62
|
+
*
|
|
63
|
+
* Colors resolve through `--dsw-alias-*` tokens so the card adapts to the
|
|
64
|
+
* light/dark theme.
|
|
65
|
+
*
|
|
66
|
+
* @module @huanlin/dsh-plugin-preface-context/client/preface-card.css
|
|
67
|
+
*/
|
|
68
|
+
/** Class-name map consumed by the card component (CSS-modules replacement). */
|
|
69
|
+
const css = {
|
|
70
|
+
card: "dsh-pfc-card",
|
|
71
|
+
cardOpen: "dsh-pfc-card--open",
|
|
72
|
+
header: "dsh-pfc-header",
|
|
73
|
+
headText: "dsh-pfc-head-text",
|
|
74
|
+
name: "dsh-pfc-name",
|
|
75
|
+
description: "dsh-pfc-description",
|
|
76
|
+
pending: "dsh-pfc-pending",
|
|
77
|
+
chevron: "dsh-pfc-chevron",
|
|
78
|
+
chevronOpen: "dsh-pfc-chevron--open",
|
|
79
|
+
body: "dsh-pfc-body",
|
|
80
|
+
readOnly: "dsh-pfc-readonly",
|
|
81
|
+
field: "dsh-pfc-field",
|
|
82
|
+
head: "dsh-pfc-field-head",
|
|
83
|
+
label: "dsh-pfc-label",
|
|
84
|
+
badges: "dsh-pfc-badges",
|
|
85
|
+
badge: "dsh-pfc-badge",
|
|
86
|
+
reset: "dsh-pfc-reset",
|
|
87
|
+
textarea: "dsh-pfc-textarea",
|
|
88
|
+
toggleRow: "dsh-pfc-toggle-row",
|
|
89
|
+
toggle: "dsh-pfc-toggle",
|
|
90
|
+
toggleOn: "dsh-pfc-toggle--on",
|
|
91
|
+
knob: "dsh-pfc-knob",
|
|
92
|
+
knobOn: "dsh-pfc-knob--on",
|
|
93
|
+
hint: "dsh-pfc-hint",
|
|
94
|
+
footer: "dsh-pfc-footer",
|
|
95
|
+
failed: "dsh-pfc-failed",
|
|
96
|
+
discard: "dsh-pfc-discard",
|
|
97
|
+
save: "dsh-pfc-save"
|
|
98
|
+
};
|
|
99
|
+
/** `data-plugin-css` tag id of the injected stylesheet. */
|
|
100
|
+
const STYLE_TAG_ID = "@huanlin/dsh-plugin-preface-context/preface-card.css";
|
|
101
|
+
/** The card stylesheet (injected as one tagged `<style>` at activation). */
|
|
102
|
+
const CSS = `
|
|
103
|
+
.dsh-pfc-card {
|
|
104
|
+
list-style: none;
|
|
105
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));
|
|
106
|
+
background: var(--dsw-alias-bg-layer-3, transparent);
|
|
107
|
+
border-radius: 12px;
|
|
108
|
+
transition: border-color 0.16s, background 0.16s;
|
|
109
|
+
overflow: hidden;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.dsh-pfc-card--open {
|
|
113
|
+
border-color: var(--dsw-alias-border-l3, rgba(128, 128, 128, 0.35));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.dsh-pfc-header {
|
|
117
|
+
display: flex;
|
|
118
|
+
width: 100%;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 12px;
|
|
121
|
+
padding: 14px 16px;
|
|
122
|
+
font: inherit;
|
|
123
|
+
color: inherit;
|
|
124
|
+
text-align: left;
|
|
125
|
+
background: transparent;
|
|
126
|
+
border: 0;
|
|
127
|
+
cursor: pointer;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.dsh-pfc-head-text {
|
|
131
|
+
display: flex;
|
|
132
|
+
flex: 1 1 auto;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
gap: 4px;
|
|
135
|
+
min-width: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.dsh-pfc-name {
|
|
139
|
+
font-size: 15px;
|
|
140
|
+
font-weight: 600;
|
|
141
|
+
line-height: 1.4;
|
|
142
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.dsh-pfc-description {
|
|
146
|
+
font-size: 13px;
|
|
147
|
+
line-height: 1.5;
|
|
148
|
+
color: var(--dsw-alias-label-tertiary, rgba(128, 128, 128, 0.7));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.dsh-pfc-pending {
|
|
152
|
+
flex: none;
|
|
153
|
+
white-space: nowrap;
|
|
154
|
+
font-size: 11px;
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
line-height: 17px;
|
|
157
|
+
padding: 1px 8px;
|
|
158
|
+
border-radius: 999px;
|
|
159
|
+
color: var(--dsw-alias-label-secondary, inherit);
|
|
160
|
+
background: var(--dsw-alias-bg-module-platform, rgba(128, 128, 128, 0.12));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.dsh-pfc-chevron {
|
|
164
|
+
flex: none;
|
|
165
|
+
display: inline-flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
color: var(--dsw-alias-label-tertiary, inherit);
|
|
168
|
+
transition: transform 0.16s;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.dsh-pfc-chevron--open {
|
|
172
|
+
transform: rotate(180deg);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.dsh-pfc-body {
|
|
176
|
+
margin: 0 16px;
|
|
177
|
+
padding: 12px 0 4px;
|
|
178
|
+
border-top: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.dsh-pfc-readonly {
|
|
182
|
+
margin: 0 0 8px;
|
|
183
|
+
font-size: 12px;
|
|
184
|
+
line-height: 1.5;
|
|
185
|
+
color: var(--dsw-alias-label-tertiary, rgba(128, 128, 128, 0.7));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.dsh-pfc-field {
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
gap: 4px;
|
|
192
|
+
margin: 0 0 12px;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.dsh-pfc-field-head {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
gap: 8px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.dsh-pfc-label {
|
|
202
|
+
font-size: 13px;
|
|
203
|
+
font-weight: 500;
|
|
204
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.dsh-pfc-badges {
|
|
208
|
+
display: flex;
|
|
209
|
+
align-items: center;
|
|
210
|
+
gap: 6px;
|
|
211
|
+
margin-left: auto;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.dsh-pfc-badge {
|
|
215
|
+
font-size: 11px;
|
|
216
|
+
font-weight: 500;
|
|
217
|
+
line-height: 17px;
|
|
218
|
+
padding: 1px 8px;
|
|
219
|
+
border-radius: 999px;
|
|
220
|
+
color: var(--dsw-alias-label-secondary, inherit);
|
|
221
|
+
background: var(--dsw-alias-bg-module-platform, rgba(128, 128, 128, 0.12));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.dsh-pfc-reset {
|
|
225
|
+
appearance: none;
|
|
226
|
+
font: inherit;
|
|
227
|
+
font-size: 12px;
|
|
228
|
+
padding: 0;
|
|
229
|
+
border: 0;
|
|
230
|
+
background: transparent;
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
color: var(--dsw-alias-brand-primary, #0a84ff);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.dsh-pfc-reset:disabled {
|
|
236
|
+
cursor: not-allowed;
|
|
237
|
+
opacity: 0.5;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.dsh-pfc-textarea {
|
|
241
|
+
width: 100%;
|
|
242
|
+
box-sizing: border-box;
|
|
243
|
+
min-height: 96px;
|
|
244
|
+
resize: vertical;
|
|
245
|
+
padding: 6px 10px;
|
|
246
|
+
font-family: var(--dsw-font-mono, ui-monospace, monospace);
|
|
247
|
+
font-size: 13px;
|
|
248
|
+
line-height: 1.5;
|
|
249
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
250
|
+
background: var(--dsw-alias-bg-layer-3, transparent);
|
|
251
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));
|
|
252
|
+
border-radius: 8px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.dsh-pfc-textarea:focus {
|
|
256
|
+
outline: none;
|
|
257
|
+
border-color: var(--dsw-alias-brand-primary, #0a84ff);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.dsh-pfc-textarea:disabled {
|
|
261
|
+
opacity: 0.6;
|
|
262
|
+
cursor: not-allowed;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.dsh-pfc-toggle-row {
|
|
266
|
+
display: flex;
|
|
267
|
+
align-items: center;
|
|
268
|
+
gap: 10px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.dsh-pfc-toggle {
|
|
272
|
+
position: relative;
|
|
273
|
+
width: 40px;
|
|
274
|
+
height: 22px;
|
|
275
|
+
flex: none;
|
|
276
|
+
padding: 0;
|
|
277
|
+
background: var(--dsw-alias-bg-module-platform, rgba(128, 128, 128, 0.12));
|
|
278
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));
|
|
279
|
+
border-radius: 999px;
|
|
280
|
+
cursor: pointer;
|
|
281
|
+
transition: background 0.16s, border-color 0.16s;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.dsh-pfc-toggle--on {
|
|
285
|
+
background: var(--dsw-alias-brand-primary, #0a84ff);
|
|
286
|
+
border-color: var(--dsw-alias-brand-primary, #0a84ff);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.dsh-pfc-knob {
|
|
290
|
+
position: absolute;
|
|
291
|
+
top: 2px;
|
|
292
|
+
left: 2px;
|
|
293
|
+
width: 16px;
|
|
294
|
+
height: 16px;
|
|
295
|
+
background: var(--dsw-alias-bg-layer-1, #fff);
|
|
296
|
+
border-radius: 50%;
|
|
297
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
298
|
+
transition: transform 0.16s;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.dsh-pfc-knob--on {
|
|
302
|
+
transform: translateX(18px);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.dsh-pfc-toggle:disabled {
|
|
306
|
+
cursor: not-allowed;
|
|
307
|
+
opacity: 0.5;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.dsh-pfc-hint {
|
|
311
|
+
margin: 0;
|
|
312
|
+
font-size: 12px;
|
|
313
|
+
line-height: 1.5;
|
|
314
|
+
color: var(--dsw-alias-label-tertiary, rgba(128, 128, 128, 0.6));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.dsh-pfc-footer {
|
|
318
|
+
display: flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
justify-content: flex-end;
|
|
321
|
+
gap: 8px;
|
|
322
|
+
padding: 12px 0 4px;
|
|
323
|
+
border-top: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.dsh-pfc-failed {
|
|
327
|
+
flex: 1 1 auto;
|
|
328
|
+
min-width: 0;
|
|
329
|
+
margin: 0;
|
|
330
|
+
font-size: 12px;
|
|
331
|
+
line-height: 1.5;
|
|
332
|
+
color: var(--dsw-alias-label-error, #ff453a);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.dsh-pfc-discard,
|
|
336
|
+
.dsh-pfc-save {
|
|
337
|
+
appearance: none;
|
|
338
|
+
font: inherit;
|
|
339
|
+
font-size: 13px;
|
|
340
|
+
font-weight: 500;
|
|
341
|
+
line-height: 20px;
|
|
342
|
+
padding: 5px 14px;
|
|
343
|
+
border: 1px solid transparent;
|
|
344
|
+
border-radius: 8px;
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
347
|
+
background: var(--dsw-alias-bg-module-platform, rgba(128, 128, 128, 0.12));
|
|
348
|
+
transition: background 0.16s, opacity 0.16s;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.dsh-pfc-save {
|
|
352
|
+
background: var(--dsw-alias-brand-primary, #0a84ff);
|
|
353
|
+
color: var(--dsw-alias-bg-layer-1, #fff);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.dsh-pfc-discard:disabled,
|
|
357
|
+
.dsh-pfc-save:disabled {
|
|
358
|
+
cursor: not-allowed;
|
|
359
|
+
opacity: 0.5;
|
|
360
|
+
}
|
|
361
|
+
`;
|
|
362
|
+
/**
|
|
363
|
+
* Install the card stylesheet as one tagged `<style>` element.
|
|
364
|
+
* @returns the disposer removing the tag (idempotent outside a document).
|
|
365
|
+
*/
|
|
366
|
+
function installPrefaceCardStyles() {
|
|
367
|
+
if (typeof document === "undefined") return () => {};
|
|
368
|
+
if (document.querySelector(`style[data-plugin-css='${STYLE_TAG_ID}']`) !== null) return () => {};
|
|
369
|
+
const style = document.createElement("style");
|
|
370
|
+
style.dataset.plugin = "@huanlin/dsh-plugin-preface-context";
|
|
371
|
+
style.dataset.pluginCss = STYLE_TAG_ID;
|
|
372
|
+
style.textContent = CSS;
|
|
373
|
+
document.head.appendChild(style);
|
|
374
|
+
return () => {
|
|
375
|
+
style.remove();
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region src/client/preface-card.tsx
|
|
381
|
+
/**
|
|
382
|
+
* Render the preface-context card.
|
|
383
|
+
* @param props - locale copy, the card snapshot, and its form actions.
|
|
384
|
+
* @returns the card, or nothing when the namespace is unavailable.
|
|
385
|
+
*/
|
|
386
|
+
function PrefaceCard(props) {
|
|
387
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
388
|
+
const { t } = props;
|
|
389
|
+
const state = props.usePrefaceCard((snapshot) => snapshot);
|
|
390
|
+
if (!state.available) return null;
|
|
391
|
+
const title = t("title");
|
|
392
|
+
const blocked = !state.dirty || state.saving;
|
|
393
|
+
const enabledOn = state.enabled.text === "true";
|
|
394
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
395
|
+
className: clsx_default(css.card, open && css.cardOpen),
|
|
396
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
397
|
+
type: "button",
|
|
398
|
+
className: css.header,
|
|
399
|
+
"aria-expanded": open,
|
|
400
|
+
"aria-label": `${t(open ? "collapse" : "expand")}: ${title}`,
|
|
401
|
+
onClick: () => {
|
|
402
|
+
setOpen(!open);
|
|
403
|
+
},
|
|
404
|
+
children: [
|
|
405
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
406
|
+
className: css.headText,
|
|
407
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
408
|
+
className: css.name,
|
|
409
|
+
children: title
|
|
410
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
411
|
+
className: css.description,
|
|
412
|
+
children: t("description")
|
|
413
|
+
})]
|
|
414
|
+
}),
|
|
415
|
+
state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
416
|
+
className: css.pending,
|
|
417
|
+
children: t("unsaved")
|
|
418
|
+
}) : null,
|
|
419
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: clsx_default(css.chevron, open && css.chevronOpen) })
|
|
420
|
+
]
|
|
421
|
+
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
422
|
+
className: css.body,
|
|
423
|
+
children: [
|
|
424
|
+
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
425
|
+
className: css.readOnly,
|
|
426
|
+
role: "status",
|
|
427
|
+
children: t("readOnly")
|
|
428
|
+
}) : null,
|
|
429
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
430
|
+
className: css.field,
|
|
431
|
+
children: [
|
|
432
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
433
|
+
className: css.head,
|
|
434
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
435
|
+
className: css.label,
|
|
436
|
+
children: t("enabled")
|
|
437
|
+
}), state.enabled.overridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
438
|
+
className: css.badges,
|
|
439
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
440
|
+
className: css.badge,
|
|
441
|
+
children: t("overridden")
|
|
442
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
443
|
+
type: "button",
|
|
444
|
+
className: css.reset,
|
|
445
|
+
disabled: !state.writable,
|
|
446
|
+
onClick: () => {
|
|
447
|
+
props.resetField("enabled");
|
|
448
|
+
},
|
|
449
|
+
children: t("reset")
|
|
450
|
+
})]
|
|
451
|
+
}) : null]
|
|
452
|
+
}),
|
|
453
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
454
|
+
className: css.toggleRow,
|
|
455
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
456
|
+
type: "button",
|
|
457
|
+
role: "switch",
|
|
458
|
+
"aria-checked": enabledOn,
|
|
459
|
+
className: clsx_default(css.toggle, enabledOn && css.toggleOn),
|
|
460
|
+
disabled: !state.writable,
|
|
461
|
+
onClick: () => {
|
|
462
|
+
props.edit("enabled", enabledOn ? "false" : "true");
|
|
463
|
+
},
|
|
464
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: clsx_default(css.knob, enabledOn && css.knobOn) })
|
|
465
|
+
})
|
|
466
|
+
}),
|
|
467
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
468
|
+
className: css.hint,
|
|
469
|
+
children: t("enabledHint")
|
|
470
|
+
})
|
|
471
|
+
]
|
|
472
|
+
}),
|
|
473
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
474
|
+
className: css.field,
|
|
475
|
+
children: [
|
|
476
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
477
|
+
className: css.head,
|
|
478
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
479
|
+
className: css.label,
|
|
480
|
+
children: t("contextText")
|
|
481
|
+
}), state.contextText.overridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
482
|
+
className: css.badges,
|
|
483
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
484
|
+
className: css.badge,
|
|
485
|
+
children: t("overridden")
|
|
486
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
487
|
+
type: "button",
|
|
488
|
+
className: css.reset,
|
|
489
|
+
disabled: !state.writable,
|
|
490
|
+
onClick: () => {
|
|
491
|
+
props.resetField("contextText");
|
|
492
|
+
},
|
|
493
|
+
children: t("reset")
|
|
494
|
+
})]
|
|
495
|
+
}) : null]
|
|
496
|
+
}),
|
|
497
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
498
|
+
id: "plugin-config-preface-context-text",
|
|
499
|
+
className: css.textarea,
|
|
500
|
+
value: state.contextText.text,
|
|
501
|
+
placeholder: t("contextTextPlaceholder"),
|
|
502
|
+
disabled: !state.writable,
|
|
503
|
+
onChange: (event) => {
|
|
504
|
+
props.edit("contextText", event.target.value);
|
|
505
|
+
}
|
|
506
|
+
}),
|
|
507
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
508
|
+
className: css.hint,
|
|
509
|
+
children: t("contextTextHint")
|
|
510
|
+
})
|
|
511
|
+
]
|
|
512
|
+
}),
|
|
513
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
514
|
+
className: css.footer,
|
|
515
|
+
children: [
|
|
516
|
+
state.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
517
|
+
className: css.failed,
|
|
518
|
+
role: "status",
|
|
519
|
+
children: t("saveFailed")
|
|
520
|
+
}) : null,
|
|
521
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
522
|
+
type: "button",
|
|
523
|
+
className: css.discard,
|
|
524
|
+
disabled: !state.dirty || state.saving,
|
|
525
|
+
onClick: props.discard,
|
|
526
|
+
children: t("discard")
|
|
527
|
+
}),
|
|
528
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
529
|
+
type: "button",
|
|
530
|
+
className: css.save,
|
|
531
|
+
disabled: blocked,
|
|
532
|
+
onClick: props.save,
|
|
533
|
+
children: t(state.saving ? "saving" : "save")
|
|
534
|
+
})
|
|
535
|
+
]
|
|
536
|
+
})
|
|
537
|
+
]
|
|
538
|
+
}) : null]
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
//#endregion
|
|
543
|
+
//#region src/client/preface-card-controller.ts
|
|
544
|
+
/** A minimal snapshot store: a value + a listener set. Self-contained so the
|
|
545
|
+
* controller does not pull `createSnapshotStore` (a browser-bundle symbol)
|
|
546
|
+
* into its unit-test graph. */
|
|
547
|
+
var MiniSnapshotStore = class {
|
|
548
|
+
snapshot;
|
|
549
|
+
listeners = /* @__PURE__ */ new Set();
|
|
550
|
+
constructor(initial) {
|
|
551
|
+
this.snapshot = initial;
|
|
552
|
+
}
|
|
553
|
+
getSnapshot() {
|
|
554
|
+
return this.snapshot;
|
|
555
|
+
}
|
|
556
|
+
set(value) {
|
|
557
|
+
this.snapshot = value;
|
|
558
|
+
for (const listener of [...this.listeners]) listener();
|
|
559
|
+
}
|
|
560
|
+
update(mutator) {
|
|
561
|
+
const draft = Array.isArray(this.snapshot) ? [...this.snapshot] : { ...this.snapshot };
|
|
562
|
+
mutator(draft);
|
|
563
|
+
this.set(draft);
|
|
564
|
+
}
|
|
565
|
+
subscribe(listener) {
|
|
566
|
+
this.listeners.add(listener);
|
|
567
|
+
return () => {
|
|
568
|
+
this.listeners.delete(listener);
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
/** The default value for a field when the user-layer carries none. */
|
|
573
|
+
function baseValue(snapshot, field) {
|
|
574
|
+
return snapshot.base?.[field];
|
|
575
|
+
}
|
|
576
|
+
/** The current resolved value of a field. */
|
|
577
|
+
function sectionValue(snapshot, field) {
|
|
578
|
+
return snapshot.value?.[field];
|
|
579
|
+
}
|
|
580
|
+
/** Whether the user layer carries an entry for a field. */
|
|
581
|
+
function stored(snapshot, field) {
|
|
582
|
+
const user = snapshot.user;
|
|
583
|
+
return user !== void 0 && Object.hasOwn(user, field);
|
|
584
|
+
}
|
|
585
|
+
/** Format a stored value as draft text for a field. */
|
|
586
|
+
function format(field, value) {
|
|
587
|
+
if (field === "enabled") return value === true ? "true" : "false";
|
|
588
|
+
if (field === "contextText") return typeof value === "string" ? value : "";
|
|
589
|
+
return "";
|
|
590
|
+
}
|
|
591
|
+
/** Parse draft text into a write value, or undefined when invalid. */
|
|
592
|
+
function parse(field, text) {
|
|
593
|
+
if (field === "enabled") return { value: text === "true" };
|
|
594
|
+
return text.trim() === "" ? { clear: true } : { value: text };
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Bridges the `preface-context` scope onto the card's staged form.
|
|
598
|
+
*
|
|
599
|
+
* Publishes through a snapshot store because slot components read through a
|
|
600
|
+
* snapshot selector, while both the scope and the local drafts change
|
|
601
|
+
* underneath; every projection is rebuilt from the two together.
|
|
602
|
+
*/
|
|
603
|
+
var PrefaceCardController = class {
|
|
604
|
+
scope;
|
|
605
|
+
store;
|
|
606
|
+
staged = /* @__PURE__ */ new Map();
|
|
607
|
+
saving = false;
|
|
608
|
+
failed = false;
|
|
609
|
+
/** @param scope - the bound settings scope for the `preface-context` namespace. */
|
|
610
|
+
constructor(scope) {
|
|
611
|
+
this.scope = scope;
|
|
612
|
+
this.store = new MiniSnapshotStore(this.project());
|
|
613
|
+
scope.subscribe(() => {
|
|
614
|
+
this.publish();
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
/** @returns the store the card's component reads through its bound selector. */
|
|
618
|
+
get snapshot() {
|
|
619
|
+
return this.store;
|
|
620
|
+
}
|
|
621
|
+
project() {
|
|
622
|
+
const snapshot = this.scope.getSnapshot();
|
|
623
|
+
const dirty = this.staged.size > 0;
|
|
624
|
+
return {
|
|
625
|
+
available: snapshot.status === "ready",
|
|
626
|
+
writable: snapshot.writable,
|
|
627
|
+
dirty,
|
|
628
|
+
saving: this.saving,
|
|
629
|
+
failed: this.failed,
|
|
630
|
+
enabled: this.fieldState(snapshot, "enabled"),
|
|
631
|
+
contextText: this.fieldState(snapshot, "contextText")
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
fieldState(snapshot, field) {
|
|
635
|
+
const staged = this.staged.get(field);
|
|
636
|
+
if (staged === void 0) return {
|
|
637
|
+
text: format(field, sectionValue(snapshot, field)),
|
|
638
|
+
overridden: stored(snapshot, field)
|
|
639
|
+
};
|
|
640
|
+
const write = staged.clear ? { clear: true } : parse(field, staged.text);
|
|
641
|
+
return {
|
|
642
|
+
text: staged.text,
|
|
643
|
+
overridden: write !== void 0 && "value" in write
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
/** Build the face the card's slot registration injects. */
|
|
647
|
+
inject() {
|
|
648
|
+
return {
|
|
649
|
+
hooks: { prefaceCard: this.store },
|
|
650
|
+
edit: (field, text) => {
|
|
651
|
+
this.stage(field, {
|
|
652
|
+
text,
|
|
653
|
+
clear: false
|
|
654
|
+
});
|
|
655
|
+
},
|
|
656
|
+
resetField: (field) => {
|
|
657
|
+
this.stage(field, {
|
|
658
|
+
text: format(field, baseValue(this.scope.getSnapshot(), field)),
|
|
659
|
+
clear: true
|
|
660
|
+
});
|
|
661
|
+
},
|
|
662
|
+
save: () => {
|
|
663
|
+
this.save();
|
|
664
|
+
},
|
|
665
|
+
discard: () => {
|
|
666
|
+
if (this.staged.size === 0 && !this.failed) return;
|
|
667
|
+
this.staged.clear();
|
|
668
|
+
this.failed = false;
|
|
669
|
+
this.publish();
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
stage(field, edit) {
|
|
674
|
+
this.staged.set(field, edit);
|
|
675
|
+
this.failed = false;
|
|
676
|
+
this.publish();
|
|
677
|
+
}
|
|
678
|
+
publish() {
|
|
679
|
+
this.store.set(this.project());
|
|
680
|
+
}
|
|
681
|
+
/** Write every staged edit, then re-seed from what the Host accepted. */
|
|
682
|
+
async save() {
|
|
683
|
+
if (this.staged.size === 0 || this.saving) return;
|
|
684
|
+
this.saving = true;
|
|
685
|
+
this.failed = false;
|
|
686
|
+
this.publish();
|
|
687
|
+
let landed = true;
|
|
688
|
+
for (const [field, staged] of this.staged) {
|
|
689
|
+
const write = staged.clear ? { clear: true } : parse(field, staged.text);
|
|
690
|
+
if (write === void 0) continue;
|
|
691
|
+
try {
|
|
692
|
+
if ("clear" in write) await this.scope.unset(field);
|
|
693
|
+
else await this.scope.set(field, write.value);
|
|
694
|
+
} catch {
|
|
695
|
+
landed = false;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (landed) this.staged.clear();
|
|
699
|
+
this.saving = false;
|
|
700
|
+
this.failed = !landed;
|
|
701
|
+
this.publish();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
//#endregion
|
|
706
|
+
//#region src/client/locales.ts
|
|
707
|
+
/** English copy. */
|
|
708
|
+
const en = {
|
|
709
|
+
title: "Preface context",
|
|
710
|
+
description: "Inject a text block as model-visible instructions at the start of every session.",
|
|
711
|
+
enabled: "Enabled",
|
|
712
|
+
enabledHint: "When off, no context is injected at session start.",
|
|
713
|
+
contextText: "Context text",
|
|
714
|
+
contextTextHint: "Injected once per session as instructions context, closest to the model’s first answer. Empty text injects nothing.",
|
|
715
|
+
contextTextPlaceholder: "Enter the text to inject at the start of every session…",
|
|
716
|
+
overridden: "Overridden",
|
|
717
|
+
reset: "Reset to default",
|
|
718
|
+
save: "Save",
|
|
719
|
+
saving: "Saving…",
|
|
720
|
+
discard: "Discard",
|
|
721
|
+
unsaved: "Unsaved",
|
|
722
|
+
saveFailed: "The deployment did not accept these values; they were left for you to correct.",
|
|
723
|
+
readOnly: "This deployment stores settings read-only.",
|
|
724
|
+
expand: "Show settings",
|
|
725
|
+
collapse: "Hide settings"
|
|
726
|
+
};
|
|
727
|
+
/** Simplified Chinese copy. */
|
|
728
|
+
const zh = {
|
|
729
|
+
title: "前言上下文",
|
|
730
|
+
description: "在每次会话开头注入一段文本作为模型可见的指令上下文。",
|
|
731
|
+
enabled: "启用",
|
|
732
|
+
enabledHint: "关闭后,会话开始时不注入任何上下文。",
|
|
733
|
+
contextText: "上下文文本",
|
|
734
|
+
contextTextHint: "每次会话注入一次,作为指令上下文最贴近模型的首个回答。文本为空则不注入。",
|
|
735
|
+
contextTextPlaceholder: "输入要在每次会话开头注入的文本…",
|
|
736
|
+
overridden: "已覆盖",
|
|
737
|
+
reset: "恢复默认",
|
|
738
|
+
save: "保存",
|
|
739
|
+
saving: "保存中…",
|
|
740
|
+
discard: "放弃修改",
|
|
741
|
+
unsaved: "未保存",
|
|
742
|
+
saveFailed: "本部署没有接受这些值,已保留供你修改。",
|
|
743
|
+
readOnly: "本部署的设置为只读。",
|
|
744
|
+
expand: "展开设置",
|
|
745
|
+
collapse: "收起设置"
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
//#endregion
|
|
749
|
+
//#region src/client/index.ts
|
|
750
|
+
/** Dictionary namespace owned by this plugin. */
|
|
751
|
+
const NS = "settings.preface-context";
|
|
752
|
+
/** Settings namespace the host half registers (must match the host constant). */
|
|
753
|
+
const SETTINGS_NAMESPACE = "preface-context";
|
|
754
|
+
/**
|
|
755
|
+
* Required services (cordis fiber inject). `settingsScope` is provided by the
|
|
756
|
+
* ui-settings base plugin; `locale` by the locale plugin; `slots` is the
|
|
757
|
+
* composition root. The target slot is declared by ui-settings-plugins'
|
|
758
|
+
* `configurable` tab, whose activation order relative to this one is
|
|
759
|
+
* unconstrained; registration depends on the slot through `slots.inject()`.
|
|
760
|
+
*/
|
|
761
|
+
const inject = [
|
|
762
|
+
"slots",
|
|
763
|
+
"locale",
|
|
764
|
+
"settingsScope"
|
|
765
|
+
];
|
|
766
|
+
/**
|
|
767
|
+
* Register the preface-context card once the `settings.plugin.item`
|
|
768
|
+
* declaration is on the ledger, wire its controller to the settings scope,
|
|
769
|
+
* and keep it fresh on every pushed invalidation.
|
|
770
|
+
* @param ctx - client root context.
|
|
771
|
+
*/
|
|
772
|
+
function apply(ctx) {
|
|
773
|
+
ctx.effect(installPrefaceCardStyles, "preface-context: card styles");
|
|
774
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
775
|
+
zh,
|
|
776
|
+
en
|
|
777
|
+
}), "preface-context: copy dictionaries");
|
|
778
|
+
const settingsScope = ctx.settingsScope;
|
|
779
|
+
const controller = new PrefaceCardController(settingsScope.bind({ namespace: SETTINGS_NAMESPACE }));
|
|
780
|
+
ctx.slots.inject("settings.plugin.item", function* () {
|
|
781
|
+
yield ctx.slots.register({
|
|
782
|
+
name: "settings.plugin.item",
|
|
783
|
+
key: SETTINGS_NAMESPACE,
|
|
784
|
+
locale: NS,
|
|
785
|
+
inject: () => controller.inject()
|
|
786
|
+
}, PrefaceCard);
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
//#endregion
|
|
791
|
+
exports.apply = apply;
|
|
792
|
+
exports.inject = inject;
|
|
793
|
+
return module.exports; } });
|
|
794
|
+
//# sourceMappingURL=client.js.map
|