dsh-prompt-customizer 0.2.4 → 0.2.5
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 +16 -7
- package/client/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/presets.ts +21 -5
package/client/client.js
CHANGED
|
@@ -459,12 +459,17 @@ window.__ModuleLoader__.load({
|
|
|
459
459
|
/**
|
|
460
460
|
* Remove a custom (plugin-added) section from the config: it disappears from
|
|
461
461
|
* the inject list, is no longer forced into the blocked set, and any replace
|
|
462
|
-
* text for it is cleared.
|
|
463
|
-
*
|
|
462
|
+
* text for it is cleared. The remaining inject entries are re-indexed to a
|
|
463
|
+
* contiguous 0..n-1 order (the virtual index model), so removal never leaves
|
|
464
|
+
* holes. System sections read from the host inventory cannot be removed this
|
|
465
|
+
* way (they would just come back on the next inventory read).
|
|
464
466
|
*/
|
|
465
467
|
function removeSection(name, cfg) {
|
|
466
468
|
const sections = (cfg.sections ?? []).filter((n) => n !== name);
|
|
467
|
-
const inject = (cfg.inject ?? []).filter((item) => item.name !== name)
|
|
469
|
+
const inject = (cfg.inject ?? []).filter((item) => item.name !== name).map((item, i) => ({
|
|
470
|
+
...item,
|
|
471
|
+
order: i
|
|
472
|
+
}));
|
|
468
473
|
const replace = { ...cfg.replace ?? {} };
|
|
469
474
|
delete replace[name];
|
|
470
475
|
return {
|
|
@@ -485,11 +490,15 @@ window.__ModuleLoader__.load({
|
|
|
485
490
|
const exclude = toolsCfg?.exclude ?? [];
|
|
486
491
|
if (include.length > 0) {
|
|
487
492
|
const next = include.slice();
|
|
488
|
-
if (currentlyHidden)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
493
|
+
if (currentlyHidden) {
|
|
494
|
+
next.push(name);
|
|
495
|
+
return {
|
|
496
|
+
exclude: exclude.filter((n) => n !== name),
|
|
497
|
+
include: next
|
|
498
|
+
};
|
|
492
499
|
}
|
|
500
|
+
const i = next.indexOf(name);
|
|
501
|
+
if (i >= 0) next.splice(i, 1);
|
|
493
502
|
return {
|
|
494
503
|
exclude,
|
|
495
504
|
include: next
|
package/client/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","h","h","useState","useRef","h","h","useState"],"sources":["../src/client/locales.ts","../src/client/styles.ts","../src/client/presets.ts","../src/client/SectionsTab.tsx","../src/client/ToolsTab.tsx","../src/client/PresetsTab.tsx","../src/client/index.ts"],"sourcesContent":["/** Locale dictionaries for the prompt-customizer panel. */\nexport const DICT = {\n zh: {\n nav: '提示词定制',\n loading: '加载中…',\n unavailable: '当前环境未启用本命名空间。',\n tabsSections: '提示词',\n tabsTools: '工具',\n tabsPresets: '预设',\n refresh: '刷新',\n blockedOff: '未屏蔽',\n blockedOn: '已屏蔽',\n replaced: '已替换',\n manual: '手动',\n system: '系统',\n replace: '编辑',\n clearReplace: '清除',\n injectNew: '注入新段',\n name: '名称',\n order: '顺序',\n text: '文本',\n add: '添加',\n hiddenOff: '可见',\n hiddenOn: '已隐藏',\n includeMode: '白名单模式:仅保留勾选项',\n excludeMode: '黑名单模式:勾选 = 隐藏',\n empty: '(空)',\n dynamic: '<动态生成>',\n drag: '拖动排序',\n moveUp: '上移',\n moveDown: '下移',\n savePreset: '保存当前为预设',\n presetName: '预设名称',\n save: '保存',\n importPreset: '导入预设',\n import: '导入',\n apply: '应用',\n export: '导出',\n delete: '删除',\n active: '使用中',\n preset: '预设',\n },\n en: {\n nav: 'Prompt Customizer',\n loading: 'Loading…',\n unavailable: 'Namespace unavailable in this environment.',\n tabsSections: 'Sections',\n tabsTools: 'Tools',\n tabsPresets: 'Presets',\n refresh: 'Refresh',\n blockedOff: 'Active',\n blockedOn: 'Blocked',\n replaced: 'Replaced',\n manual: 'Manual',\n system: 'System',\n replace: 'Replace',\n clearReplace: 'Clear',\n injectNew: 'Inject section',\n name: 'Name',\n order: 'Order',\n text: 'Text',\n add: 'Add',\n hiddenOff: 'Visible',\n hiddenOn: 'Hidden',\n includeMode: 'Whitelist: keep only checked',\n excludeMode: 'Blacklist: check to hide',\n empty: '(empty)',\n dynamic: '<dynamic>',\n drag: 'Drag to reorder',\n moveUp: 'Move up',\n moveDown: 'Move down',\n savePreset: 'Save current as preset',\n presetName: 'Preset name',\n save: 'Save',\n importPreset: 'Import preset',\n import: 'Import',\n apply: 'Apply',\n export: 'Export',\n delete: 'Delete',\n active: 'Active',\n preset: 'Preset',\n },\n} as const\n\nexport type Translate = (key: string) => string\n","/** Inline styles shared by the prompt-customizer panel components. */\nexport const s = (() => {\n const flex = { display: 'flex', alignItems: 'center' }\n return {\n root: { fontFamily: 'inherit', fontSize: 13, lineHeight: 1.5 },\n bar: { ...flex, gap: 6, marginBottom: 8, flexWrap: 'wrap' },\n tab: { padding: '4px 10px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', cursor: 'pointer', color: 'inherit', opacity: 0.75 },\n tabActive: { padding: '4px 10px', border: '1px solid rgba(128,128,128,.7)', borderRadius: 6, background: 'rgba(128,128,128,.18)', cursor: 'pointer', color: 'inherit' },\n refresh: { marginLeft: 'auto', padding: '4px 10px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', cursor: 'pointer', color: 'inherit' },\n list: { display: 'flex', flexDirection: 'column', gap: 6 },\n row: { ...flex, gap: 8, padding: '6px 8px', border: '1px solid rgba(128,128,128,.2)', borderRadius: 8, background: 'rgba(128,128,128,.06)' },\n switchWrap: { ...flex, gap: 6, minWidth: 90 },\n rowBody: { flex: 1, minWidth: 0 },\n rowTitle: { ...flex, gap: 6, alignItems: 'baseline', flexWrap: 'wrap' },\n code: { fontFamily: 'monospace', fontSize: 12, wordBreak: 'break-all' },\n orderTag: { color: 'rgba(128,128,128,.8)', fontSize: 11 },\n preview: { color: 'rgba(128,128,128,.85)', fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },\n badgeOk: { color: '#3fb950', fontSize: 11, border: '1px solid rgba(63,185,80,.5)', borderRadius: 999, padding: '0 6px' },\n badgeBlocked: { color: '#f85149', fontSize: 11, border: '1px solid rgba(248,81,73,.5)', borderRadius: 999, padding: '0 6px' },\n badgeReplaced: { color: '#d29922', fontSize: 11, border: '1px solid rgba(210,153,34,.5)', borderRadius: 999, padding: '0 6px' },\n badgeCustom: { color: '#58a6ff', fontSize: 11, border: '1px solid rgba(88,166,255,.5)', borderRadius: 999, padding: '0 6px' },\n badgeSystem: { color: 'rgba(128,128,128,.85)', fontSize: 11, border: '1px solid rgba(128,128,128,.4)', borderRadius: 999, padding: '0 6px' },\n mini: { padding: '3px 8px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', cursor: 'pointer', color: 'inherit', whiteSpace: 'nowrap' },\n arrowCol: { display: 'flex', flexDirection: 'column', gap: 2 },\n arrow: { padding: '0 6px', border: '1px solid rgba(128,128,128,.3)', borderRadius: 4, background: 'transparent', cursor: 'pointer', color: 'inherit', fontSize: 11, lineHeight: 1.4, opacity: 0.8 },\n rowDragging: { opacity: 0.4 },\n rowDropAbove: { boxShadow: '0 -2px 0 0 #58a6ff' },\n rowDropBelow: { boxShadow: '0 2px 0 0 #58a6ff' },\n dragHandle: { cursor: 'grab', color: 'rgba(128,128,128,.7)', fontSize: 13, padding: '0 2px', userSelect: 'none' },\n injectBox: { marginTop: 10, padding: '8px', border: '1px dashed rgba(128,128,128,.4)', borderRadius: 8, display: 'flex', flexDirection: 'column', gap: 6 },\n injectRow: { ...flex, gap: 6 },\n editBox: { display: 'flex', flexDirection: 'column', gap: 6, marginTop: 4 },\n editInput: { padding: '6px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', color: 'inherit', fontFamily: 'inherit', fontSize: 12, resize: 'vertical', width: '100%', boxSizing: 'border-box' },\n input: { padding: '4px 6px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', color: 'inherit' },\n muted: { color: 'rgba(128,128,128,.75)', fontSize: 12 },\n error: { color: '#f85149', fontSize: 12, marginBottom: 6 },\n }\n})()\n","/** Pure preset / section helpers shared by the client UI and the node tests. */\nimport type { Config, Inventory, Preset, PresetData } from './types.ts'\n\nexport interface Section {\n name: string\n order: number\n text?: string\n active: boolean\n replaced: boolean\n /** `system` = read from the host prompt inventory (not deletable); `custom` = added by this plugin (deletable). */\n source?: 'system' | 'custom'\n}\n\n/** The config fields a preset apply must write back to the settings scope. */\nexport interface ConfigPatch {\n sections: string[]\n replace: Record<string, string>\n inject: Array<{ name: string; order: number; text: string }>\n tools: { exclude: string[]; include: string[] }\n}\n\n/**\n * Merge the inventory sections with the user's inject list, sorted by order.\n * Sections read from the inventory (other plugins) are `system`; sections this\n * plugin generated carry a hidden `custom` marker and are `custom`. The source\n * is decided by the hidden marker — never by name collisions — so a custom\n * section keeps its identity (and its deletability) even when its name happens\n * to match an inventory section, and across preset switches. Custom sections\n * always render their own text; they can never be \"<动态生成>\".\n */\nexport function mergeSections(inv: Inventory | null, cfg: Config, blockedNames: ReadonlySet<string>): Section[] {\n const map = new Map<string, Section>()\n for (const sec of inv?.sections ?? []) map.set(sec.name, { ...sec, source: 'system' })\n for (const item of cfg.inject ?? []) {\n const isCustom = item.custom === true\n const existing = map.get(item.name)\n if (existing) {\n map.set(item.name, isCustom\n ? { ...existing, order: item.order, text: item.text ?? '', source: 'custom' }\n : { ...existing, order: item.order, source: 'system' })\n } else {\n map.set(item.name, {\n name: item.name,\n order: item.order,\n text: item.text ?? '',\n active: !blockedNames.has(item.name),\n replaced: false,\n source: isCustom ? 'custom' : 'system',\n })\n }\n }\n return [...map.values()].sort((a, b) => a.order - b.order)\n}\n\n/**\n * Resolve a preset's relative order into an absolute ordered list (0..n-1).\n * Sections with no anchor (or whose anchor is absent) come first in preset\n * order; each anchored section is inserted right after its anchor; any\n * remaining sections (cycles) are appended.\n */\nexport function resolveOrder(presetOrder: PresetData['order']): Array<{ name: string; order: number; text: string; custom?: boolean }> {\n const list = presetOrder ?? []\n const afterMap = new Map<string, string | undefined>()\n const textMap = new Map<string, string>()\n const customMap = new Map<string, boolean>()\n for (const sec of list) {\n afterMap.set(sec.name, sec.after)\n textMap.set(sec.name, sec.text)\n customMap.set(sec.name, sec.custom === true)\n }\n\n const result: string[] = []\n const placed = new Set<string>()\n\n for (const sec of list) {\n const anchor = afterMap.get(sec.name)\n if (!anchor || !afterMap.has(anchor)) { result.push(sec.name); placed.add(sec.name) }\n }\n\n let changed = true\n while (changed) {\n changed = false\n for (const sec of list) {\n if (placed.has(sec.name)) continue\n const anchor = afterMap.get(sec.name)\n if (anchor && placed.has(anchor)) {\n result.splice(result.indexOf(anchor) + 1, 0, sec.name)\n placed.add(sec.name)\n changed = true\n }\n }\n }\n\n for (const sec of list) {\n if (!placed.has(sec.name)) { result.push(sec.name); placed.add(sec.name) }\n }\n\n return result.map((name, i) => ({ name, order: i, text: textMap.get(name) ?? '', custom: customMap.get(name) }))\n}\n\n/**\n * Build a preset snapshot from the current config. The order list is derived\n * from the MERGED section list (not just `cfg.inject`) so that a preset saved\n * after only blocking sections (without reordering) still carries the full\n * ordered set, and thus a meaningful \"active list\" when applied.\n */\nexport function buildPresetData(cfg: Config, merged: Section[]): PresetData {\n // Only custom (plugin-added) sections carry their own text into the preset's\n // order list. System sections keep an empty text so applying the preset only\n // reorders them and never freezes their dynamically generated content.\n const order = merged.map((sec, i) => ({\n name: sec.name,\n after: i > 0 ? merged[i - 1].name : undefined,\n text: sec.source === 'custom' ? (sec.text ?? '') : '',\n custom: sec.source === 'custom',\n }))\n return {\n sections: cfg.sections,\n replace: cfg.replace,\n order,\n tools: cfg.tools,\n }\n}\n\n/**\n * Compute the config patch when applying a preset:\n * - same-name sections are overridden (the order list drives this at runtime)\n * - preset sections missing from the current prompt are added\n * - current sections NOT in the preset's ordered list are disabled by default\n * - only the preset's ACTIVE sections (in the order list but not in its block\n * list) are unblocked; the preset's own blocked sections stay blocked.\n *\n * Custom injected sections that exist in the current config but are NOT in the\n * preset's ordered list are preserved in the resulting inject list (so they\n * stay visible) and disabled (added to the blocked set), rather than silently\n * dropped — a preset must not make the user's own injected sections vanish.\n */\nexport function applyPresetData(data: PresetData, cfg: Config, currentNames: ReadonlySet<string>): ConfigPatch {\n const presetOrder = data.order ?? []\n const presetNames = new Set(presetOrder.map((x) => x.name))\n const blocked = new Set(data.sections ?? [])\n\n // Inject list = the preset's resolved order, then any custom injected\n // sections present in the current config but absent from the preset list.\n // Keeping them in `inject` makes them visible; they are disabled below.\n const inject = resolveOrder(presetOrder)\n const kept = new Set(inject.map((x) => x.name))\n let order = inject.length\n for (const item of cfg.inject ?? []) {\n if (!item || !item.name || presetNames.has(item.name) || kept.has(item.name)) continue\n kept.add(item.name)\n inject.push({ name: item.name, order: order++, text: item.text ?? '', custom: item.custom === true })\n }\n\n // Only enforce the \"active set\" when the preset actually defines an order.\n // An empty order (e.g. a hand-authored / imported preset that only blocks a\n // few sections) must not default-disable every current section.\n if (presetOrder.length > 0) {\n const activeNames = new Set([...presetNames].filter((n) => !blocked.has(n)))\n for (const name of currentNames) if (!presetNames.has(name)) blocked.add(name)\n for (const name of activeNames) blocked.delete(name)\n }\n\n return {\n sections: [...blocked],\n replace: { ...(cfg.replace ?? {}), ...(data.replace ?? {}) },\n inject,\n tools: { exclude: data.tools?.exclude ?? [], include: data.tools?.include ?? [] },\n }\n}\n\n/**\n * Remove a custom (plugin-added) section from the config: it disappears from\n * the inject list, is no longer forced into the blocked set, and any replace\n * text for it is cleared. System sections read from the host inventory cannot\n * be removed this way (they would just come back on the next inventory read).\n */\nexport function removeSection(name: string, cfg: Config): Pick<Config, 'sections' | 'inject' | 'replace'> {\n const sections = (cfg.sections ?? []).filter((n) => n !== name)\n const inject = (cfg.inject ?? []).filter((item) => item.name !== name)\n const replace = { ...(cfg.replace ?? {}) }\n delete replace[name]\n return { sections, inject, replace }\n}\n\n// ── Tool filtering ──────────────────────────────────────────────────────────\n\nexport type ToolsCfg = { exclude?: string[]; include?: string[] }\n\n/** Whether a tool is hidden under the current include/exclude config. */\nexport function isToolHidden(name: string, toolsCfg: ToolsCfg | undefined): boolean {\n const include = toolsCfg?.include ?? []\n const exclude = toolsCfg?.exclude ?? []\n return include.length > 0 ? !include.includes(name) : exclude.includes(name)\n}\n\n/** Toggle a tool's hidden state, returning a new tools config. */\nexport function toggleTool(name: string, currentlyHidden: boolean, toolsCfg: ToolsCfg | undefined): ToolsCfg {\n const include = toolsCfg?.include ?? []\n const exclude = toolsCfg?.exclude ?? []\n if (include.length > 0) {\n const next = include.slice()\n if (currentlyHidden) next.push(name)\n else { const i = next.indexOf(name); if (i >= 0) next.splice(i, 1) }\n return { exclude, include: next }\n }\n const next = exclude.slice()\n if (currentlyHidden) { const i = next.indexOf(name); if (i >= 0) next.splice(i, 1) }\n else next.push(name)\n return { exclude: next, include }\n}\n\n/**\n * Switch between include (whitelist) and exclude (blacklist) modes. Turning\n * include mode on discards names unknown to the current tool set and seeds the\n * include list from the currently non-excluded tools; turning it off clears the\n * include list (keep only known exclude names).\n */\nexport function setToolMode(on: boolean, toolsCfg: ToolsCfg | undefined, toolNames: string[]): ToolsCfg {\n const known = new Set(toolNames)\n const exclude = (toolsCfg?.exclude ?? []).filter((n) => known.has(n))\n if (on) return { exclude, include: toolNames.filter((n) => !exclude.includes(n)) }\n return { exclude, include: [] }\n}\n\n// ── Preset list operations ──────────────────────────────────────────────────\n\n/** Serialize a preset for export (JSON-safe full snapshot). */\nexport function serializePreset(preset: Preset): { name: string; data: PresetData } {\n return { name: preset.name, data: preset.data }\n}\n\n/**\n * Import preset(s): same-name presets are skipped, only distinct names are\n * added. Returns a new presets list (or the original if nothing changed).\n */\nexport function addImportedPresets(existing: Preset[], parsed: unknown, makeId: () => string): Preset[] {\n const incoming = Array.isArray(parsed) ? parsed : [parsed]\n const existingNames = new Set(existing.map((p) => p.name))\n const added = incoming\n .filter((p) => p && typeof (p as { name?: unknown }).name === 'string' && !existingNames.has((p as Preset).name))\n .map((p) => ({ id: makeId(), name: (p as Preset).name, data: ((p as Preset).data ?? {}) as PresetData }))\n return added.length > 0 ? [...existing, ...added] : existing\n}\n\n/** Delete a preset, clearing the active id if it pointed at the removed one. */\nexport function removePreset(presets: Preset[], id: string, activeId?: string): { presets: Preset[]; activeId?: string } {\n return {\n presets: presets.filter((p) => p.id !== id),\n activeId: activeId === id ? undefined : activeId,\n }\n}\n","/** Prompt-sections tab: block / replace / inject / reorder prompt sections. */\nimport { createElement as h, useState, type ReactElement, type DragEvent, type ChangeEvent } from 'react'\nimport type { Config, Inventory, SettingsScope } from './types.ts'\nimport type { Translate } from './locales.ts'\nimport { mergeSections, removeSection, type Section } from './presets.ts'\nimport { s } from './styles.ts'\n\nexport function SectionsTab({ cfg, inv, scope, t }: { cfg: Config; inv: Inventory | null; scope: SettingsScope; t: Translate }): ReactElement {\n const replace = cfg.replace ?? {}\n const blockedNames = new Set(cfg.sections ?? [])\n const [editing, setEditing] = useState<string | null>(null)\n const [draft, setDraft] = useState('')\n const [dragName, setDragName] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<{ name: string; pos: 'above' | 'below' } | null>(null)\n\n // Merge inventory sections with user-injected sections, sorted by order.\n // Injected sections that don't exist in the original prompt appear here too,\n // positioned by their order value.\n const merged: Section[] = mergeSections(inv, cfg, blockedNames)\n\n const toggleBlock = (name: string, currentlyBlocked: boolean): void => {\n const list = (cfg.sections ?? []).slice()\n if (currentlyBlocked) { const i = list.indexOf(name); if (i >= 0) list.splice(i, 1) }\n else list.push(name)\n scope.set('sections', list)\n }\n const startReplace = (name: string, original: string): void => {\n // Echo the ORIGINAL prompt text so the user edits from the current value.\n setEditing(name)\n setDraft(replace[name] ?? original)\n }\n const commitReplace = (name: string): void => {\n const next = { ...replace }\n if (draft.trim() === '') delete next[name]\n else next[name] = draft\n scope.set('replace', next)\n setEditing(null)\n }\n const clearReplace = (name: string): void => {\n const next = { ...replace }\n delete next[name]\n scope.set('replace', next)\n }\n\n // Persist the full ordered list. We treat the sorted list as an array and\n // re-index every section with a sequential integer order (0, 1, 2, …), so\n // there are never duplicate or fractional orders. System sections keep empty\n // text (so we never freeze their dynamically generated content); custom\n // (plugin-generated) sections keep their own text and the hidden `custom`\n // marker, so they render real content and stay identifiable/deletable.\n const persistOrder = (ordered: Section[]): void => {\n const list = ordered.map((sec, i) => {\n const existing = (cfg.inject ?? []).find((x) => x.name === sec.name)\n const isCustom = sec.source === 'custom'\n return { name: sec.name, order: i, text: isCustom ? (sec.text ?? '') : (existing?.text ?? ''), custom: isCustom }\n })\n scope.set('inject', list)\n }\n\n // Delete a custom (plugin-added) section: remove it from inject / sections /\n // replace so it no longer appears in the panel at all.\n const removeCustom = (name: string): void => {\n const patch = removeSection(name, cfg)\n scope.set('sections', patch.sections)\n scope.set('inject', patch.inject)\n scope.set('replace', patch.replace)\n }\n\n // Move a section up/down one slot (array-index swap), then re-index.\n const moveOrder = (index: number, dir: -1 | 1): void => {\n const target = index + dir\n if (target < 0 || target >= merged.length) return\n const next = merged.slice()\n const [item] = next.splice(index, 1)\n next.splice(target, 0, item)\n persistOrder(next)\n }\n\n const onDragStart = (e: DragEvent, name: string): void => {\n setDragName(name)\n e.dataTransfer.effectAllowed = 'move'\n try { e.dataTransfer.setData('text/plain', name) } catch { /* ignore */ }\n }\n const onDragOver = (e: DragEvent, name: string): void => {\n if (!dragName || dragName === name) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n const rect = e.currentTarget.getBoundingClientRect()\n const pos = e.clientY < rect.top + rect.height / 2 ? 'above' : 'below'\n setDropTarget({ name, pos })\n }\n const onDrop = (e: DragEvent, target: Section): void => {\n e.preventDefault()\n if (!dragName || dragName === target.name) { setDragName(null); setDropTarget(null); return }\n const dragged = merged.find((x) => x.name === dragName)\n if (!dragged) { setDragName(null); setDropTarget(null); return }\n const next = merged.filter((x) => x.name !== dragName)\n const idx = next.findIndex((x) => x.name === target.name)\n const pos = dropTarget?.name === target.name ? dropTarget.pos : 'below'\n next.splice(pos === 'above' ? idx : idx + 1, 0, dragged)\n persistOrder(next)\n setDragName(null)\n setDropTarget(null)\n }\n const onDragEnd = (): void => { setDragName(null); setDropTarget(null) }\n\n // Add a new injected section, placed by its order hint, then re-index. The\n // section is marked `custom` (the hidden marker) so it is identified as\n // plugin-generated and thus deletable, and its own text is preserved.\n const addSection = (name: string, order: number, text: string): void => {\n const next = merged.slice()\n const entry: Section = { name, order, text, active: true, replaced: false, source: 'custom' }\n const existing = next.findIndex((x) => x.name === name)\n if (existing >= 0) next[existing] = entry\n else {\n const idx = next.findIndex((x) => x.order > order)\n if (idx < 0) next.push(entry)\n else next.splice(idx, 0, entry)\n }\n persistOrder(next)\n }\n\n return h('div', { style: s.list }, [\n merged.length === 0 ? h('div', { style: s.muted }, t('empty')) : null,\n merged.map((sec, index) => {\n const blocked = blockedNames.has(sec.name)\n const isEditing = editing === sec.name\n const isDragging = dragName === sec.name\n const isDropTarget = dropTarget?.name === sec.name\n const rowStyle = {\n ...s.row,\n ...(isDragging ? s.rowDragging : {}),\n ...(isDropTarget && dropTarget.pos === 'above' ? s.rowDropAbove : {}),\n ...(isDropTarget && dropTarget.pos === 'below' ? s.rowDropBelow : {}),\n }\n return h('div', {\n key: sec.name,\n style: rowStyle,\n draggable: true,\n onDragStart: (e: DragEvent) => onDragStart(e, sec.name),\n onDragOver: (e: DragEvent) => onDragOver(e, sec.name),\n onDrop: (e: DragEvent) => onDrop(e, sec),\n onDragEnd,\n }, [\n h('span', { style: s.dragHandle, title: t('drag') }, '⠿'),\n h('label', { style: s.switchWrap }, [\n h('input', { type: 'checkbox', checked: blocked, onChange: () => toggleBlock(sec.name, blocked) }),\n h('span', { style: blocked ? s.badgeBlocked : s.badgeOk }, blocked ? t('blockedOn') : t('blockedOff')),\n ]),\n h('div', { style: s.rowBody }, [\n h('div', { style: s.rowTitle }, [\n h('span', { style: s.code }, sec.name),\n h('span', { style: s.orderTag }, '#' + index),\n h('span', { style: sec.source === 'custom' ? s.badgeCustom : s.badgeSystem }, sec.source === 'custom' ? t('manual') : t('system')),\n sec.replaced ? h('span', { style: s.badgeReplaced }, t('replaced')) : null,\n ]),\n isEditing\n ? h('div', { style: s.editBox }, [\n h('textarea', { style: s.editInput, value: draft, onChange: (e: ChangeEvent<HTMLTextAreaElement>) => setDraft(e.target.value), rows: 3 }),\n h('div', { style: s.injectRow }, [\n h('button', { style: s.mini, onClick: () => commitReplace(sec.name) }, t('add')),\n h('button', { style: s.mini, onClick: () => setEditing(null) }, t('clearReplace')),\n ]),\n ])\n : h('div', { style: s.preview }, String(sec.text ?? '').slice(0, 140) || (sec.source === 'custom' ? t('empty') : t('dynamic'))),\n ]),\n h('div', { style: s.arrowCol }, [\n h('button', { style: s.arrow, disabled: index === 0, onClick: () => moveOrder(index, -1), title: t('moveUp') }, '↑'),\n h('button', { style: s.arrow, disabled: index === merged.length - 1, onClick: () => moveOrder(index, 1), title: t('moveDown') }, '↓'),\n ]),\n h('button', { style: s.mini, onClick: () => replace[sec.name] ? clearReplace(sec.name) : startReplace(sec.name, String(sec.text ?? '')) }, replace[sec.name] ? t('clearReplace') : t('replace')),\n sec.source === 'custom' ? h('button', { style: s.mini, onClick: () => removeCustom(sec.name), title: t('delete') }, t('delete')) : null,\n ])\n }),\n h('div', { style: s.injectBox }, [\n h('div', { style: s.rowTitle }, t('injectNew')),\n h(InjectForm, { onAdd: addSection, t }),\n ]),\n ])\n}\n\nfunction InjectForm({ onAdd, t }: { onAdd: (name: string, order: number, text: string) => void; t: Translate }): ReactElement {\n const [name, setName] = useState('')\n const [order, setOrder] = useState('120')\n const [text, setText] = useState('')\n\n const submit = (): void => {\n if (!name.trim()) return\n onAdd(name.trim(), Number(order) || 120, text)\n setName(''); setText(''); setOrder('120')\n }\n\n return h('div', {}, [\n h('div', { style: s.injectRow }, [\n h('input', { style: { ...s.input, width: '22%' }, placeholder: t('name'), value: name, onChange: (e) => setName(e.target.value) }),\n h('input', { style: { ...s.input, width: '12%' }, type: 'number', placeholder: t('order'), value: order, onChange: (e) => setOrder(e.target.value) }),\n h('input', { style: { ...s.input, flex: 1 }, placeholder: t('text'), value: text, onChange: (e) => setText(e.target.value) }),\n h('button', { style: s.mini, onClick: submit }, t('add')),\n ]),\n ])\n}\n","/** Tools tab: hide tools from the model catalog by exclude/include. */\nimport { createElement as h, type ReactElement } from 'react'\nimport type { Config, Inventory, SettingsScope } from './types.ts'\nimport type { Translate } from './locales.ts'\nimport { isToolHidden, setToolMode, toggleTool } from './presets.ts'\nimport { s } from './styles.ts'\n\nexport function ToolsTab({ cfg, inv, scope, t }: { cfg: Config; inv: Inventory | null; scope: SettingsScope; t: Translate }): ReactElement {\n const tools = inv?.tools ?? []\n const toolsCfg = cfg.tools ?? { exclude: [], include: [] }\n const includeMode = (toolsCfg.include ?? []).length > 0\n\n const toggle = (name: string, currentlyHidden: boolean): void => {\n scope.set('tools', toggleTool(name, currentlyHidden, toolsCfg))\n }\n const setIncludeMode = (on: boolean): void => {\n scope.set('tools', setToolMode(on, toolsCfg, tools.map((tool) => tool.name)))\n }\n\n return h('div', {}, [\n h('div', { style: s.bar }, [\n h('button', { style: includeMode ? s.tabActive : s.tab, onClick: () => setIncludeMode(true) }, t('includeMode')),\n h('button', { style: includeMode ? s.tab : s.tabActive, onClick: () => setIncludeMode(false) }, t('excludeMode')),\n ]),\n h('div', { style: s.list }, [\n tools.length === 0 ? h('div', { style: s.muted }, t('empty')) : null,\n tools.map((tool) => {\n // Hidden state comes from the CONFIG (exclude/include lists), not the\n // inventory snapshot, so toggling updates the checkbox immediately.\n const hidden = isToolHidden(tool.name, toolsCfg)\n return h('div', { key: tool.name, style: s.row }, [\n h('label', { style: s.switchWrap }, [\n h('input', { type: 'checkbox', checked: hidden, onChange: () => toggle(tool.name, hidden) }),\n h('span', { style: hidden ? s.badgeBlocked : s.badgeOk }, hidden ? t('hiddenOn') : t('hiddenOff')),\n ]),\n h('div', { style: s.rowBody }, [\n h('div', { style: s.rowTitle }, h('span', { style: s.code }, tool.name)),\n h('div', { style: s.preview }, String(tool.description ?? '').slice(0, 140)),\n ]),\n ])\n }),\n ]),\n ])\n}\n","/** Presets tab: save / apply / export / import complete customization snapshots. */\nimport { createElement as h, useRef, useState, type ReactElement, type ChangeEvent } from 'react'\nimport type { Config, Inventory, Preset, PresetData, SettingsScope } from './types.ts'\nimport type { Translate } from './locales.ts'\nimport { addImportedPresets, applyPresetData, buildPresetData, mergeSections, removePreset, serializePreset } from './presets.ts'\nimport { s } from './styles.ts'\n\nexport function PresetsTab({ cfg, inv, scope, t }: { cfg: Config; inv: Inventory | null; scope: SettingsScope; t: Translate }): ReactElement {\n const presets = cfg.presets ?? []\n const [name, setName] = useState('')\n const fileRef = useRef<HTMLInputElement | null>(null)\n\n const blockedNames = new Set(cfg.sections ?? [])\n const merged = mergeSections(inv, cfg, blockedNames)\n const currentNames = new Set(merged.map((sec) => sec.name))\n\n // Capture the current customization as a new preset (full snapshot). The\n // absolute order is converted to a relative form (each section records the\n // section it should follow) so the preset stays portable across prompts.\n const saveCurrent = (): void => {\n const presetName = name.trim() || `${t('preset')} ${presets.length + 1}`\n const data = buildPresetData(cfg, merged)\n scope.set('presets', [...presets, { id: genId(), name: presetName, data }])\n setName('')\n }\n\n // Apply a preset. The patch is computed by the pure helper:\n // - same-name sections are overridden (content + order)\n // - preset sections missing from the current prompt are added\n // - current sections NOT in the preset list are disabled (blocked)\n // - only the preset's ACTIVE sections are unblocked (its own blocked list\n // is preserved)\n const applyPreset = (preset: Preset): void => {\n const patch = applyPresetData(preset.data, cfg, currentNames)\n scope.set('inject', patch.inject)\n scope.set('replace', patch.replace)\n scope.set('sections', patch.sections)\n scope.set('tools', patch.tools)\n scope.set('activePreset', preset.id)\n }\n\n const deletePreset = (id: string): void => {\n const next = removePreset(presets, id, cfg.activePreset)\n scope.set('presets', next.presets)\n if (next.activeId === undefined && cfg.activePreset === id) scope.unset('activePreset')\n }\n\n // Serialize a preset to a downloadable JSON file.\n const exportPreset = (preset: Preset): void => {\n const blob = new Blob([JSON.stringify(serializePreset(preset), null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${preset.name}.json`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n // Import preset(s) from a JSON file. Same-name presets are skipped; only\n // presets with new names are added to the local list.\n const onImportFile = (e: ChangeEvent<HTMLInputElement>): void => {\n const file = e.target.files?.[0]\n if (!file) return\n const reader = new FileReader()\n reader.onload = () => {\n try {\n const parsed = JSON.parse(String(reader.result))\n scope.set('presets', addImportedPresets(presets, parsed, genId))\n } catch { /* ignore invalid json */ }\n }\n reader.readAsText(file)\n e.target.value = ''\n }\n\n return h('div', { style: s.list }, [\n h('div', { style: s.injectBox }, [\n h('div', { style: s.rowTitle }, t('savePreset')),\n h('div', { style: s.injectRow }, [\n h('input', { style: { ...s.input, flex: 1 }, placeholder: t('presetName'), value: name, onChange: (e: ChangeEvent<HTMLInputElement>) => setName(e.target.value) }),\n h('button', { style: s.mini, onClick: saveCurrent }, t('save')),\n ]),\n ]),\n h('div', { style: s.injectBox }, [\n h('div', { style: s.rowTitle }, t('importPreset')),\n h('div', { style: s.injectRow }, [\n h('button', { style: s.mini, onClick: () => fileRef.current?.click() }, t('import')),\n h('input', { ref: fileRef, type: 'file', accept: '.json,application/json', style: { display: 'none' }, onChange: onImportFile }),\n ]),\n ]),\n presets.length === 0 ? h('div', { style: s.muted }, t('empty')) : null,\n presets.map((preset) => {\n const active = cfg.activePreset === preset.id\n return h('div', { key: preset.id, style: s.row }, [\n h('div', { style: s.rowBody }, [\n h('div', { style: s.rowTitle }, [\n h('span', { style: s.code }, preset.name),\n active ? h('span', { style: s.badgeOk }, t('active')) : null,\n ]),\n ]),\n h('button', { style: s.mini, onClick: () => applyPreset(preset) }, t('apply')),\n h('button', { style: s.mini, onClick: () => exportPreset(preset) }, t('export')),\n h('button', { style: s.mini, onClick: () => deletePreset(preset.id) }, t('delete')),\n ])\n }),\n ])\n}\n\nfunction genId(): string {\n return 'p_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7)\n}\n","/**\n * dsh-prompt-customizer — browser half (TypeScript source).\n *\n * Registers a \"提示词定制\" settings section (sidebar entry) and a plugin\n * settings card. The panel fetches the effective section / tool inventory\n * from the host `/api/prompt-customizer/inventory` and lets the user block,\n * replace, inject prompt sections and hide tools. All writes go through the\n * bound settings scope (`prompt-customizer` namespace) and apply live.\n *\n * Built by tsdown into the __ModuleLoader__ factory bundle at client/client.js;\n * the only external is the loader module table's react entry.\n */\nimport { createElement as h, useEffect, useState, type ReactElement } from 'react'\nimport { DICT, type Translate } from './locales.ts'\nimport { s } from './styles.ts'\nimport type { Config, Inventory, SettingsScope } from './types.ts'\nimport { SectionsTab } from './SectionsTab.tsx'\nimport { ToolsTab } from './ToolsTab.tsx'\nimport { PresetsTab } from './PresetsTab.tsx'\n\nconst NS = 'prompt-customizer'\nconst INVENTORY_URL = '/api/prompt-customizer/inventory'\n\nexport const name = 'prompt-customizer'\nexport const inject = ['slots', 'locale']\n\n/** The subset of the client cordis context this plugin touches. */\ninterface ClientContext {\n effect(callback: () => unknown, label?: string): void\n locale: {\n register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string> }): unknown\n bind(namespace: string): Translate\n }\n inject(services: string[], callback: (scoped: SettingsScopeHost) => void): void\n}\n\n/** The host surface the settings card needs (settingsScope transport). */\ninterface SettingsScopeHost {\n settingsScope: {\n bind(options: { namespace: string }): SettingsScope\n }\n slots: {\n inject(name: string, register: () => unknown): void\n register(meta: Record<string, unknown>, render: () => unknown): unknown\n }\n}\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, DICT), 'prompt-customizer: locale')\n const t = ctx.locale.bind(NS)\n\n // Register a standalone settings section (sidebar menu entry) so the panel\n // only appears under \"提示词定制\", not as a card inside the \"插件\" settings\n // list. Goes through a NESTED inject of settingsScope so the panel can\n // read/write the namespace config; on hosts without the settings transport\n // it stays hidden instead of unmounting the whole plugin.\n ctx.inject(['settingsScope'], (scoped) => {\n const scope = scoped.settingsScope.bind({ namespace: NS })\n\n scoped.slots.inject('settings.section', () => scoped.slots.register({\n name: 'settings.section',\n id: 'prompt-customizer',\n order: 50,\n label: () => t('nav'),\n locale: NS,\n inject: () => ({ t }),\n }, () => h(Panel, { scope, t })))\n })\n}\n\n// ── Root panel ──────────────────────────────────────────────────────────────\n\nfunction Panel({ scope, t }: { scope: SettingsScope; t: Translate }): ReactElement {\n const [snap, setSnap] = useState(() => scope.getSnapshot())\n const [inv, setInv] = useState<Inventory | null>(null)\n const [tab, setTab] = useState<'sections' | 'tools' | 'presets'>('sections')\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => scope.subscribe(() => setSnap(scope.getSnapshot())), [scope])\n\n const refresh = (): void => {\n fetch(INVENTORY_URL)\n .then((r) => r.json())\n .then((data: Inventory) => { setInv(data); setError(null) })\n .catch((e: unknown) => setError(String(e instanceof Error ? e.message : e)))\n }\n useEffect(refresh, [])\n\n if (snap.status !== 'ready' && snap.value === undefined) {\n return h('div', { style: s.muted }, t('loading'))\n }\n\n const cfg: Config = snap.value && typeof snap.value === 'object'\n ? snap.value as Config\n : { sections: [], replace: {}, inject: [], tools: { exclude: [], include: [] } }\n\n return h('div', { style: s.root }, [\n h('div', { style: s.bar }, [\n h('button', { style: tab === 'sections' ? s.tabActive : s.tab, onClick: () => setTab('sections') }, t('tabsSections')),\n h('button', { style: tab === 'tools' ? s.tabActive : s.tab, onClick: () => setTab('tools') }, t('tabsTools')),\n h('button', { style: tab === 'presets' ? s.tabActive : s.tab, onClick: () => setTab('presets') }, t('tabsPresets')),\n h('button', { style: s.refresh, onClick: refresh }, t('refresh')),\n ]),\n error ? h('div', { style: s.error }, String(error)) : null,\n tab === 'sections'\n ? h(SectionsTab, { cfg, inv, scope, t })\n : tab === 'tools'\n ? h(ToolsTab, { cfg, inv, scope, t })\n : h(PresetsTab, { cfg, inv, scope, t }),\n ])\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","h","h","useState","useRef","h","h","useState"],"sources":["../src/client/locales.ts","../src/client/styles.ts","../src/client/presets.ts","../src/client/SectionsTab.tsx","../src/client/ToolsTab.tsx","../src/client/PresetsTab.tsx","../src/client/index.ts"],"sourcesContent":["/** Locale dictionaries for the prompt-customizer panel. */\nexport const DICT = {\n zh: {\n nav: '提示词定制',\n loading: '加载中…',\n unavailable: '当前环境未启用本命名空间。',\n tabsSections: '提示词',\n tabsTools: '工具',\n tabsPresets: '预设',\n refresh: '刷新',\n blockedOff: '未屏蔽',\n blockedOn: '已屏蔽',\n replaced: '已替换',\n manual: '手动',\n system: '系统',\n replace: '编辑',\n clearReplace: '清除',\n injectNew: '注入新段',\n name: '名称',\n order: '顺序',\n text: '文本',\n add: '添加',\n hiddenOff: '可见',\n hiddenOn: '已隐藏',\n includeMode: '白名单模式:仅保留勾选项',\n excludeMode: '黑名单模式:勾选 = 隐藏',\n empty: '(空)',\n dynamic: '<动态生成>',\n drag: '拖动排序',\n moveUp: '上移',\n moveDown: '下移',\n savePreset: '保存当前为预设',\n presetName: '预设名称',\n save: '保存',\n importPreset: '导入预设',\n import: '导入',\n apply: '应用',\n export: '导出',\n delete: '删除',\n active: '使用中',\n preset: '预设',\n },\n en: {\n nav: 'Prompt Customizer',\n loading: 'Loading…',\n unavailable: 'Namespace unavailable in this environment.',\n tabsSections: 'Sections',\n tabsTools: 'Tools',\n tabsPresets: 'Presets',\n refresh: 'Refresh',\n blockedOff: 'Active',\n blockedOn: 'Blocked',\n replaced: 'Replaced',\n manual: 'Manual',\n system: 'System',\n replace: 'Replace',\n clearReplace: 'Clear',\n injectNew: 'Inject section',\n name: 'Name',\n order: 'Order',\n text: 'Text',\n add: 'Add',\n hiddenOff: 'Visible',\n hiddenOn: 'Hidden',\n includeMode: 'Whitelist: keep only checked',\n excludeMode: 'Blacklist: check to hide',\n empty: '(empty)',\n dynamic: '<dynamic>',\n drag: 'Drag to reorder',\n moveUp: 'Move up',\n moveDown: 'Move down',\n savePreset: 'Save current as preset',\n presetName: 'Preset name',\n save: 'Save',\n importPreset: 'Import preset',\n import: 'Import',\n apply: 'Apply',\n export: 'Export',\n delete: 'Delete',\n active: 'Active',\n preset: 'Preset',\n },\n} as const\n\nexport type Translate = (key: string) => string\n","/** Inline styles shared by the prompt-customizer panel components. */\nexport const s = (() => {\n const flex = { display: 'flex', alignItems: 'center' }\n return {\n root: { fontFamily: 'inherit', fontSize: 13, lineHeight: 1.5 },\n bar: { ...flex, gap: 6, marginBottom: 8, flexWrap: 'wrap' },\n tab: { padding: '4px 10px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', cursor: 'pointer', color: 'inherit', opacity: 0.75 },\n tabActive: { padding: '4px 10px', border: '1px solid rgba(128,128,128,.7)', borderRadius: 6, background: 'rgba(128,128,128,.18)', cursor: 'pointer', color: 'inherit' },\n refresh: { marginLeft: 'auto', padding: '4px 10px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', cursor: 'pointer', color: 'inherit' },\n list: { display: 'flex', flexDirection: 'column', gap: 6 },\n row: { ...flex, gap: 8, padding: '6px 8px', border: '1px solid rgba(128,128,128,.2)', borderRadius: 8, background: 'rgba(128,128,128,.06)' },\n switchWrap: { ...flex, gap: 6, minWidth: 90 },\n rowBody: { flex: 1, minWidth: 0 },\n rowTitle: { ...flex, gap: 6, alignItems: 'baseline', flexWrap: 'wrap' },\n code: { fontFamily: 'monospace', fontSize: 12, wordBreak: 'break-all' },\n orderTag: { color: 'rgba(128,128,128,.8)', fontSize: 11 },\n preview: { color: 'rgba(128,128,128,.85)', fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },\n badgeOk: { color: '#3fb950', fontSize: 11, border: '1px solid rgba(63,185,80,.5)', borderRadius: 999, padding: '0 6px' },\n badgeBlocked: { color: '#f85149', fontSize: 11, border: '1px solid rgba(248,81,73,.5)', borderRadius: 999, padding: '0 6px' },\n badgeReplaced: { color: '#d29922', fontSize: 11, border: '1px solid rgba(210,153,34,.5)', borderRadius: 999, padding: '0 6px' },\n badgeCustom: { color: '#58a6ff', fontSize: 11, border: '1px solid rgba(88,166,255,.5)', borderRadius: 999, padding: '0 6px' },\n badgeSystem: { color: 'rgba(128,128,128,.85)', fontSize: 11, border: '1px solid rgba(128,128,128,.4)', borderRadius: 999, padding: '0 6px' },\n mini: { padding: '3px 8px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', cursor: 'pointer', color: 'inherit', whiteSpace: 'nowrap' },\n arrowCol: { display: 'flex', flexDirection: 'column', gap: 2 },\n arrow: { padding: '0 6px', border: '1px solid rgba(128,128,128,.3)', borderRadius: 4, background: 'transparent', cursor: 'pointer', color: 'inherit', fontSize: 11, lineHeight: 1.4, opacity: 0.8 },\n rowDragging: { opacity: 0.4 },\n rowDropAbove: { boxShadow: '0 -2px 0 0 #58a6ff' },\n rowDropBelow: { boxShadow: '0 2px 0 0 #58a6ff' },\n dragHandle: { cursor: 'grab', color: 'rgba(128,128,128,.7)', fontSize: 13, padding: '0 2px', userSelect: 'none' },\n injectBox: { marginTop: 10, padding: '8px', border: '1px dashed rgba(128,128,128,.4)', borderRadius: 8, display: 'flex', flexDirection: 'column', gap: 6 },\n injectRow: { ...flex, gap: 6 },\n editBox: { display: 'flex', flexDirection: 'column', gap: 6, marginTop: 4 },\n editInput: { padding: '6px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', color: 'inherit', fontFamily: 'inherit', fontSize: 12, resize: 'vertical', width: '100%', boxSizing: 'border-box' },\n input: { padding: '4px 6px', border: '1px solid rgba(128,128,128,.35)', borderRadius: 6, background: 'transparent', color: 'inherit' },\n muted: { color: 'rgba(128,128,128,.75)', fontSize: 12 },\n error: { color: '#f85149', fontSize: 12, marginBottom: 6 },\n }\n})()\n","/** Pure preset / section helpers shared by the client UI and the node tests. */\nimport type { Config, Inventory, Preset, PresetData } from './types.ts'\n\nexport interface Section {\n name: string\n order: number\n text?: string\n active: boolean\n replaced: boolean\n /** `system` = read from the host prompt inventory (not deletable); `custom` = added by this plugin (deletable). */\n source?: 'system' | 'custom'\n}\n\n/** The config fields a preset apply must write back to the settings scope. */\nexport interface ConfigPatch {\n sections: string[]\n replace: Record<string, string>\n inject: Array<{ name: string; order: number; text: string }>\n tools: { exclude: string[]; include: string[] }\n}\n\n/**\n * Merge the inventory sections with the user's inject list, sorted by order.\n * Sections read from the inventory (other plugins) are `system`; sections this\n * plugin generated carry a hidden `custom` marker and are `custom`. The source\n * is decided by the hidden marker — never by name collisions — so a custom\n * section keeps its identity (and its deletability) even when its name happens\n * to match an inventory section, and across preset switches. Custom sections\n * always render their own text; they can never be \"<动态生成>\".\n */\nexport function mergeSections(inv: Inventory | null, cfg: Config, blockedNames: ReadonlySet<string>): Section[] {\n const map = new Map<string, Section>()\n for (const sec of inv?.sections ?? []) map.set(sec.name, { ...sec, source: 'system' })\n for (const item of cfg.inject ?? []) {\n const isCustom = item.custom === true\n const existing = map.get(item.name)\n if (existing) {\n map.set(item.name, isCustom\n ? { ...existing, order: item.order, text: item.text ?? '', source: 'custom' }\n : { ...existing, order: item.order, source: 'system' })\n } else {\n map.set(item.name, {\n name: item.name,\n order: item.order,\n text: item.text ?? '',\n active: !blockedNames.has(item.name),\n replaced: false,\n source: isCustom ? 'custom' : 'system',\n })\n }\n }\n return [...map.values()].sort((a, b) => a.order - b.order)\n}\n\n/**\n * Resolve a preset's relative order into an absolute ordered list (0..n-1).\n * Sections with no anchor (or whose anchor is absent) come first in preset\n * order; each anchored section is inserted right after its anchor; any\n * remaining sections (cycles) are appended.\n */\nexport function resolveOrder(presetOrder: PresetData['order']): Array<{ name: string; order: number; text: string; custom?: boolean }> {\n const list = presetOrder ?? []\n const afterMap = new Map<string, string | undefined>()\n const textMap = new Map<string, string>()\n const customMap = new Map<string, boolean>()\n for (const sec of list) {\n afterMap.set(sec.name, sec.after)\n textMap.set(sec.name, sec.text)\n customMap.set(sec.name, sec.custom === true)\n }\n\n const result: string[] = []\n const placed = new Set<string>()\n\n for (const sec of list) {\n const anchor = afterMap.get(sec.name)\n if (!anchor || !afterMap.has(anchor)) { result.push(sec.name); placed.add(sec.name) }\n }\n\n let changed = true\n while (changed) {\n changed = false\n for (const sec of list) {\n if (placed.has(sec.name)) continue\n const anchor = afterMap.get(sec.name)\n if (anchor && placed.has(anchor)) {\n result.splice(result.indexOf(anchor) + 1, 0, sec.name)\n placed.add(sec.name)\n changed = true\n }\n }\n }\n\n for (const sec of list) {\n if (!placed.has(sec.name)) { result.push(sec.name); placed.add(sec.name) }\n }\n\n return result.map((name, i) => ({ name, order: i, text: textMap.get(name) ?? '', custom: customMap.get(name) }))\n}\n\n/**\n * Build a preset snapshot from the current config. The order list is derived\n * from the MERGED section list (not just `cfg.inject`) so that a preset saved\n * after only blocking sections (without reordering) still carries the full\n * ordered set, and thus a meaningful \"active list\" when applied.\n */\nexport function buildPresetData(cfg: Config, merged: Section[]): PresetData {\n // Only custom (plugin-added) sections carry their own text into the preset's\n // order list. System sections keep an empty text so applying the preset only\n // reorders them and never freezes their dynamically generated content.\n const order = merged.map((sec, i) => ({\n name: sec.name,\n after: i > 0 ? merged[i - 1].name : undefined,\n text: sec.source === 'custom' ? (sec.text ?? '') : '',\n custom: sec.source === 'custom',\n }))\n return {\n sections: cfg.sections,\n replace: cfg.replace,\n order,\n tools: cfg.tools,\n }\n}\n\n/**\n * Compute the config patch when applying a preset:\n * - same-name sections are overridden (the order list drives this at runtime)\n * - preset sections missing from the current prompt are added\n * - current sections NOT in the preset's ordered list are disabled by default\n * - only the preset's ACTIVE sections (in the order list but not in its block\n * list) are unblocked; the preset's own blocked sections stay blocked.\n *\n * Custom injected sections that exist in the current config but are NOT in the\n * preset's ordered list are preserved in the resulting inject list (so they\n * stay visible) and disabled (added to the blocked set), rather than silently\n * dropped — a preset must not make the user's own injected sections vanish.\n */\nexport function applyPresetData(data: PresetData, cfg: Config, currentNames: ReadonlySet<string>): ConfigPatch {\n const presetOrder = data.order ?? []\n const presetNames = new Set(presetOrder.map((x) => x.name))\n const blocked = new Set(data.sections ?? [])\n\n // Inject list = the preset's resolved order, then any custom injected\n // sections present in the current config but absent from the preset list.\n // Keeping them in `inject` makes them visible; they are disabled below.\n // Kept customs continue after the preset's own indexes; if the preset covers\n // only a small subset they may tie with the inventory's native orders — the\n // merge view sorts stably (inventory first), so ordering stays deterministic,\n // and the next reorder/persist re-indexes everything contiguously anyway.\n const inject = resolveOrder(presetOrder)\n const kept = new Set(inject.map((x) => x.name))\n let order = inject.length\n for (const item of cfg.inject ?? []) {\n if (!item || !item.name || presetNames.has(item.name) || kept.has(item.name)) continue\n kept.add(item.name)\n inject.push({ name: item.name, order: order++, text: item.text ?? '', custom: item.custom === true })\n }\n\n // Only enforce the \"active set\" when the preset actually defines an order.\n // An empty order (e.g. a hand-authored / imported preset that only blocks a\n // few sections) must not default-disable every current section.\n if (presetOrder.length > 0) {\n const activeNames = new Set([...presetNames].filter((n) => !blocked.has(n)))\n for (const name of currentNames) if (!presetNames.has(name)) blocked.add(name)\n for (const name of activeNames) blocked.delete(name)\n }\n\n return {\n sections: [...blocked],\n replace: { ...(cfg.replace ?? {}), ...(data.replace ?? {}) },\n inject,\n tools: { exclude: data.tools?.exclude ?? [], include: data.tools?.include ?? [] },\n }\n}\n\n/**\n * Remove a custom (plugin-added) section from the config: it disappears from\n * the inject list, is no longer forced into the blocked set, and any replace\n * text for it is cleared. The remaining inject entries are re-indexed to a\n * contiguous 0..n-1 order (the virtual index model), so removal never leaves\n * holes. System sections read from the host inventory cannot be removed this\n * way (they would just come back on the next inventory read).\n */\nexport function removeSection(name: string, cfg: Config): Pick<Config, 'sections' | 'inject' | 'replace'> {\n const sections = (cfg.sections ?? []).filter((n) => n !== name)\n const inject = (cfg.inject ?? [])\n .filter((item) => item.name !== name)\n .map((item, i) => ({ ...item, order: i }))\n const replace = { ...(cfg.replace ?? {}) }\n delete replace[name]\n return { sections, inject, replace }\n}\n\n// ── Tool filtering ──────────────────────────────────────────────────────────\n\nexport type ToolsCfg = { exclude?: string[]; include?: string[] }\n\n/** Whether a tool is hidden under the current include/exclude config. */\nexport function isToolHidden(name: string, toolsCfg: ToolsCfg | undefined): boolean {\n const include = toolsCfg?.include ?? []\n const exclude = toolsCfg?.exclude ?? []\n return include.length > 0 ? !include.includes(name) : exclude.includes(name)\n}\n\n/** Toggle a tool's hidden state, returning a new tools config. */\nexport function toggleTool(name: string, currentlyHidden: boolean, toolsCfg: ToolsCfg | undefined): ToolsCfg {\n const include = toolsCfg?.include ?? []\n const exclude = toolsCfg?.exclude ?? []\n if (include.length > 0) {\n const next = include.slice()\n if (currentlyHidden) {\n next.push(name)\n // Re-showing a tool in whitelist mode must also clear any stale blacklist\n // entry, otherwise the name lingers in both lists and reappears as hidden\n // if the user later switches back to blacklist mode.\n const nextExclude = exclude.filter((n) => n !== name)\n return { exclude: nextExclude, include: next }\n }\n const i = next.indexOf(name)\n if (i >= 0) next.splice(i, 1)\n return { exclude, include: next }\n }\n const next = exclude.slice()\n if (currentlyHidden) { const i = next.indexOf(name); if (i >= 0) next.splice(i, 1) }\n else next.push(name)\n return { exclude: next, include }\n}\n\n/**\n * Switch between include (whitelist) and exclude (blacklist) modes. Turning\n * include mode on discards names unknown to the current tool set and seeds the\n * include list from the currently non-excluded tools; turning it off clears the\n * include list (keep only known exclude names).\n */\nexport function setToolMode(on: boolean, toolsCfg: ToolsCfg | undefined, toolNames: string[]): ToolsCfg {\n const known = new Set(toolNames)\n const exclude = (toolsCfg?.exclude ?? []).filter((n) => known.has(n))\n if (on) return { exclude, include: toolNames.filter((n) => !exclude.includes(n)) }\n return { exclude, include: [] }\n}\n\n// ── Preset list operations ──────────────────────────────────────────────────\n\n/** Serialize a preset for export (JSON-safe full snapshot). */\nexport function serializePreset(preset: Preset): { name: string; data: PresetData } {\n return { name: preset.name, data: preset.data }\n}\n\n/**\n * Import preset(s): same-name presets are skipped, only distinct names are\n * added. Returns a new presets list (or the original if nothing changed).\n */\nexport function addImportedPresets(existing: Preset[], parsed: unknown, makeId: () => string): Preset[] {\n const incoming = Array.isArray(parsed) ? parsed : [parsed]\n const existingNames = new Set(existing.map((p) => p.name))\n const added = incoming\n .filter((p) => p && typeof (p as { name?: unknown }).name === 'string' && !existingNames.has((p as Preset).name))\n .map((p) => ({ id: makeId(), name: (p as Preset).name, data: ((p as Preset).data ?? {}) as PresetData }))\n return added.length > 0 ? [...existing, ...added] : existing\n}\n\n/** Delete a preset, clearing the active id if it pointed at the removed one. */\nexport function removePreset(presets: Preset[], id: string, activeId?: string): { presets: Preset[]; activeId?: string } {\n return {\n presets: presets.filter((p) => p.id !== id),\n activeId: activeId === id ? undefined : activeId,\n }\n}\n","/** Prompt-sections tab: block / replace / inject / reorder prompt sections. */\nimport { createElement as h, useState, type ReactElement, type DragEvent, type ChangeEvent } from 'react'\nimport type { Config, Inventory, SettingsScope } from './types.ts'\nimport type { Translate } from './locales.ts'\nimport { mergeSections, removeSection, type Section } from './presets.ts'\nimport { s } from './styles.ts'\n\nexport function SectionsTab({ cfg, inv, scope, t }: { cfg: Config; inv: Inventory | null; scope: SettingsScope; t: Translate }): ReactElement {\n const replace = cfg.replace ?? {}\n const blockedNames = new Set(cfg.sections ?? [])\n const [editing, setEditing] = useState<string | null>(null)\n const [draft, setDraft] = useState('')\n const [dragName, setDragName] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<{ name: string; pos: 'above' | 'below' } | null>(null)\n\n // Merge inventory sections with user-injected sections, sorted by order.\n // Injected sections that don't exist in the original prompt appear here too,\n // positioned by their order value.\n const merged: Section[] = mergeSections(inv, cfg, blockedNames)\n\n const toggleBlock = (name: string, currentlyBlocked: boolean): void => {\n const list = (cfg.sections ?? []).slice()\n if (currentlyBlocked) { const i = list.indexOf(name); if (i >= 0) list.splice(i, 1) }\n else list.push(name)\n scope.set('sections', list)\n }\n const startReplace = (name: string, original: string): void => {\n // Echo the ORIGINAL prompt text so the user edits from the current value.\n setEditing(name)\n setDraft(replace[name] ?? original)\n }\n const commitReplace = (name: string): void => {\n const next = { ...replace }\n if (draft.trim() === '') delete next[name]\n else next[name] = draft\n scope.set('replace', next)\n setEditing(null)\n }\n const clearReplace = (name: string): void => {\n const next = { ...replace }\n delete next[name]\n scope.set('replace', next)\n }\n\n // Persist the full ordered list. We treat the sorted list as an array and\n // re-index every section with a sequential integer order (0, 1, 2, …), so\n // there are never duplicate or fractional orders. System sections keep empty\n // text (so we never freeze their dynamically generated content); custom\n // (plugin-generated) sections keep their own text and the hidden `custom`\n // marker, so they render real content and stay identifiable/deletable.\n const persistOrder = (ordered: Section[]): void => {\n const list = ordered.map((sec, i) => {\n const existing = (cfg.inject ?? []).find((x) => x.name === sec.name)\n const isCustom = sec.source === 'custom'\n return { name: sec.name, order: i, text: isCustom ? (sec.text ?? '') : (existing?.text ?? ''), custom: isCustom }\n })\n scope.set('inject', list)\n }\n\n // Delete a custom (plugin-added) section: remove it from inject / sections /\n // replace so it no longer appears in the panel at all.\n const removeCustom = (name: string): void => {\n const patch = removeSection(name, cfg)\n scope.set('sections', patch.sections)\n scope.set('inject', patch.inject)\n scope.set('replace', patch.replace)\n }\n\n // Move a section up/down one slot (array-index swap), then re-index.\n const moveOrder = (index: number, dir: -1 | 1): void => {\n const target = index + dir\n if (target < 0 || target >= merged.length) return\n const next = merged.slice()\n const [item] = next.splice(index, 1)\n next.splice(target, 0, item)\n persistOrder(next)\n }\n\n const onDragStart = (e: DragEvent, name: string): void => {\n setDragName(name)\n e.dataTransfer.effectAllowed = 'move'\n try { e.dataTransfer.setData('text/plain', name) } catch { /* ignore */ }\n }\n const onDragOver = (e: DragEvent, name: string): void => {\n if (!dragName || dragName === name) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n const rect = e.currentTarget.getBoundingClientRect()\n const pos = e.clientY < rect.top + rect.height / 2 ? 'above' : 'below'\n setDropTarget({ name, pos })\n }\n const onDrop = (e: DragEvent, target: Section): void => {\n e.preventDefault()\n if (!dragName || dragName === target.name) { setDragName(null); setDropTarget(null); return }\n const dragged = merged.find((x) => x.name === dragName)\n if (!dragged) { setDragName(null); setDropTarget(null); return }\n const next = merged.filter((x) => x.name !== dragName)\n const idx = next.findIndex((x) => x.name === target.name)\n const pos = dropTarget?.name === target.name ? dropTarget.pos : 'below'\n next.splice(pos === 'above' ? idx : idx + 1, 0, dragged)\n persistOrder(next)\n setDragName(null)\n setDropTarget(null)\n }\n const onDragEnd = (): void => { setDragName(null); setDropTarget(null) }\n\n // Add a new injected section, placed by its order hint, then re-index. The\n // section is marked `custom` (the hidden marker) so it is identified as\n // plugin-generated and thus deletable, and its own text is preserved.\n const addSection = (name: string, order: number, text: string): void => {\n const next = merged.slice()\n const entry: Section = { name, order, text, active: true, replaced: false, source: 'custom' }\n const existing = next.findIndex((x) => x.name === name)\n if (existing >= 0) next[existing] = entry\n else {\n const idx = next.findIndex((x) => x.order > order)\n if (idx < 0) next.push(entry)\n else next.splice(idx, 0, entry)\n }\n persistOrder(next)\n }\n\n return h('div', { style: s.list }, [\n merged.length === 0 ? h('div', { style: s.muted }, t('empty')) : null,\n merged.map((sec, index) => {\n const blocked = blockedNames.has(sec.name)\n const isEditing = editing === sec.name\n const isDragging = dragName === sec.name\n const isDropTarget = dropTarget?.name === sec.name\n const rowStyle = {\n ...s.row,\n ...(isDragging ? s.rowDragging : {}),\n ...(isDropTarget && dropTarget.pos === 'above' ? s.rowDropAbove : {}),\n ...(isDropTarget && dropTarget.pos === 'below' ? s.rowDropBelow : {}),\n }\n return h('div', {\n key: sec.name,\n style: rowStyle,\n draggable: true,\n onDragStart: (e: DragEvent) => onDragStart(e, sec.name),\n onDragOver: (e: DragEvent) => onDragOver(e, sec.name),\n onDrop: (e: DragEvent) => onDrop(e, sec),\n onDragEnd,\n }, [\n h('span', { style: s.dragHandle, title: t('drag') }, '⠿'),\n h('label', { style: s.switchWrap }, [\n h('input', { type: 'checkbox', checked: blocked, onChange: () => toggleBlock(sec.name, blocked) }),\n h('span', { style: blocked ? s.badgeBlocked : s.badgeOk }, blocked ? t('blockedOn') : t('blockedOff')),\n ]),\n h('div', { style: s.rowBody }, [\n h('div', { style: s.rowTitle }, [\n h('span', { style: s.code }, sec.name),\n h('span', { style: s.orderTag }, '#' + index),\n h('span', { style: sec.source === 'custom' ? s.badgeCustom : s.badgeSystem }, sec.source === 'custom' ? t('manual') : t('system')),\n sec.replaced ? h('span', { style: s.badgeReplaced }, t('replaced')) : null,\n ]),\n isEditing\n ? h('div', { style: s.editBox }, [\n h('textarea', { style: s.editInput, value: draft, onChange: (e: ChangeEvent<HTMLTextAreaElement>) => setDraft(e.target.value), rows: 3 }),\n h('div', { style: s.injectRow }, [\n h('button', { style: s.mini, onClick: () => commitReplace(sec.name) }, t('add')),\n h('button', { style: s.mini, onClick: () => setEditing(null) }, t('clearReplace')),\n ]),\n ])\n : h('div', { style: s.preview }, String(sec.text ?? '').slice(0, 140) || (sec.source === 'custom' ? t('empty') : t('dynamic'))),\n ]),\n h('div', { style: s.arrowCol }, [\n h('button', { style: s.arrow, disabled: index === 0, onClick: () => moveOrder(index, -1), title: t('moveUp') }, '↑'),\n h('button', { style: s.arrow, disabled: index === merged.length - 1, onClick: () => moveOrder(index, 1), title: t('moveDown') }, '↓'),\n ]),\n h('button', { style: s.mini, onClick: () => replace[sec.name] ? clearReplace(sec.name) : startReplace(sec.name, String(sec.text ?? '')) }, replace[sec.name] ? t('clearReplace') : t('replace')),\n sec.source === 'custom' ? h('button', { style: s.mini, onClick: () => removeCustom(sec.name), title: t('delete') }, t('delete')) : null,\n ])\n }),\n h('div', { style: s.injectBox }, [\n h('div', { style: s.rowTitle }, t('injectNew')),\n h(InjectForm, { onAdd: addSection, t }),\n ]),\n ])\n}\n\nfunction InjectForm({ onAdd, t }: { onAdd: (name: string, order: number, text: string) => void; t: Translate }): ReactElement {\n const [name, setName] = useState('')\n const [order, setOrder] = useState('120')\n const [text, setText] = useState('')\n\n const submit = (): void => {\n if (!name.trim()) return\n onAdd(name.trim(), Number(order) || 120, text)\n setName(''); setText(''); setOrder('120')\n }\n\n return h('div', {}, [\n h('div', { style: s.injectRow }, [\n h('input', { style: { ...s.input, width: '22%' }, placeholder: t('name'), value: name, onChange: (e) => setName(e.target.value) }),\n h('input', { style: { ...s.input, width: '12%' }, type: 'number', placeholder: t('order'), value: order, onChange: (e) => setOrder(e.target.value) }),\n h('input', { style: { ...s.input, flex: 1 }, placeholder: t('text'), value: text, onChange: (e) => setText(e.target.value) }),\n h('button', { style: s.mini, onClick: submit }, t('add')),\n ]),\n ])\n}\n","/** Tools tab: hide tools from the model catalog by exclude/include. */\nimport { createElement as h, type ReactElement } from 'react'\nimport type { Config, Inventory, SettingsScope } from './types.ts'\nimport type { Translate } from './locales.ts'\nimport { isToolHidden, setToolMode, toggleTool } from './presets.ts'\nimport { s } from './styles.ts'\n\nexport function ToolsTab({ cfg, inv, scope, t }: { cfg: Config; inv: Inventory | null; scope: SettingsScope; t: Translate }): ReactElement {\n const tools = inv?.tools ?? []\n const toolsCfg = cfg.tools ?? { exclude: [], include: [] }\n const includeMode = (toolsCfg.include ?? []).length > 0\n\n const toggle = (name: string, currentlyHidden: boolean): void => {\n scope.set('tools', toggleTool(name, currentlyHidden, toolsCfg))\n }\n const setIncludeMode = (on: boolean): void => {\n scope.set('tools', setToolMode(on, toolsCfg, tools.map((tool) => tool.name)))\n }\n\n return h('div', {}, [\n h('div', { style: s.bar }, [\n h('button', { style: includeMode ? s.tabActive : s.tab, onClick: () => setIncludeMode(true) }, t('includeMode')),\n h('button', { style: includeMode ? s.tab : s.tabActive, onClick: () => setIncludeMode(false) }, t('excludeMode')),\n ]),\n h('div', { style: s.list }, [\n tools.length === 0 ? h('div', { style: s.muted }, t('empty')) : null,\n tools.map((tool) => {\n // Hidden state comes from the CONFIG (exclude/include lists), not the\n // inventory snapshot, so toggling updates the checkbox immediately.\n const hidden = isToolHidden(tool.name, toolsCfg)\n return h('div', { key: tool.name, style: s.row }, [\n h('label', { style: s.switchWrap }, [\n h('input', { type: 'checkbox', checked: hidden, onChange: () => toggle(tool.name, hidden) }),\n h('span', { style: hidden ? s.badgeBlocked : s.badgeOk }, hidden ? t('hiddenOn') : t('hiddenOff')),\n ]),\n h('div', { style: s.rowBody }, [\n h('div', { style: s.rowTitle }, h('span', { style: s.code }, tool.name)),\n h('div', { style: s.preview }, String(tool.description ?? '').slice(0, 140)),\n ]),\n ])\n }),\n ]),\n ])\n}\n","/** Presets tab: save / apply / export / import complete customization snapshots. */\nimport { createElement as h, useRef, useState, type ReactElement, type ChangeEvent } from 'react'\nimport type { Config, Inventory, Preset, PresetData, SettingsScope } from './types.ts'\nimport type { Translate } from './locales.ts'\nimport { addImportedPresets, applyPresetData, buildPresetData, mergeSections, removePreset, serializePreset } from './presets.ts'\nimport { s } from './styles.ts'\n\nexport function PresetsTab({ cfg, inv, scope, t }: { cfg: Config; inv: Inventory | null; scope: SettingsScope; t: Translate }): ReactElement {\n const presets = cfg.presets ?? []\n const [name, setName] = useState('')\n const fileRef = useRef<HTMLInputElement | null>(null)\n\n const blockedNames = new Set(cfg.sections ?? [])\n const merged = mergeSections(inv, cfg, blockedNames)\n const currentNames = new Set(merged.map((sec) => sec.name))\n\n // Capture the current customization as a new preset (full snapshot). The\n // absolute order is converted to a relative form (each section records the\n // section it should follow) so the preset stays portable across prompts.\n const saveCurrent = (): void => {\n const presetName = name.trim() || `${t('preset')} ${presets.length + 1}`\n const data = buildPresetData(cfg, merged)\n scope.set('presets', [...presets, { id: genId(), name: presetName, data }])\n setName('')\n }\n\n // Apply a preset. The patch is computed by the pure helper:\n // - same-name sections are overridden (content + order)\n // - preset sections missing from the current prompt are added\n // - current sections NOT in the preset list are disabled (blocked)\n // - only the preset's ACTIVE sections are unblocked (its own blocked list\n // is preserved)\n const applyPreset = (preset: Preset): void => {\n const patch = applyPresetData(preset.data, cfg, currentNames)\n scope.set('inject', patch.inject)\n scope.set('replace', patch.replace)\n scope.set('sections', patch.sections)\n scope.set('tools', patch.tools)\n scope.set('activePreset', preset.id)\n }\n\n const deletePreset = (id: string): void => {\n const next = removePreset(presets, id, cfg.activePreset)\n scope.set('presets', next.presets)\n if (next.activeId === undefined && cfg.activePreset === id) scope.unset('activePreset')\n }\n\n // Serialize a preset to a downloadable JSON file.\n const exportPreset = (preset: Preset): void => {\n const blob = new Blob([JSON.stringify(serializePreset(preset), null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${preset.name}.json`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n // Import preset(s) from a JSON file. Same-name presets are skipped; only\n // presets with new names are added to the local list.\n const onImportFile = (e: ChangeEvent<HTMLInputElement>): void => {\n const file = e.target.files?.[0]\n if (!file) return\n const reader = new FileReader()\n reader.onload = () => {\n try {\n const parsed = JSON.parse(String(reader.result))\n scope.set('presets', addImportedPresets(presets, parsed, genId))\n } catch { /* ignore invalid json */ }\n }\n reader.readAsText(file)\n e.target.value = ''\n }\n\n return h('div', { style: s.list }, [\n h('div', { style: s.injectBox }, [\n h('div', { style: s.rowTitle }, t('savePreset')),\n h('div', { style: s.injectRow }, [\n h('input', { style: { ...s.input, flex: 1 }, placeholder: t('presetName'), value: name, onChange: (e: ChangeEvent<HTMLInputElement>) => setName(e.target.value) }),\n h('button', { style: s.mini, onClick: saveCurrent }, t('save')),\n ]),\n ]),\n h('div', { style: s.injectBox }, [\n h('div', { style: s.rowTitle }, t('importPreset')),\n h('div', { style: s.injectRow }, [\n h('button', { style: s.mini, onClick: () => fileRef.current?.click() }, t('import')),\n h('input', { ref: fileRef, type: 'file', accept: '.json,application/json', style: { display: 'none' }, onChange: onImportFile }),\n ]),\n ]),\n presets.length === 0 ? h('div', { style: s.muted }, t('empty')) : null,\n presets.map((preset) => {\n const active = cfg.activePreset === preset.id\n return h('div', { key: preset.id, style: s.row }, [\n h('div', { style: s.rowBody }, [\n h('div', { style: s.rowTitle }, [\n h('span', { style: s.code }, preset.name),\n active ? h('span', { style: s.badgeOk }, t('active')) : null,\n ]),\n ]),\n h('button', { style: s.mini, onClick: () => applyPreset(preset) }, t('apply')),\n h('button', { style: s.mini, onClick: () => exportPreset(preset) }, t('export')),\n h('button', { style: s.mini, onClick: () => deletePreset(preset.id) }, t('delete')),\n ])\n }),\n ])\n}\n\nfunction genId(): string {\n return 'p_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7)\n}\n","/**\n * dsh-prompt-customizer — browser half (TypeScript source).\n *\n * Registers a \"提示词定制\" settings section (sidebar entry) and a plugin\n * settings card. The panel fetches the effective section / tool inventory\n * from the host `/api/prompt-customizer/inventory` and lets the user block,\n * replace, inject prompt sections and hide tools. All writes go through the\n * bound settings scope (`prompt-customizer` namespace) and apply live.\n *\n * Built by tsdown into the __ModuleLoader__ factory bundle at client/client.js;\n * the only external is the loader module table's react entry.\n */\nimport { createElement as h, useEffect, useState, type ReactElement } from 'react'\nimport { DICT, type Translate } from './locales.ts'\nimport { s } from './styles.ts'\nimport type { Config, Inventory, SettingsScope } from './types.ts'\nimport { SectionsTab } from './SectionsTab.tsx'\nimport { ToolsTab } from './ToolsTab.tsx'\nimport { PresetsTab } from './PresetsTab.tsx'\n\nconst NS = 'prompt-customizer'\nconst INVENTORY_URL = '/api/prompt-customizer/inventory'\n\nexport const name = 'prompt-customizer'\nexport const inject = ['slots', 'locale']\n\n/** The subset of the client cordis context this plugin touches. */\ninterface ClientContext {\n effect(callback: () => unknown, label?: string): void\n locale: {\n register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string> }): unknown\n bind(namespace: string): Translate\n }\n inject(services: string[], callback: (scoped: SettingsScopeHost) => void): void\n}\n\n/** The host surface the settings card needs (settingsScope transport). */\ninterface SettingsScopeHost {\n settingsScope: {\n bind(options: { namespace: string }): SettingsScope\n }\n slots: {\n inject(name: string, register: () => unknown): void\n register(meta: Record<string, unknown>, render: () => unknown): unknown\n }\n}\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, DICT), 'prompt-customizer: locale')\n const t = ctx.locale.bind(NS)\n\n // Register a standalone settings section (sidebar menu entry) so the panel\n // only appears under \"提示词定制\", not as a card inside the \"插件\" settings\n // list. Goes through a NESTED inject of settingsScope so the panel can\n // read/write the namespace config; on hosts without the settings transport\n // it stays hidden instead of unmounting the whole plugin.\n ctx.inject(['settingsScope'], (scoped) => {\n const scope = scoped.settingsScope.bind({ namespace: NS })\n\n scoped.slots.inject('settings.section', () => scoped.slots.register({\n name: 'settings.section',\n id: 'prompt-customizer',\n order: 50,\n label: () => t('nav'),\n locale: NS,\n inject: () => ({ t }),\n }, () => h(Panel, { scope, t })))\n })\n}\n\n// ── Root panel ──────────────────────────────────────────────────────────────\n\nfunction Panel({ scope, t }: { scope: SettingsScope; t: Translate }): ReactElement {\n const [snap, setSnap] = useState(() => scope.getSnapshot())\n const [inv, setInv] = useState<Inventory | null>(null)\n const [tab, setTab] = useState<'sections' | 'tools' | 'presets'>('sections')\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => scope.subscribe(() => setSnap(scope.getSnapshot())), [scope])\n\n const refresh = (): void => {\n fetch(INVENTORY_URL)\n .then((r) => r.json())\n .then((data: Inventory) => { setInv(data); setError(null) })\n .catch((e: unknown) => setError(String(e instanceof Error ? e.message : e)))\n }\n useEffect(refresh, [])\n\n if (snap.status !== 'ready' && snap.value === undefined) {\n return h('div', { style: s.muted }, t('loading'))\n }\n\n const cfg: Config = snap.value && typeof snap.value === 'object'\n ? snap.value as Config\n : { sections: [], replace: {}, inject: [], tools: { exclude: [], include: [] } }\n\n return h('div', { style: s.root }, [\n h('div', { style: s.bar }, [\n h('button', { style: tab === 'sections' ? s.tabActive : s.tab, onClick: () => setTab('sections') }, t('tabsSections')),\n h('button', { style: tab === 'tools' ? s.tabActive : s.tab, onClick: () => setTab('tools') }, t('tabsTools')),\n h('button', { style: tab === 'presets' ? s.tabActive : s.tab, onClick: () => setTab('presets') }, t('tabsPresets')),\n h('button', { style: s.refresh, onClick: refresh }, t('refresh')),\n ]),\n error ? h('div', { style: s.error }, String(error)) : null,\n tab === 'sections'\n ? h(SectionsTab, { cfg, inv, scope, t })\n : tab === 'tools'\n ? h(ToolsTab, { cfg, inv, scope, t })\n : h(PresetsTab, { cfg, inv, scope, t }),\n ])\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-prompt-customizer",
|
|
3
3
|
"description": "System-prompt & tool customizer for DeepSeek Harness with a settings-panel UI: block / replace / inject prompt sections by name, and hide tools from the model catalog by exclude/include. Config lives in the dsh settings document (namespace prompt-customizer).",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"main": "lib/index.js",
|
package/src/client/presets.ts
CHANGED
|
@@ -143,6 +143,10 @@ export function applyPresetData(data: PresetData, cfg: Config, currentNames: Rea
|
|
|
143
143
|
// Inject list = the preset's resolved order, then any custom injected
|
|
144
144
|
// sections present in the current config but absent from the preset list.
|
|
145
145
|
// Keeping them in `inject` makes them visible; they are disabled below.
|
|
146
|
+
// Kept customs continue after the preset's own indexes; if the preset covers
|
|
147
|
+
// only a small subset they may tie with the inventory's native orders — the
|
|
148
|
+
// merge view sorts stably (inventory first), so ordering stays deterministic,
|
|
149
|
+
// and the next reorder/persist re-indexes everything contiguously anyway.
|
|
146
150
|
const inject = resolveOrder(presetOrder)
|
|
147
151
|
const kept = new Set(inject.map((x) => x.name))
|
|
148
152
|
let order = inject.length
|
|
@@ -172,12 +176,16 @@ export function applyPresetData(data: PresetData, cfg: Config, currentNames: Rea
|
|
|
172
176
|
/**
|
|
173
177
|
* Remove a custom (plugin-added) section from the config: it disappears from
|
|
174
178
|
* the inject list, is no longer forced into the blocked set, and any replace
|
|
175
|
-
* text for it is cleared.
|
|
176
|
-
*
|
|
179
|
+
* text for it is cleared. The remaining inject entries are re-indexed to a
|
|
180
|
+
* contiguous 0..n-1 order (the virtual index model), so removal never leaves
|
|
181
|
+
* holes. System sections read from the host inventory cannot be removed this
|
|
182
|
+
* way (they would just come back on the next inventory read).
|
|
177
183
|
*/
|
|
178
184
|
export function removeSection(name: string, cfg: Config): Pick<Config, 'sections' | 'inject' | 'replace'> {
|
|
179
185
|
const sections = (cfg.sections ?? []).filter((n) => n !== name)
|
|
180
|
-
const inject = (cfg.inject ?? [])
|
|
186
|
+
const inject = (cfg.inject ?? [])
|
|
187
|
+
.filter((item) => item.name !== name)
|
|
188
|
+
.map((item, i) => ({ ...item, order: i }))
|
|
181
189
|
const replace = { ...(cfg.replace ?? {}) }
|
|
182
190
|
delete replace[name]
|
|
183
191
|
return { sections, inject, replace }
|
|
@@ -200,8 +208,16 @@ export function toggleTool(name: string, currentlyHidden: boolean, toolsCfg: Too
|
|
|
200
208
|
const exclude = toolsCfg?.exclude ?? []
|
|
201
209
|
if (include.length > 0) {
|
|
202
210
|
const next = include.slice()
|
|
203
|
-
if (currentlyHidden)
|
|
204
|
-
|
|
211
|
+
if (currentlyHidden) {
|
|
212
|
+
next.push(name)
|
|
213
|
+
// Re-showing a tool in whitelist mode must also clear any stale blacklist
|
|
214
|
+
// entry, otherwise the name lingers in both lists and reappears as hidden
|
|
215
|
+
// if the user later switches back to blacklist mode.
|
|
216
|
+
const nextExclude = exclude.filter((n) => n !== name)
|
|
217
|
+
return { exclude: nextExclude, include: next }
|
|
218
|
+
}
|
|
219
|
+
const i = next.indexOf(name)
|
|
220
|
+
if (i >= 0) next.splice(i, 1)
|
|
205
221
|
return { exclude, include: next }
|
|
206
222
|
}
|
|
207
223
|
const next = exclude.slice()
|