dsh-prompt-customizer 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 +107 -0
- package/README.zh-CN.md +107 -0
- package/client/client.js +896 -0
- package/client/client.js.map +1 -0
- package/cordis.patch.yml +9 -0
- package/lib/client.js +344 -0
- package/lib/index.js +140 -0
- package/lib/schema.js +27 -0
- package/package.json +61 -0
- package/src/client/PresetsTab.tsx +184 -0
- package/src/client/SectionsTab.tsx +207 -0
- package/src/client/ToolsTab.tsx +62 -0
- package/src/client/index.ts +117 -0
- package/src/client/locales.ts +81 -0
- package/src/client/styles.ts +36 -0
- package/src/client/types.ts +41 -0
package/client/client.js
ADDED
|
@@ -0,0 +1,896 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-prompt-customizer",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
//#region src/client/locales.ts
|
|
9
|
+
/** Locale dictionaries for the prompt-customizer panel. */
|
|
10
|
+
const DICT = {
|
|
11
|
+
zh: {
|
|
12
|
+
nav: "提示词定制",
|
|
13
|
+
loading: "加载中…",
|
|
14
|
+
unavailable: "当前环境未启用本命名空间。",
|
|
15
|
+
tabsSections: "提示词",
|
|
16
|
+
tabsTools: "工具",
|
|
17
|
+
tabsPresets: "预设",
|
|
18
|
+
refresh: "刷新",
|
|
19
|
+
blockedOff: "未屏蔽",
|
|
20
|
+
blockedOn: "已屏蔽",
|
|
21
|
+
replaced: "已替换",
|
|
22
|
+
replace: "替换",
|
|
23
|
+
clearReplace: "清除替换",
|
|
24
|
+
injectNew: "注入新段",
|
|
25
|
+
name: "名称",
|
|
26
|
+
order: "顺序",
|
|
27
|
+
text: "文本",
|
|
28
|
+
add: "添加",
|
|
29
|
+
hiddenOff: "可见",
|
|
30
|
+
hiddenOn: "已隐藏",
|
|
31
|
+
includeMode: "白名单模式:仅保留勾选项",
|
|
32
|
+
excludeMode: "黑名单模式:勾选 = 隐藏",
|
|
33
|
+
empty: "(空)",
|
|
34
|
+
dynamic: "<动态生成>",
|
|
35
|
+
drag: "拖动排序",
|
|
36
|
+
moveUp: "上移",
|
|
37
|
+
moveDown: "下移",
|
|
38
|
+
savePreset: "保存当前为预设",
|
|
39
|
+
presetName: "预设名称",
|
|
40
|
+
save: "保存",
|
|
41
|
+
importPreset: "导入预设",
|
|
42
|
+
import: "导入",
|
|
43
|
+
apply: "应用",
|
|
44
|
+
export: "导出",
|
|
45
|
+
delete: "删除",
|
|
46
|
+
active: "使用中",
|
|
47
|
+
preset: "预设"
|
|
48
|
+
},
|
|
49
|
+
en: {
|
|
50
|
+
nav: "Prompt Customizer",
|
|
51
|
+
loading: "Loading…",
|
|
52
|
+
unavailable: "Namespace unavailable in this environment.",
|
|
53
|
+
tabsSections: "Sections",
|
|
54
|
+
tabsTools: "Tools",
|
|
55
|
+
tabsPresets: "Presets",
|
|
56
|
+
refresh: "Refresh",
|
|
57
|
+
blockedOff: "Active",
|
|
58
|
+
blockedOn: "Blocked",
|
|
59
|
+
replaced: "Replaced",
|
|
60
|
+
replace: "Replace",
|
|
61
|
+
clearReplace: "Clear",
|
|
62
|
+
injectNew: "Inject section",
|
|
63
|
+
name: "Name",
|
|
64
|
+
order: "Order",
|
|
65
|
+
text: "Text",
|
|
66
|
+
add: "Add",
|
|
67
|
+
hiddenOff: "Visible",
|
|
68
|
+
hiddenOn: "Hidden",
|
|
69
|
+
includeMode: "Whitelist: keep only checked",
|
|
70
|
+
excludeMode: "Blacklist: check to hide",
|
|
71
|
+
empty: "(empty)",
|
|
72
|
+
dynamic: "<dynamic>",
|
|
73
|
+
drag: "Drag to reorder",
|
|
74
|
+
moveUp: "Move up",
|
|
75
|
+
moveDown: "Move down",
|
|
76
|
+
savePreset: "Save current as preset",
|
|
77
|
+
presetName: "Preset name",
|
|
78
|
+
save: "Save",
|
|
79
|
+
importPreset: "Import preset",
|
|
80
|
+
import: "Import",
|
|
81
|
+
apply: "Apply",
|
|
82
|
+
export: "Export",
|
|
83
|
+
delete: "Delete",
|
|
84
|
+
active: "Active",
|
|
85
|
+
preset: "Preset"
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/client/styles.ts
|
|
90
|
+
/** Inline styles shared by the prompt-customizer panel components. */
|
|
91
|
+
const s = (() => {
|
|
92
|
+
const flex = {
|
|
93
|
+
display: "flex",
|
|
94
|
+
alignItems: "center"
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
root: {
|
|
98
|
+
fontFamily: "inherit",
|
|
99
|
+
fontSize: 13,
|
|
100
|
+
lineHeight: 1.5
|
|
101
|
+
},
|
|
102
|
+
bar: {
|
|
103
|
+
...flex,
|
|
104
|
+
gap: 6,
|
|
105
|
+
marginBottom: 8,
|
|
106
|
+
flexWrap: "wrap"
|
|
107
|
+
},
|
|
108
|
+
tab: {
|
|
109
|
+
padding: "4px 10px",
|
|
110
|
+
border: "1px solid rgba(128,128,128,.35)",
|
|
111
|
+
borderRadius: 6,
|
|
112
|
+
background: "transparent",
|
|
113
|
+
cursor: "pointer",
|
|
114
|
+
color: "inherit",
|
|
115
|
+
opacity: .75
|
|
116
|
+
},
|
|
117
|
+
tabActive: {
|
|
118
|
+
padding: "4px 10px",
|
|
119
|
+
border: "1px solid rgba(128,128,128,.7)",
|
|
120
|
+
borderRadius: 6,
|
|
121
|
+
background: "rgba(128,128,128,.18)",
|
|
122
|
+
cursor: "pointer",
|
|
123
|
+
color: "inherit"
|
|
124
|
+
},
|
|
125
|
+
refresh: {
|
|
126
|
+
marginLeft: "auto",
|
|
127
|
+
padding: "4px 10px",
|
|
128
|
+
border: "1px solid rgba(128,128,128,.35)",
|
|
129
|
+
borderRadius: 6,
|
|
130
|
+
background: "transparent",
|
|
131
|
+
cursor: "pointer",
|
|
132
|
+
color: "inherit"
|
|
133
|
+
},
|
|
134
|
+
list: {
|
|
135
|
+
display: "flex",
|
|
136
|
+
flexDirection: "column",
|
|
137
|
+
gap: 6
|
|
138
|
+
},
|
|
139
|
+
row: {
|
|
140
|
+
...flex,
|
|
141
|
+
gap: 8,
|
|
142
|
+
padding: "6px 8px",
|
|
143
|
+
border: "1px solid rgba(128,128,128,.2)",
|
|
144
|
+
borderRadius: 8,
|
|
145
|
+
background: "rgba(128,128,128,.06)"
|
|
146
|
+
},
|
|
147
|
+
switchWrap: {
|
|
148
|
+
...flex,
|
|
149
|
+
gap: 6,
|
|
150
|
+
minWidth: 90
|
|
151
|
+
},
|
|
152
|
+
rowBody: {
|
|
153
|
+
flex: 1,
|
|
154
|
+
minWidth: 0
|
|
155
|
+
},
|
|
156
|
+
rowTitle: {
|
|
157
|
+
...flex,
|
|
158
|
+
gap: 6,
|
|
159
|
+
alignItems: "baseline",
|
|
160
|
+
flexWrap: "wrap"
|
|
161
|
+
},
|
|
162
|
+
code: {
|
|
163
|
+
fontFamily: "monospace",
|
|
164
|
+
fontSize: 12,
|
|
165
|
+
wordBreak: "break-all"
|
|
166
|
+
},
|
|
167
|
+
orderTag: {
|
|
168
|
+
color: "rgba(128,128,128,.8)",
|
|
169
|
+
fontSize: 11
|
|
170
|
+
},
|
|
171
|
+
preview: {
|
|
172
|
+
color: "rgba(128,128,128,.85)",
|
|
173
|
+
fontSize: 12,
|
|
174
|
+
overflow: "hidden",
|
|
175
|
+
textOverflow: "ellipsis",
|
|
176
|
+
whiteSpace: "nowrap"
|
|
177
|
+
},
|
|
178
|
+
badgeOk: {
|
|
179
|
+
color: "#3fb950",
|
|
180
|
+
fontSize: 11,
|
|
181
|
+
border: "1px solid rgba(63,185,80,.5)",
|
|
182
|
+
borderRadius: 999,
|
|
183
|
+
padding: "0 6px"
|
|
184
|
+
},
|
|
185
|
+
badgeBlocked: {
|
|
186
|
+
color: "#f85149",
|
|
187
|
+
fontSize: 11,
|
|
188
|
+
border: "1px solid rgba(248,81,73,.5)",
|
|
189
|
+
borderRadius: 999,
|
|
190
|
+
padding: "0 6px"
|
|
191
|
+
},
|
|
192
|
+
badgeReplaced: {
|
|
193
|
+
color: "#d29922",
|
|
194
|
+
fontSize: 11,
|
|
195
|
+
border: "1px solid rgba(210,153,34,.5)",
|
|
196
|
+
borderRadius: 999,
|
|
197
|
+
padding: "0 6px"
|
|
198
|
+
},
|
|
199
|
+
mini: {
|
|
200
|
+
padding: "3px 8px",
|
|
201
|
+
border: "1px solid rgba(128,128,128,.35)",
|
|
202
|
+
borderRadius: 6,
|
|
203
|
+
background: "transparent",
|
|
204
|
+
cursor: "pointer",
|
|
205
|
+
color: "inherit",
|
|
206
|
+
whiteSpace: "nowrap"
|
|
207
|
+
},
|
|
208
|
+
arrowCol: {
|
|
209
|
+
display: "flex",
|
|
210
|
+
flexDirection: "column",
|
|
211
|
+
gap: 2
|
|
212
|
+
},
|
|
213
|
+
arrow: {
|
|
214
|
+
padding: "0 6px",
|
|
215
|
+
border: "1px solid rgba(128,128,128,.3)",
|
|
216
|
+
borderRadius: 4,
|
|
217
|
+
background: "transparent",
|
|
218
|
+
cursor: "pointer",
|
|
219
|
+
color: "inherit",
|
|
220
|
+
fontSize: 11,
|
|
221
|
+
lineHeight: 1.4,
|
|
222
|
+
opacity: .8
|
|
223
|
+
},
|
|
224
|
+
rowDragging: { opacity: .4 },
|
|
225
|
+
rowDropAbove: { boxShadow: "0 -2px 0 0 #58a6ff" },
|
|
226
|
+
rowDropBelow: { boxShadow: "0 2px 0 0 #58a6ff" },
|
|
227
|
+
dragHandle: {
|
|
228
|
+
cursor: "grab",
|
|
229
|
+
color: "rgba(128,128,128,.7)",
|
|
230
|
+
fontSize: 13,
|
|
231
|
+
padding: "0 2px",
|
|
232
|
+
userSelect: "none"
|
|
233
|
+
},
|
|
234
|
+
injectBox: {
|
|
235
|
+
marginTop: 10,
|
|
236
|
+
padding: "8px",
|
|
237
|
+
border: "1px dashed rgba(128,128,128,.4)",
|
|
238
|
+
borderRadius: 8,
|
|
239
|
+
display: "flex",
|
|
240
|
+
flexDirection: "column",
|
|
241
|
+
gap: 6
|
|
242
|
+
},
|
|
243
|
+
injectRow: {
|
|
244
|
+
...flex,
|
|
245
|
+
gap: 6
|
|
246
|
+
},
|
|
247
|
+
editBox: {
|
|
248
|
+
display: "flex",
|
|
249
|
+
flexDirection: "column",
|
|
250
|
+
gap: 6,
|
|
251
|
+
marginTop: 4
|
|
252
|
+
},
|
|
253
|
+
editInput: {
|
|
254
|
+
padding: "6px",
|
|
255
|
+
border: "1px solid rgba(128,128,128,.35)",
|
|
256
|
+
borderRadius: 6,
|
|
257
|
+
background: "transparent",
|
|
258
|
+
color: "inherit",
|
|
259
|
+
fontFamily: "inherit",
|
|
260
|
+
fontSize: 12,
|
|
261
|
+
resize: "vertical",
|
|
262
|
+
width: "100%",
|
|
263
|
+
boxSizing: "border-box"
|
|
264
|
+
},
|
|
265
|
+
input: {
|
|
266
|
+
padding: "4px 6px",
|
|
267
|
+
border: "1px solid rgba(128,128,128,.35)",
|
|
268
|
+
borderRadius: 6,
|
|
269
|
+
background: "transparent",
|
|
270
|
+
color: "inherit"
|
|
271
|
+
},
|
|
272
|
+
muted: {
|
|
273
|
+
color: "rgba(128,128,128,.75)",
|
|
274
|
+
fontSize: 12
|
|
275
|
+
},
|
|
276
|
+
error: {
|
|
277
|
+
color: "#f85149",
|
|
278
|
+
fontSize: 12,
|
|
279
|
+
marginBottom: 6
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
})();
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/client/SectionsTab.tsx
|
|
285
|
+
/** Prompt-sections tab: block / replace / inject / reorder prompt sections. */
|
|
286
|
+
function SectionsTab({ cfg, inv, scope, t }) {
|
|
287
|
+
const replace = cfg.replace ?? {};
|
|
288
|
+
const blockedNames = new Set(cfg.sections ?? []);
|
|
289
|
+
const [editing, setEditing] = (0, react.useState)(null);
|
|
290
|
+
const [draft, setDraft] = (0, react.useState)("");
|
|
291
|
+
const [dragName, setDragName] = (0, react.useState)(null);
|
|
292
|
+
const [dropTarget, setDropTarget] = (0, react.useState)(null);
|
|
293
|
+
const merged = (() => {
|
|
294
|
+
const map = /* @__PURE__ */ new Map();
|
|
295
|
+
for (const sec of inv?.sections ?? []) map.set(sec.name, sec);
|
|
296
|
+
for (const item of cfg.inject ?? []) {
|
|
297
|
+
const existing = map.get(item.name);
|
|
298
|
+
if (existing) map.set(item.name, {
|
|
299
|
+
...existing,
|
|
300
|
+
order: item.order
|
|
301
|
+
});
|
|
302
|
+
else map.set(item.name, {
|
|
303
|
+
name: item.name,
|
|
304
|
+
order: item.order,
|
|
305
|
+
text: item.text || "<动态生成>",
|
|
306
|
+
active: !blockedNames.has(item.name),
|
|
307
|
+
replaced: false
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
return [...map.values()].sort((a, b) => a.order - b.order);
|
|
311
|
+
})();
|
|
312
|
+
const toggleBlock = (name, currentlyBlocked) => {
|
|
313
|
+
const list = (cfg.sections ?? []).slice();
|
|
314
|
+
if (currentlyBlocked) {
|
|
315
|
+
const i = list.indexOf(name);
|
|
316
|
+
if (i >= 0) list.splice(i, 1);
|
|
317
|
+
} else list.push(name);
|
|
318
|
+
scope.set("sections", list);
|
|
319
|
+
};
|
|
320
|
+
const startReplace = (name, original) => {
|
|
321
|
+
setEditing(name);
|
|
322
|
+
setDraft(replace[name] ?? original);
|
|
323
|
+
};
|
|
324
|
+
const commitReplace = (name) => {
|
|
325
|
+
const next = { ...replace };
|
|
326
|
+
if (draft.trim() === "") delete next[name];
|
|
327
|
+
else next[name] = draft;
|
|
328
|
+
scope.set("replace", next);
|
|
329
|
+
setEditing(null);
|
|
330
|
+
};
|
|
331
|
+
const clearReplace = (name) => {
|
|
332
|
+
const next = { ...replace };
|
|
333
|
+
delete next[name];
|
|
334
|
+
scope.set("replace", next);
|
|
335
|
+
};
|
|
336
|
+
const persistOrder = (ordered) => {
|
|
337
|
+
const list = ordered.map((sec, i) => {
|
|
338
|
+
const existing = (cfg.inject ?? []).find((x) => x.name === sec.name);
|
|
339
|
+
return {
|
|
340
|
+
name: sec.name,
|
|
341
|
+
order: i,
|
|
342
|
+
text: existing ? existing.text : ""
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
scope.set("inject", list);
|
|
346
|
+
};
|
|
347
|
+
const moveOrder = (index, dir) => {
|
|
348
|
+
const target = index + dir;
|
|
349
|
+
if (target < 0 || target >= merged.length) return;
|
|
350
|
+
const next = merged.slice();
|
|
351
|
+
const [item] = next.splice(index, 1);
|
|
352
|
+
next.splice(target, 0, item);
|
|
353
|
+
persistOrder(next);
|
|
354
|
+
};
|
|
355
|
+
const onDragStart = (e, name) => {
|
|
356
|
+
setDragName(name);
|
|
357
|
+
e.dataTransfer.effectAllowed = "move";
|
|
358
|
+
try {
|
|
359
|
+
e.dataTransfer.setData("text/plain", name);
|
|
360
|
+
} catch {}
|
|
361
|
+
};
|
|
362
|
+
const onDragOver = (e, name) => {
|
|
363
|
+
if (!dragName || dragName === name) return;
|
|
364
|
+
e.preventDefault();
|
|
365
|
+
e.dataTransfer.dropEffect = "move";
|
|
366
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
367
|
+
const pos = e.clientY < rect.top + rect.height / 2 ? "above" : "below";
|
|
368
|
+
setDropTarget({
|
|
369
|
+
name,
|
|
370
|
+
pos
|
|
371
|
+
});
|
|
372
|
+
};
|
|
373
|
+
const onDrop = (e, target) => {
|
|
374
|
+
e.preventDefault();
|
|
375
|
+
if (!dragName || dragName === target.name) {
|
|
376
|
+
setDragName(null);
|
|
377
|
+
setDropTarget(null);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const dragged = merged.find((x) => x.name === dragName);
|
|
381
|
+
if (!dragged) {
|
|
382
|
+
setDragName(null);
|
|
383
|
+
setDropTarget(null);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const next = merged.filter((x) => x.name !== dragName);
|
|
387
|
+
const idx = next.findIndex((x) => x.name === target.name);
|
|
388
|
+
const pos = dropTarget?.name === target.name ? dropTarget.pos : "below";
|
|
389
|
+
next.splice(pos === "above" ? idx : idx + 1, 0, dragged);
|
|
390
|
+
persistOrder(next);
|
|
391
|
+
setDragName(null);
|
|
392
|
+
setDropTarget(null);
|
|
393
|
+
};
|
|
394
|
+
const onDragEnd = () => {
|
|
395
|
+
setDragName(null);
|
|
396
|
+
setDropTarget(null);
|
|
397
|
+
};
|
|
398
|
+
const addSection = (name, order, text) => {
|
|
399
|
+
const next = merged.slice();
|
|
400
|
+
const entry = {
|
|
401
|
+
name,
|
|
402
|
+
order,
|
|
403
|
+
text: text || "<动态生成>",
|
|
404
|
+
active: true,
|
|
405
|
+
replaced: false
|
|
406
|
+
};
|
|
407
|
+
const existing = next.findIndex((x) => x.name === name);
|
|
408
|
+
if (existing >= 0) next[existing] = entry;
|
|
409
|
+
else {
|
|
410
|
+
const idx = next.findIndex((x) => x.order > order);
|
|
411
|
+
if (idx < 0) next.push(entry);
|
|
412
|
+
else next.splice(idx, 0, entry);
|
|
413
|
+
}
|
|
414
|
+
persistOrder(next);
|
|
415
|
+
};
|
|
416
|
+
return (0, react.createElement)("div", { style: s.list }, [
|
|
417
|
+
merged.length === 0 ? (0, react.createElement)("div", { style: s.muted }, t("empty")) : null,
|
|
418
|
+
merged.map((sec, index) => {
|
|
419
|
+
const blocked = blockedNames.has(sec.name);
|
|
420
|
+
const isEditing = editing === sec.name;
|
|
421
|
+
const isDragging = dragName === sec.name;
|
|
422
|
+
const isDropTarget = dropTarget?.name === sec.name;
|
|
423
|
+
const rowStyle = {
|
|
424
|
+
...s.row,
|
|
425
|
+
...isDragging ? s.rowDragging : {},
|
|
426
|
+
...isDropTarget && dropTarget.pos === "above" ? s.rowDropAbove : {},
|
|
427
|
+
...isDropTarget && dropTarget.pos === "below" ? s.rowDropBelow : {}
|
|
428
|
+
};
|
|
429
|
+
return (0, react.createElement)("div", {
|
|
430
|
+
key: sec.name,
|
|
431
|
+
style: rowStyle,
|
|
432
|
+
draggable: true,
|
|
433
|
+
onDragStart: (e) => onDragStart(e, sec.name),
|
|
434
|
+
onDragOver: (e) => onDragOver(e, sec.name),
|
|
435
|
+
onDrop: (e) => onDrop(e, sec),
|
|
436
|
+
onDragEnd
|
|
437
|
+
}, [
|
|
438
|
+
(0, react.createElement)("span", {
|
|
439
|
+
style: s.dragHandle,
|
|
440
|
+
title: t("drag")
|
|
441
|
+
}, "⠿"),
|
|
442
|
+
(0, react.createElement)("label", { style: s.switchWrap }, [(0, react.createElement)("input", {
|
|
443
|
+
type: "checkbox",
|
|
444
|
+
checked: blocked,
|
|
445
|
+
onChange: () => toggleBlock(sec.name, blocked)
|
|
446
|
+
}), (0, react.createElement)("span", { style: blocked ? s.badgeBlocked : s.badgeOk }, blocked ? t("blockedOn") : t("blockedOff"))]),
|
|
447
|
+
(0, react.createElement)("div", { style: s.rowBody }, [(0, react.createElement)("div", { style: s.rowTitle }, [
|
|
448
|
+
(0, react.createElement)("span", { style: s.code }, sec.name),
|
|
449
|
+
(0, react.createElement)("span", { style: s.orderTag }, "#" + index),
|
|
450
|
+
sec.replaced ? (0, react.createElement)("span", { style: s.badgeReplaced }, t("replaced")) : null
|
|
451
|
+
]), isEditing ? (0, react.createElement)("div", { style: s.editBox }, [(0, react.createElement)("textarea", {
|
|
452
|
+
style: s.editInput,
|
|
453
|
+
value: draft,
|
|
454
|
+
onChange: (e) => setDraft(e.target.value),
|
|
455
|
+
rows: 3
|
|
456
|
+
}), (0, react.createElement)("div", { style: s.injectRow }, [(0, react.createElement)("button", {
|
|
457
|
+
style: s.mini,
|
|
458
|
+
onClick: () => commitReplace(sec.name)
|
|
459
|
+
}, t("add")), (0, react.createElement)("button", {
|
|
460
|
+
style: s.mini,
|
|
461
|
+
onClick: () => setEditing(null)
|
|
462
|
+
}, t("clearReplace"))])]) : (0, react.createElement)("div", { style: s.preview }, String(sec.text ?? "").slice(0, 140) || t("dynamic"))]),
|
|
463
|
+
(0, react.createElement)("div", { style: s.arrowCol }, [(0, react.createElement)("button", {
|
|
464
|
+
style: s.arrow,
|
|
465
|
+
disabled: index === 0,
|
|
466
|
+
onClick: () => moveOrder(index, -1),
|
|
467
|
+
title: t("moveUp")
|
|
468
|
+
}, "↑"), (0, react.createElement)("button", {
|
|
469
|
+
style: s.arrow,
|
|
470
|
+
disabled: index === merged.length - 1,
|
|
471
|
+
onClick: () => moveOrder(index, 1),
|
|
472
|
+
title: t("moveDown")
|
|
473
|
+
}, "↓")]),
|
|
474
|
+
(0, react.createElement)("button", {
|
|
475
|
+
style: s.mini,
|
|
476
|
+
onClick: () => replace[sec.name] ? clearReplace(sec.name) : startReplace(sec.name, String(sec.text ?? ""))
|
|
477
|
+
}, replace[sec.name] ? t("clearReplace") : t("replace"))
|
|
478
|
+
]);
|
|
479
|
+
}),
|
|
480
|
+
(0, react.createElement)("div", { style: s.injectBox }, [(0, react.createElement)("div", { style: s.rowTitle }, t("injectNew")), (0, react.createElement)(InjectForm, {
|
|
481
|
+
onAdd: addSection,
|
|
482
|
+
t
|
|
483
|
+
})])
|
|
484
|
+
]);
|
|
485
|
+
}
|
|
486
|
+
function InjectForm({ onAdd, t }) {
|
|
487
|
+
const [name, setName] = (0, react.useState)("");
|
|
488
|
+
const [order, setOrder] = (0, react.useState)("120");
|
|
489
|
+
const [text, setText] = (0, react.useState)("");
|
|
490
|
+
const submit = () => {
|
|
491
|
+
if (!name.trim()) return;
|
|
492
|
+
onAdd(name.trim(), Number(order) || 120, text);
|
|
493
|
+
setName("");
|
|
494
|
+
setText("");
|
|
495
|
+
setOrder("120");
|
|
496
|
+
};
|
|
497
|
+
return (0, react.createElement)("div", {}, [(0, react.createElement)("div", { style: s.injectRow }, [
|
|
498
|
+
(0, react.createElement)("input", {
|
|
499
|
+
style: {
|
|
500
|
+
...s.input,
|
|
501
|
+
width: "22%"
|
|
502
|
+
},
|
|
503
|
+
placeholder: t("name"),
|
|
504
|
+
value: name,
|
|
505
|
+
onChange: (e) => setName(e.target.value)
|
|
506
|
+
}),
|
|
507
|
+
(0, react.createElement)("input", {
|
|
508
|
+
style: {
|
|
509
|
+
...s.input,
|
|
510
|
+
width: "12%"
|
|
511
|
+
},
|
|
512
|
+
type: "number",
|
|
513
|
+
placeholder: t("order"),
|
|
514
|
+
value: order,
|
|
515
|
+
onChange: (e) => setOrder(e.target.value)
|
|
516
|
+
}),
|
|
517
|
+
(0, react.createElement)("input", {
|
|
518
|
+
style: {
|
|
519
|
+
...s.input,
|
|
520
|
+
flex: 1
|
|
521
|
+
},
|
|
522
|
+
placeholder: t("text"),
|
|
523
|
+
value: text,
|
|
524
|
+
onChange: (e) => setText(e.target.value)
|
|
525
|
+
}),
|
|
526
|
+
(0, react.createElement)("button", {
|
|
527
|
+
style: s.mini,
|
|
528
|
+
onClick: submit
|
|
529
|
+
}, t("add"))
|
|
530
|
+
])]);
|
|
531
|
+
}
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/client/ToolsTab.tsx
|
|
534
|
+
/** Tools tab: hide tools from the model catalog by exclude/include. */
|
|
535
|
+
function ToolsTab({ cfg, inv, scope, t }) {
|
|
536
|
+
const tools = inv?.tools ?? [];
|
|
537
|
+
const toolsCfg = cfg.tools ?? {
|
|
538
|
+
exclude: [],
|
|
539
|
+
include: []
|
|
540
|
+
};
|
|
541
|
+
const exclude = toolsCfg.exclude ?? [];
|
|
542
|
+
const include = toolsCfg.include ?? [];
|
|
543
|
+
const includeMode = include.length > 0;
|
|
544
|
+
const toggle = (name, currentlyHidden) => {
|
|
545
|
+
if (includeMode) {
|
|
546
|
+
const next = include.slice();
|
|
547
|
+
if (currentlyHidden) next.push(name);
|
|
548
|
+
else {
|
|
549
|
+
const i = next.indexOf(name);
|
|
550
|
+
if (i >= 0) next.splice(i, 1);
|
|
551
|
+
}
|
|
552
|
+
scope.set("tools", {
|
|
553
|
+
...toolsCfg,
|
|
554
|
+
include: next
|
|
555
|
+
});
|
|
556
|
+
} else {
|
|
557
|
+
const next = exclude.slice();
|
|
558
|
+
if (currentlyHidden) {
|
|
559
|
+
const i = next.indexOf(name);
|
|
560
|
+
if (i >= 0) next.splice(i, 1);
|
|
561
|
+
} else next.push(name);
|
|
562
|
+
scope.set("tools", {
|
|
563
|
+
...toolsCfg,
|
|
564
|
+
exclude: next
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const setIncludeMode = (on) => {
|
|
569
|
+
scope.set("tools", on ? {
|
|
570
|
+
exclude: exclude.filter((n) => tools.some((tool) => tool.name === n)),
|
|
571
|
+
include: tools.filter((tool) => !tool.hidden).map((tool) => tool.name)
|
|
572
|
+
} : {
|
|
573
|
+
exclude: ensureOnlyKnown(exclude, tools),
|
|
574
|
+
include: []
|
|
575
|
+
});
|
|
576
|
+
};
|
|
577
|
+
return (0, react.createElement)("div", {}, [(0, react.createElement)("div", { style: s.bar }, [(0, react.createElement)("button", {
|
|
578
|
+
style: includeMode ? s.tabActive : s.tab,
|
|
579
|
+
onClick: () => setIncludeMode(true)
|
|
580
|
+
}, t("includeMode")), (0, react.createElement)("button", {
|
|
581
|
+
style: includeMode ? s.tab : s.tabActive,
|
|
582
|
+
onClick: () => setIncludeMode(false)
|
|
583
|
+
}, t("excludeMode"))]), (0, react.createElement)("div", { style: s.list }, [tools.length === 0 ? (0, react.createElement)("div", { style: s.muted }, t("empty")) : null, tools.map((tool) => {
|
|
584
|
+
const hidden = includeMode ? !include.includes(tool.name) : exclude.includes(tool.name);
|
|
585
|
+
return (0, react.createElement)("div", {
|
|
586
|
+
key: tool.name,
|
|
587
|
+
style: s.row
|
|
588
|
+
}, [(0, react.createElement)("label", { style: s.switchWrap }, [(0, react.createElement)("input", {
|
|
589
|
+
type: "checkbox",
|
|
590
|
+
checked: hidden,
|
|
591
|
+
onChange: () => toggle(tool.name, hidden)
|
|
592
|
+
}), (0, react.createElement)("span", { style: hidden ? s.badgeBlocked : s.badgeOk }, hidden ? t("hiddenOn") : t("hiddenOff"))]), (0, react.createElement)("div", { style: s.rowBody }, [(0, react.createElement)("div", { style: s.rowTitle }, (0, react.createElement)("span", { style: s.code }, tool.name)), (0, react.createElement)("div", { style: s.preview }, String(tool.description ?? "").slice(0, 140))])]);
|
|
593
|
+
})])]);
|
|
594
|
+
}
|
|
595
|
+
function ensureOnlyKnown(list, known) {
|
|
596
|
+
const names = known.map((tool) => tool.name);
|
|
597
|
+
return list.filter((n) => names.includes(n));
|
|
598
|
+
}
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region src/client/PresetsTab.tsx
|
|
601
|
+
/** Presets tab: save / apply / export / import complete customization snapshots. */
|
|
602
|
+
function PresetsTab({ cfg, inv, scope, t }) {
|
|
603
|
+
const presets = cfg.presets ?? [];
|
|
604
|
+
const [name, setName] = (0, react.useState)("");
|
|
605
|
+
const fileRef = (0, react.useRef)(null);
|
|
606
|
+
const currentNames = (() => {
|
|
607
|
+
const set = /* @__PURE__ */ new Set();
|
|
608
|
+
for (const sec of inv?.sections ?? []) set.add(sec.name);
|
|
609
|
+
for (const item of cfg.inject ?? []) set.add(item.name);
|
|
610
|
+
return set;
|
|
611
|
+
})();
|
|
612
|
+
const saveCurrent = () => {
|
|
613
|
+
const presetName = name.trim() || `${t("preset")} ${presets.length + 1}`;
|
|
614
|
+
const inject = cfg.inject ?? [];
|
|
615
|
+
const order = inject.map((sec, i) => ({
|
|
616
|
+
name: sec.name,
|
|
617
|
+
after: i > 0 ? inject[i - 1].name : void 0,
|
|
618
|
+
text: sec.text
|
|
619
|
+
}));
|
|
620
|
+
const data = {
|
|
621
|
+
sections: cfg.sections,
|
|
622
|
+
replace: cfg.replace,
|
|
623
|
+
order,
|
|
624
|
+
tools: cfg.tools
|
|
625
|
+
};
|
|
626
|
+
scope.set("presets", [...presets, {
|
|
627
|
+
id: genId(),
|
|
628
|
+
name: presetName,
|
|
629
|
+
data
|
|
630
|
+
}]);
|
|
631
|
+
setName("");
|
|
632
|
+
};
|
|
633
|
+
const applyPreset = (preset) => {
|
|
634
|
+
const presetOrder = preset.data.order ?? [];
|
|
635
|
+
const presetNames = new Set(presetOrder.map((x) => x.name));
|
|
636
|
+
const blocked = new Set(preset.data.sections ?? []);
|
|
637
|
+
for (const name of currentNames) if (!presetNames.has(name)) blocked.add(name);
|
|
638
|
+
for (const name of presetNames) blocked.delete(name);
|
|
639
|
+
scope.set("inject", resolveOrder(presetOrder));
|
|
640
|
+
scope.set("replace", {
|
|
641
|
+
...cfg.replace ?? {},
|
|
642
|
+
...preset.data.replace ?? {}
|
|
643
|
+
});
|
|
644
|
+
scope.set("sections", [...blocked]);
|
|
645
|
+
scope.set("tools", preset.data.tools ?? {
|
|
646
|
+
exclude: [],
|
|
647
|
+
include: []
|
|
648
|
+
});
|
|
649
|
+
scope.set("activePreset", preset.id);
|
|
650
|
+
};
|
|
651
|
+
const deletePreset = (id) => {
|
|
652
|
+
scope.set("presets", presets.filter((p) => p.id !== id));
|
|
653
|
+
if (cfg.activePreset === id) scope.unset("activePreset");
|
|
654
|
+
};
|
|
655
|
+
const exportPreset = (preset) => {
|
|
656
|
+
const blob = new Blob([JSON.stringify({
|
|
657
|
+
name: preset.name,
|
|
658
|
+
data: preset.data
|
|
659
|
+
}, null, 2)], { type: "application/json" });
|
|
660
|
+
const url = URL.createObjectURL(blob);
|
|
661
|
+
const a = document.createElement("a");
|
|
662
|
+
a.href = url;
|
|
663
|
+
a.download = `${preset.name}.json`;
|
|
664
|
+
a.click();
|
|
665
|
+
URL.revokeObjectURL(url);
|
|
666
|
+
};
|
|
667
|
+
const onImportFile = (e) => {
|
|
668
|
+
const file = e.target.files?.[0];
|
|
669
|
+
if (!file) return;
|
|
670
|
+
const reader = new FileReader();
|
|
671
|
+
reader.onload = () => {
|
|
672
|
+
try {
|
|
673
|
+
const parsed = JSON.parse(String(reader.result));
|
|
674
|
+
const incoming = Array.isArray(parsed) ? parsed : [parsed];
|
|
675
|
+
const existing = new Set(presets.map((p) => p.name));
|
|
676
|
+
const added = incoming.filter((p) => p && typeof p.name === "string" && !existing.has(p.name)).map((p) => ({
|
|
677
|
+
id: genId(),
|
|
678
|
+
name: p.name,
|
|
679
|
+
data: p.data ?? {}
|
|
680
|
+
}));
|
|
681
|
+
if (added.length > 0) scope.set("presets", [...presets, ...added]);
|
|
682
|
+
} catch {}
|
|
683
|
+
};
|
|
684
|
+
reader.readAsText(file);
|
|
685
|
+
e.target.value = "";
|
|
686
|
+
};
|
|
687
|
+
return (0, react.createElement)("div", { style: s.list }, [
|
|
688
|
+
(0, react.createElement)("div", { style: s.injectBox }, [(0, react.createElement)("div", { style: s.rowTitle }, t("savePreset")), (0, react.createElement)("div", { style: s.injectRow }, [(0, react.createElement)("input", {
|
|
689
|
+
style: {
|
|
690
|
+
...s.input,
|
|
691
|
+
flex: 1
|
|
692
|
+
},
|
|
693
|
+
placeholder: t("presetName"),
|
|
694
|
+
value: name,
|
|
695
|
+
onChange: (e) => setName(e.target.value)
|
|
696
|
+
}), (0, react.createElement)("button", {
|
|
697
|
+
style: s.mini,
|
|
698
|
+
onClick: saveCurrent
|
|
699
|
+
}, t("save"))])]),
|
|
700
|
+
(0, react.createElement)("div", { style: s.injectBox }, [(0, react.createElement)("div", { style: s.rowTitle }, t("importPreset")), (0, react.createElement)("div", { style: s.injectRow }, [(0, react.createElement)("button", {
|
|
701
|
+
style: s.mini,
|
|
702
|
+
onClick: () => fileRef.current?.click()
|
|
703
|
+
}, t("import")), (0, react.createElement)("input", {
|
|
704
|
+
ref: fileRef,
|
|
705
|
+
type: "file",
|
|
706
|
+
accept: ".json,application/json",
|
|
707
|
+
style: { display: "none" },
|
|
708
|
+
onChange: onImportFile
|
|
709
|
+
})])]),
|
|
710
|
+
presets.length === 0 ? (0, react.createElement)("div", { style: s.muted }, t("empty")) : null,
|
|
711
|
+
presets.map((preset) => {
|
|
712
|
+
const active = cfg.activePreset === preset.id;
|
|
713
|
+
return (0, react.createElement)("div", {
|
|
714
|
+
key: preset.id,
|
|
715
|
+
style: s.row
|
|
716
|
+
}, [
|
|
717
|
+
(0, react.createElement)("div", { style: s.rowBody }, [(0, react.createElement)("div", { style: s.rowTitle }, [(0, react.createElement)("span", { style: s.code }, preset.name), active ? (0, react.createElement)("span", { style: s.badgeOk }, t("active")) : null])]),
|
|
718
|
+
(0, react.createElement)("button", {
|
|
719
|
+
style: s.mini,
|
|
720
|
+
onClick: () => applyPreset(preset)
|
|
721
|
+
}, t("apply")),
|
|
722
|
+
(0, react.createElement)("button", {
|
|
723
|
+
style: s.mini,
|
|
724
|
+
onClick: () => exportPreset(preset)
|
|
725
|
+
}, t("export")),
|
|
726
|
+
(0, react.createElement)("button", {
|
|
727
|
+
style: s.mini,
|
|
728
|
+
onClick: () => deletePreset(preset.id)
|
|
729
|
+
}, t("delete"))
|
|
730
|
+
]);
|
|
731
|
+
})
|
|
732
|
+
]);
|
|
733
|
+
}
|
|
734
|
+
function genId() {
|
|
735
|
+
return "p_" + Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Resolve a preset's relative order into an absolute ordered list (0..n-1).
|
|
739
|
+
* Sections with no anchor (or whose anchor is absent) come first in preset
|
|
740
|
+
* order; each anchored section is inserted right after its anchor; any
|
|
741
|
+
* remaining sections (cycles) are appended.
|
|
742
|
+
*/
|
|
743
|
+
function resolveOrder(presetOrder) {
|
|
744
|
+
const afterMap = /* @__PURE__ */ new Map();
|
|
745
|
+
const textMap = /* @__PURE__ */ new Map();
|
|
746
|
+
for (const sec of presetOrder) {
|
|
747
|
+
afterMap.set(sec.name, sec.after);
|
|
748
|
+
textMap.set(sec.name, sec.text);
|
|
749
|
+
}
|
|
750
|
+
const result = [];
|
|
751
|
+
const placed = /* @__PURE__ */ new Set();
|
|
752
|
+
for (const sec of presetOrder) {
|
|
753
|
+
const anchor = afterMap.get(sec.name);
|
|
754
|
+
if (!anchor || !afterMap.has(anchor)) {
|
|
755
|
+
result.push(sec.name);
|
|
756
|
+
placed.add(sec.name);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
let changed = true;
|
|
760
|
+
while (changed) {
|
|
761
|
+
changed = false;
|
|
762
|
+
for (const sec of presetOrder) {
|
|
763
|
+
if (placed.has(sec.name)) continue;
|
|
764
|
+
const anchor = afterMap.get(sec.name);
|
|
765
|
+
if (anchor && placed.has(anchor)) {
|
|
766
|
+
result.splice(result.indexOf(anchor) + 1, 0, sec.name);
|
|
767
|
+
placed.add(sec.name);
|
|
768
|
+
changed = true;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
for (const sec of presetOrder) if (!placed.has(sec.name)) {
|
|
773
|
+
result.push(sec.name);
|
|
774
|
+
placed.add(sec.name);
|
|
775
|
+
}
|
|
776
|
+
return result.map((name, i) => ({
|
|
777
|
+
name,
|
|
778
|
+
order: i,
|
|
779
|
+
text: textMap.get(name) ?? ""
|
|
780
|
+
}));
|
|
781
|
+
}
|
|
782
|
+
//#endregion
|
|
783
|
+
//#region src/client/index.ts
|
|
784
|
+
/**
|
|
785
|
+
* dsh-prompt-customizer — browser half (TypeScript source).
|
|
786
|
+
*
|
|
787
|
+
* Registers a "提示词定制" settings section (sidebar entry) and a plugin
|
|
788
|
+
* settings card. The panel fetches the effective section / tool inventory
|
|
789
|
+
* from the host `/api/prompt-customizer/inventory` and lets the user block,
|
|
790
|
+
* replace, inject prompt sections and hide tools. All writes go through the
|
|
791
|
+
* bound settings scope (`prompt-customizer` namespace) and apply live.
|
|
792
|
+
*
|
|
793
|
+
* Built by tsdown into the __ModuleLoader__ factory bundle at client/client.js;
|
|
794
|
+
* the only external is the loader module table's react entry.
|
|
795
|
+
*/
|
|
796
|
+
const NS = "prompt-customizer";
|
|
797
|
+
const INVENTORY_URL = "/api/prompt-customizer/inventory";
|
|
798
|
+
const name = "prompt-customizer";
|
|
799
|
+
const inject = ["slots", "locale"];
|
|
800
|
+
function apply(ctx) {
|
|
801
|
+
ctx.effect(() => ctx.locale.register(NS, DICT), "prompt-customizer: locale");
|
|
802
|
+
const t = ctx.locale.bind(NS);
|
|
803
|
+
ctx.inject(["settingsScope"], (scoped) => {
|
|
804
|
+
const scope = scoped.settingsScope.bind({ namespace: NS });
|
|
805
|
+
scoped.slots.inject("settings.section", () => scoped.slots.register({
|
|
806
|
+
name: "settings.section",
|
|
807
|
+
id: "prompt-customizer",
|
|
808
|
+
order: 50,
|
|
809
|
+
label: () => t("nav"),
|
|
810
|
+
locale: NS,
|
|
811
|
+
inject: () => ({ t })
|
|
812
|
+
}, () => (0, react.createElement)(Panel, {
|
|
813
|
+
scope,
|
|
814
|
+
t
|
|
815
|
+
})));
|
|
816
|
+
scoped.slots.inject("settings.plugin.item", () => scoped.slots.register({
|
|
817
|
+
name: "settings.plugin.item",
|
|
818
|
+
key: NS,
|
|
819
|
+
locale: NS,
|
|
820
|
+
inject: () => ({ t })
|
|
821
|
+
}, () => (0, react.createElement)(Panel, {
|
|
822
|
+
scope,
|
|
823
|
+
t
|
|
824
|
+
})));
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
function Panel({ scope, t }) {
|
|
828
|
+
const [snap, setSnap] = (0, react.useState)(() => scope.getSnapshot());
|
|
829
|
+
const [inv, setInv] = (0, react.useState)(null);
|
|
830
|
+
const [tab, setTab] = (0, react.useState)("sections");
|
|
831
|
+
const [error, setError] = (0, react.useState)(null);
|
|
832
|
+
(0, react.useEffect)(() => scope.subscribe(() => setSnap(scope.getSnapshot())), [scope]);
|
|
833
|
+
const refresh = () => {
|
|
834
|
+
fetch(INVENTORY_URL).then((r) => r.json()).then((data) => {
|
|
835
|
+
setInv(data);
|
|
836
|
+
setError(null);
|
|
837
|
+
}).catch((e) => setError(String(e instanceof Error ? e.message : e)));
|
|
838
|
+
};
|
|
839
|
+
(0, react.useEffect)(refresh, []);
|
|
840
|
+
if (snap.status !== "ready" && snap.value === void 0) return (0, react.createElement)("div", { style: s.muted }, t("loading"));
|
|
841
|
+
const cfg = snap.value && typeof snap.value === "object" ? snap.value : {
|
|
842
|
+
sections: [],
|
|
843
|
+
replace: {},
|
|
844
|
+
inject: [],
|
|
845
|
+
tools: {
|
|
846
|
+
exclude: [],
|
|
847
|
+
include: []
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
return (0, react.createElement)("div", { style: s.root }, [
|
|
851
|
+
(0, react.createElement)("div", { style: s.bar }, [
|
|
852
|
+
(0, react.createElement)("button", {
|
|
853
|
+
style: tab === "sections" ? s.tabActive : s.tab,
|
|
854
|
+
onClick: () => setTab("sections")
|
|
855
|
+
}, t("tabsSections")),
|
|
856
|
+
(0, react.createElement)("button", {
|
|
857
|
+
style: tab === "tools" ? s.tabActive : s.tab,
|
|
858
|
+
onClick: () => setTab("tools")
|
|
859
|
+
}, t("tabsTools")),
|
|
860
|
+
(0, react.createElement)("button", {
|
|
861
|
+
style: tab === "presets" ? s.tabActive : s.tab,
|
|
862
|
+
onClick: () => setTab("presets")
|
|
863
|
+
}, t("tabsPresets")),
|
|
864
|
+
(0, react.createElement)("button", {
|
|
865
|
+
style: s.refresh,
|
|
866
|
+
onClick: refresh
|
|
867
|
+
}, t("refresh"))
|
|
868
|
+
]),
|
|
869
|
+
error ? (0, react.createElement)("div", { style: s.error }, String(error)) : null,
|
|
870
|
+
tab === "sections" ? (0, react.createElement)(SectionsTab, {
|
|
871
|
+
cfg,
|
|
872
|
+
inv,
|
|
873
|
+
scope,
|
|
874
|
+
t
|
|
875
|
+
}) : tab === "tools" ? (0, react.createElement)(ToolsTab, {
|
|
876
|
+
cfg,
|
|
877
|
+
inv,
|
|
878
|
+
scope,
|
|
879
|
+
t
|
|
880
|
+
}) : (0, react.createElement)(PresetsTab, {
|
|
881
|
+
cfg,
|
|
882
|
+
inv,
|
|
883
|
+
scope,
|
|
884
|
+
t
|
|
885
|
+
})
|
|
886
|
+
]);
|
|
887
|
+
}
|
|
888
|
+
//#endregion
|
|
889
|
+
exports.apply = apply;
|
|
890
|
+
exports.inject = inject;
|
|
891
|
+
exports.name = name;
|
|
892
|
+
return module.exports;
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
//# sourceMappingURL=client.js.map
|