dsh-prompt-customizer 0.2.5 → 0.2.7

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/client/client.js CHANGED
@@ -15,6 +15,7 @@ window.__ModuleLoader__.load({
15
15
  tabsSections: "提示词",
16
16
  tabsTools: "工具",
17
17
  tabsPresets: "预设",
18
+ tabsPreview: "预览",
18
19
  refresh: "刷新",
19
20
  blockedOff: "未屏蔽",
20
21
  blockedOn: "已屏蔽",
@@ -30,13 +31,18 @@ window.__ModuleLoader__.load({
30
31
  add: "添加",
31
32
  hiddenOff: "可见",
32
33
  hiddenOn: "已隐藏",
33
- includeMode: "白名单模式:仅保留勾选项",
34
- excludeMode: "黑名单模式:勾选 = 隐藏",
34
+ selectAll: "全选",
35
+ selectNone: "全不选",
35
36
  empty: "(空)",
36
37
  dynamic: "<动态生成>",
37
38
  drag: "拖动排序",
38
39
  moveUp: "上移",
39
40
  moveDown: "下移",
41
+ previewHint: "以下为屏蔽/替换/注入后的最终系统提示词:",
42
+ previewPrompt: "提示词预览",
43
+ previewSections: "段",
44
+ previewTools: "工具预览",
45
+ previewToolCount: "个工具",
40
46
  savePreset: "保存当前为预设",
41
47
  presetName: "预设名称",
42
48
  save: "保存",
@@ -55,6 +61,7 @@ window.__ModuleLoader__.load({
55
61
  tabsSections: "Sections",
56
62
  tabsTools: "Tools",
57
63
  tabsPresets: "Presets",
64
+ tabsPreview: "Preview",
58
65
  refresh: "Refresh",
59
66
  blockedOff: "Active",
60
67
  blockedOn: "Blocked",
@@ -70,13 +77,18 @@ window.__ModuleLoader__.load({
70
77
  add: "Add",
71
78
  hiddenOff: "Visible",
72
79
  hiddenOn: "Hidden",
73
- includeMode: "Whitelist: keep only checked",
74
- excludeMode: "Blacklist: check to hide",
80
+ selectAll: "Select all",
81
+ selectNone: "Select none",
75
82
  empty: "(empty)",
76
83
  dynamic: "<dynamic>",
77
84
  drag: "Drag to reorder",
78
85
  moveUp: "Move up",
79
86
  moveDown: "Move down",
87
+ previewHint: "Final system prompt after block/replace/inject:",
88
+ previewPrompt: "Prompt preview",
89
+ previewSections: "sections",
90
+ previewTools: "Tools preview",
91
+ previewToolCount: "tools",
80
92
  savePreset: "Save current as preset",
81
93
  presetName: "Preset name",
82
94
  save: "Save",
@@ -179,6 +191,34 @@ window.__ModuleLoader__.load({
179
191
  textOverflow: "ellipsis",
180
192
  whiteSpace: "nowrap"
181
193
  },
194
+ previewText: {
195
+ fontFamily: "monospace",
196
+ fontSize: 12,
197
+ lineHeight: 1.6,
198
+ whiteSpace: "pre-wrap",
199
+ wordBreak: "break-word",
200
+ maxHeight: 480,
201
+ overflowY: "auto",
202
+ padding: 10,
203
+ border: "1px solid rgba(128,128,128,.2)",
204
+ borderRadius: 8,
205
+ background: "rgba(0,0,0,.18)",
206
+ margin: 0
207
+ },
208
+ toolWrap: {
209
+ display: "flex",
210
+ flexWrap: "wrap",
211
+ gap: 6
212
+ },
213
+ toolChip: {
214
+ fontFamily: "monospace",
215
+ fontSize: 12,
216
+ color: "rgba(128,128,128,.95)",
217
+ border: "1px solid rgba(128,128,128,.3)",
218
+ borderRadius: 6,
219
+ padding: "2px 6px",
220
+ cursor: "help"
221
+ },
182
222
  badgeOk: {
183
223
  color: "#3fb950",
184
224
  fontSize: 11,
@@ -478,60 +518,6 @@ window.__ModuleLoader__.load({
478
518
  replace
479
519
  };
480
520
  }
481
- /** Whether a tool is hidden under the current include/exclude config. */
482
- function isToolHidden(name, toolsCfg) {
483
- const include = toolsCfg?.include ?? [];
484
- const exclude = toolsCfg?.exclude ?? [];
485
- return include.length > 0 ? !include.includes(name) : exclude.includes(name);
486
- }
487
- /** Toggle a tool's hidden state, returning a new tools config. */
488
- function toggleTool(name, currentlyHidden, toolsCfg) {
489
- const include = toolsCfg?.include ?? [];
490
- const exclude = toolsCfg?.exclude ?? [];
491
- if (include.length > 0) {
492
- const next = include.slice();
493
- if (currentlyHidden) {
494
- next.push(name);
495
- return {
496
- exclude: exclude.filter((n) => n !== name),
497
- include: next
498
- };
499
- }
500
- const i = next.indexOf(name);
501
- if (i >= 0) next.splice(i, 1);
502
- return {
503
- exclude,
504
- include: next
505
- };
506
- }
507
- const next = exclude.slice();
508
- if (currentlyHidden) {
509
- const i = next.indexOf(name);
510
- if (i >= 0) next.splice(i, 1);
511
- } else next.push(name);
512
- return {
513
- exclude: next,
514
- include
515
- };
516
- }
517
- /**
518
- * Switch between include (whitelist) and exclude (blacklist) modes. Turning
519
- * include mode on discards names unknown to the current tool set and seeds the
520
- * include list from the currently non-excluded tools; turning it off clears the
521
- * include list (keep only known exclude names).
522
- */
523
- function setToolMode(on, toolsCfg, toolNames) {
524
- const known = new Set(toolNames);
525
- const exclude = (toolsCfg?.exclude ?? []).filter((n) => known.has(n));
526
- if (on) return {
527
- exclude,
528
- include: toolNames.filter((n) => !exclude.includes(n))
529
- };
530
- return {
531
- exclude,
532
- include: []
533
- };
534
- }
535
521
  /** Serialize a preset for export (JSON-safe full snapshot). */
536
522
  function serializePreset(preset) {
537
523
  return {
@@ -808,36 +794,44 @@ window.__ModuleLoader__.load({
808
794
  }
809
795
  //#endregion
810
796
  //#region src/client/ToolsTab.tsx
811
- /** Tools tab: hide tools from the model catalog by exclude/include. */
797
+ /** Tools tab: hide tools from the model catalog (blacklist only — check = hide). */
812
798
  function ToolsTab({ cfg, inv, scope, t }) {
813
799
  const tools = inv?.tools ?? [];
814
- const toolsCfg = cfg.tools ?? {
815
- exclude: [],
816
- include: []
817
- };
818
- const includeMode = (toolsCfg.include ?? []).length > 0;
800
+ const exclude = cfg.tools?.exclude ?? [];
801
+ const hidden = (name) => exclude.includes(name);
819
802
  const toggle = (name, currentlyHidden) => {
820
- scope.set("tools", toggleTool(name, currentlyHidden, toolsCfg));
803
+ const next = exclude.slice();
804
+ if (currentlyHidden) {
805
+ const i = next.indexOf(name);
806
+ if (i >= 0) next.splice(i, 1);
807
+ } else next.push(name);
808
+ scope.set("tools", {
809
+ exclude: next,
810
+ include: []
811
+ });
821
812
  };
822
- const setIncludeMode = (on) => {
823
- scope.set("tools", setToolMode(on, toolsCfg, tools.map((tool) => tool.name)));
813
+ const setAll = (hideAll) => {
814
+ scope.set("tools", {
815
+ exclude: hideAll ? tools.map((tool) => tool.name) : [],
816
+ include: []
817
+ });
824
818
  };
825
819
  return (0, react.createElement)("div", {}, [(0, react.createElement)("div", { style: s.bar }, [(0, react.createElement)("button", {
826
- style: includeMode ? s.tabActive : s.tab,
827
- onClick: () => setIncludeMode(true)
828
- }, t("includeMode")), (0, react.createElement)("button", {
829
- style: includeMode ? s.tab : s.tabActive,
830
- onClick: () => setIncludeMode(false)
831
- }, 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) => {
832
- const hidden = isToolHidden(tool.name, toolsCfg);
820
+ style: s.mini,
821
+ onClick: () => setAll(true)
822
+ }, t("selectAll")), (0, react.createElement)("button", {
823
+ style: s.mini,
824
+ onClick: () => setAll(false)
825
+ }, t("selectNone"))]), (0, react.createElement)("div", { style: s.list }, [tools.length === 0 ? (0, react.createElement)("div", { style: s.muted }, t("empty")) : null, tools.map((tool) => {
826
+ const isHidden = hidden(tool.name);
833
827
  return (0, react.createElement)("div", {
834
828
  key: tool.name,
835
829
  style: s.row
836
830
  }, [(0, react.createElement)("label", { style: s.switchWrap }, [(0, react.createElement)("input", {
837
831
  type: "checkbox",
838
- checked: hidden,
839
- onChange: () => toggle(tool.name, hidden)
840
- }), (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))])]);
832
+ checked: isHidden,
833
+ onChange: () => toggle(tool.name, isHidden)
834
+ }), (0, react.createElement)("span", { style: isHidden ? s.badgeBlocked : s.badgeOk }, isHidden ? 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))])]);
841
835
  })])]);
842
836
  }
843
837
  //#endregion
@@ -945,6 +939,77 @@ window.__ModuleLoader__.load({
945
939
  return "p_" + Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
946
940
  }
947
941
  //#endregion
942
+ //#region src/client/PreviewTools.tsx
943
+ /** Tools preview: read-only whitelist-style list of the tools the current
944
+ * preset will inject (the FINAL model-visible catalog after include/exclude).
945
+ * A tool being listed means it is visible — there is no "blocked" state here.
946
+ * This view never edits the blacklist/whitelist config. */
947
+ function norm(tool) {
948
+ return typeof tool === "string" ? {
949
+ name: tool,
950
+ description: ""
951
+ } : tool;
952
+ }
953
+ function PreviewTools({ tools, t }) {
954
+ if (tools.length === 0) return (0, react.createElement)("div", { style: s.muted }, t("empty"));
955
+ return (0, react.createElement)("div", { style: s.list }, [(0, react.createElement)("div", { style: s.rowTitle }, [(0, react.createElement)("span", { style: s.orderTag }, `${tools.length} ${t("previewToolCount")}`)]), tools.map((tool) => {
956
+ const { name, description } = norm(tool);
957
+ return (0, react.createElement)("div", {
958
+ key: name,
959
+ style: s.row
960
+ }, [(0, react.createElement)("div", { style: s.rowBody }, [(0, react.createElement)("div", { style: s.rowTitle }, (0, react.createElement)("span", { style: s.code }, name)), (0, react.createElement)("div", { style: s.preview }, String(description ?? "").slice(0, 140))])]);
961
+ })]);
962
+ }
963
+ //#endregion
964
+ //#region src/client/PreviewTab.tsx
965
+ /** Preview tab: two read-only sub-tabs — the FINAL assembled system prompt
966
+ * after every plugin's filter, and the tools the current preset will inject
967
+ * (whitelist-style, after include/exclude). Neither view edits config. */
968
+ const PREVIEW_URL = "/api/prompt-customizer/preview";
969
+ function PreviewTab({ scope, t }) {
970
+ const [sub, setSub] = (0, react.useState)("prompt");
971
+ const [data, setData] = (0, react.useState)(null);
972
+ const [error, setError] = (0, react.useState)(null);
973
+ const inFlight = (0, react.useRef)(false);
974
+ const pending = (0, react.useRef)(false);
975
+ const load = () => {
976
+ if (inFlight.current) {
977
+ pending.current = true;
978
+ return;
979
+ }
980
+ inFlight.current = true;
981
+ setData(null);
982
+ fetch(PREVIEW_URL, { cache: "no-store" }).then((r) => r.json()).then((body) => {
983
+ if (body && body.ok === false) throw new Error(body.error ?? "preview failed");
984
+ setData(body);
985
+ setError(null);
986
+ }).catch((e) => setError(String(e instanceof Error ? e.message : e))).finally(() => {
987
+ inFlight.current = false;
988
+ if (pending.current) {
989
+ pending.current = false;
990
+ load();
991
+ }
992
+ });
993
+ };
994
+ (0, react.useEffect)(load, []);
995
+ (0, react.useEffect)(() => scope.subscribe(load), [scope]);
996
+ return (0, react.createElement)("div", { style: s.list }, [
997
+ (0, react.createElement)("div", { style: s.bar }, [(0, react.createElement)("button", {
998
+ style: sub === "prompt" ? s.tabActive : s.tab,
999
+ onClick: () => setSub("prompt")
1000
+ }, t("previewPrompt")), (0, react.createElement)("button", {
1001
+ style: sub === "tools" ? s.tabActive : s.tab,
1002
+ onClick: () => setSub("tools")
1003
+ }, t("previewTools"))]),
1004
+ error ? (0, react.createElement)("div", { style: s.error }, String(error)) : null,
1005
+ data === null && !error ? (0, react.createElement)("div", { style: s.muted }, t("loading")) : null,
1006
+ sub === "prompt" ? data ? [(0, react.createElement)("div", { style: s.rowTitle }, [(0, react.createElement)("span", { style: s.muted }, t("previewHint")), (0, react.createElement)("span", { style: s.orderTag }, `${data.sections.length} ${t("previewSections")}`)]), (0, react.createElement)("pre", { style: s.previewText }, data.text || t("empty"))] : null : data ? (0, react.createElement)(PreviewTools, {
1007
+ tools: data.tools,
1008
+ t
1009
+ }) : null
1010
+ ]);
1011
+ }
1012
+ //#endregion
948
1013
  //#region src/client/index.ts
949
1014
  /**
950
1015
  * dsh-prompt-customizer — browser half (TypeScript source).
@@ -1017,6 +1082,10 @@ window.__ModuleLoader__.load({
1017
1082
  style: tab === "presets" ? s.tabActive : s.tab,
1018
1083
  onClick: () => setTab("presets")
1019
1084
  }, t("tabsPresets")),
1085
+ (0, react.createElement)("button", {
1086
+ style: tab === "preview" ? s.tabActive : s.tab,
1087
+ onClick: () => setTab("preview")
1088
+ }, t("tabsPreview")),
1020
1089
  (0, react.createElement)("button", {
1021
1090
  style: s.refresh,
1022
1091
  onClick: refresh
@@ -1033,11 +1102,14 @@ window.__ModuleLoader__.load({
1033
1102
  inv,
1034
1103
  scope,
1035
1104
  t
1036
- }) : (0, react.createElement)(PresetsTab, {
1105
+ }) : tab === "presets" ? (0, react.createElement)(PresetsTab, {
1037
1106
  cfg,
1038
1107
  inv,
1039
1108
  scope,
1040
1109
  t
1110
+ }) : (0, react.createElement)(PreviewTab, {
1111
+ scope,
1112
+ t
1041
1113
  })
1042
1114
  ]);
1043
1115
  }