UNPKG

@gongfu/prompt-editor

Version:

A powerful prompt engineering editor SDK for AI applications

1,203 lines (1,183 loc) 141 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client" // src/components/PromptEditor.tsx var _react = require('react'); var _react3 = require('@monaco-editor/react'); var _react4 = _interopRequireDefault(_react3); var _framermotion = require('framer-motion'); // src/hooks/usePromptEditorStore.ts var _zustand = require('zustand'); var _immer = require('zustand/middleware/immer'); var initialTemplate = { id: "", name: "Untitled Prompt", content: "", variables: [], tags: [] }; var usePromptEditorStore = _zustand.create.call(void 0, )( _immer.immer.call(void 0, (set2, get) => ({ // State template: initialTemplate, isDirty: false, isValid: true, errors: {}, history: [initialTemplate], historyIndex: 0, selectedVariableId: void 0, previewValues: {}, // Actions updateTemplate: (updates) => set2((state) => { Object.assign(state.template, updates); state.isDirty = true; addToHistory(state); }), updateContent: (content) => set2((state) => { state.template.content = content; state.isDirty = true; addToHistory(state); }), addVariable: (variable) => set2((state) => { if (state.template.variables.some((v) => v.name === variable.name)) { state.errors[variable.name] = "Variable name already exists"; return; } state.template.variables.push(variable); state.isDirty = true; state.errors = {}; addToHistory(state); }), updateVariable: (name, updates) => set2((state) => { const index = state.template.variables.findIndex((v) => v.name === name); if (index !== -1) { if (updates.name && updates.name !== name) { const nameExists = state.template.variables.some( (v, i) => i !== index && v.name === updates.name ); if (nameExists) { state.errors[name] = "Variable name already exists"; return; } } Object.assign(state.template.variables[index], updates); state.isDirty = true; state.errors = {}; addToHistory(state); } }), removeVariable: (name) => set2((state) => { state.template.variables = state.template.variables.filter((v) => v.name !== name); delete state.previewValues[name]; state.isDirty = true; addToHistory(state); }), setPreviewValue: (name, value) => set2((state) => { state.previewValues[name] = value; }), undo: () => set2((state) => { if (state.historyIndex > 0) { state.historyIndex--; state.template = JSON.parse(JSON.stringify(state.history[state.historyIndex])); state.isDirty = state.historyIndex !== 0; } }), redo: () => set2((state) => { if (state.historyIndex < state.history.length - 1) { state.historyIndex++; state.template = JSON.parse(JSON.stringify(state.history[state.historyIndex])); state.isDirty = true; } }), reset: () => set2((state) => { state.template = initialTemplate; state.isDirty = false; state.isValid = true; state.errors = {}; state.history = [initialTemplate]; state.historyIndex = 0; state.previewValues = {}; }), loadTemplate: (template) => set2((state) => { state.template = template; state.isDirty = false; state.isValid = true; state.errors = {}; state.history = [template]; state.historyIndex = 0; state.previewValues = {}; template.variables.forEach((variable) => { if (variable.defaultValue !== void 0) { state.previewValues[variable.name] = variable.defaultValue; } }); }), save: async () => { const state = get(); if (state.isValid) { set2((state2) => { state2.isDirty = false; state2.template.updatedAt = /* @__PURE__ */ new Date(); }); } }, validate: () => { const state = get(); const errors = {}; let isValid = true; if (!state.template.name || state.template.name.trim() === "") { errors.name = "Template name is required"; isValid = false; } const variableNames = /* @__PURE__ */ new Set(); state.template.variables.forEach((variable, index) => { if (!variable.name || variable.name.trim() === "") { errors[`variable_${index}`] = "Variable name is required"; isValid = false; } else if (variableNames.has(variable.name)) { errors[`variable_${index}`] = "Duplicate variable name"; isValid = false; } else { variableNames.add(variable.name); } if (_optionalChain([variable, 'access', _ => _.validation, 'optionalAccess', _2 => _2.pattern])) { try { new RegExp(variable.validation.pattern); } catch (e2) { errors[`variable_${index}_pattern`] = "Invalid regular expression"; isValid = false; } } }); set2((state2) => { state2.errors = errors; state2.isValid = isValid; }); return isValid; } })) ); function addToHistory(state) { if (state.historyIndex < state.history.length - 1) { state.history = state.history.slice(0, state.historyIndex + 1); } const newHistory = JSON.parse(JSON.stringify(state.template)); state.history.push(newHistory); state.historyIndex = state.history.length - 1; const maxHistory = 50; if (state.history.length > maxHistory) { state.history = state.history.slice(-maxHistory); state.historyIndex = state.history.length - 1; } } // src/components/VariablePanel.tsx // src/components/VariableForm.tsx var _jsxruntime = require('react/jsx-runtime'); var VariableForm = ({ variable, onSubmit, onCancel, customTypes, locale = "en" }) => { const [formData, setFormData] = _react.useState.call(void 0, { name: _optionalChain([variable, 'optionalAccess', _3 => _3.name]) || "", type: _optionalChain([variable, 'optionalAccess', _4 => _4.type]) || "text", description: _optionalChain([variable, 'optionalAccess', _5 => _5.description]) || "", defaultValue: _optionalChain([variable, 'optionalAccess', _6 => _6.defaultValue]) || "", required: _optionalChain([variable, 'optionalAccess', _7 => _7.required]) || false, options: _optionalChain([variable, 'optionalAccess', _8 => _8.options]) || [], validation: _optionalChain([variable, 'optionalAccess', _9 => _9.validation]) || {} }); const [errors, setErrors] = _react.useState.call(void 0, {}); const labels = { en: { name: "Variable Name", type: "Type", description: "Description", defaultValue: "Default Value", required: "Required", save: "Save", cancel: "Cancel", addOption: "Add Option", optionLabel: "Label", optionValue: "Value", validation: "Validation", minValue: "Min Value", maxValue: "Max Value", pattern: "Pattern (RegExp)", errorMessage: "Error Message" }, "zh-CN": { name: "\u53D8\u91CF\u540D\u79F0", type: "\u7C7B\u578B", description: "\u63CF\u8FF0", defaultValue: "\u9ED8\u8BA4\u503C", required: "\u5FC5\u586B", save: "\u4FDD\u5B58", cancel: "\u53D6\u6D88", addOption: "\u6DFB\u52A0\u9009\u9879", optionLabel: "\u6807\u7B7E", optionValue: "\u503C", validation: "\u9A8C\u8BC1\u89C4\u5219", minValue: "\u6700\u5C0F\u503C", maxValue: "\u6700\u5927\u503C", pattern: "\u6B63\u5219\u8868\u8FBE\u5F0F", errorMessage: "\u9519\u8BEF\u63D0\u793A" } }[locale]; const typeOptions = [ { value: "text", label: locale === "zh-CN" ? "\u6587\u672C" : "Text" }, { value: "number", label: locale === "zh-CN" ? "\u6570\u5B57" : "Number" }, { value: "boolean", label: locale === "zh-CN" ? "\u5E03\u5C14\u503C" : "Boolean" }, { value: "select", label: locale === "zh-CN" ? "\u9009\u62E9" : "Select" }, { value: "multiline", label: locale === "zh-CN" ? "\u591A\u884C\u6587\u672C" : "Multiline" }, ..._optionalChain([customTypes, 'optionalAccess', _10 => _10.map, 'call', _11 => _11((t) => ({ value: t.type, label: t.label }))]) || [] ]; const validate = () => { const newErrors = {}; if (!_optionalChain([formData, 'access', _12 => _12.name, 'optionalAccess', _13 => _13.trim, 'call', _14 => _14()])) { newErrors.name = locale === "zh-CN" ? "\u53D8\u91CF\u540D\u4E0D\u80FD\u4E3A\u7A7A" : "Variable name is required"; } else if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(formData.name)) { newErrors.name = locale === "zh-CN" ? "\u53D8\u91CF\u540D\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF\uFF0C\u4E14\u4E0D\u80FD\u4EE5\u6570\u5B57\u5F00\u5934" : "Variable name must contain only letters, numbers, and underscores, and cannot start with a number"; } if (formData.type === "select" && (!formData.options || formData.options.length === 0)) { newErrors.options = locale === "zh-CN" ? "\u9009\u62E9\u7C7B\u578B\u5FC5\u987B\u81F3\u5C11\u6709\u4E00\u4E2A\u9009\u9879" : "Select type must have at least one option"; } if (_optionalChain([formData, 'access', _15 => _15.validation, 'optionalAccess', _16 => _16.pattern])) { try { new RegExp(formData.validation.pattern); } catch (e3) { newErrors.pattern = locale === "zh-CN" ? "\u65E0\u6548\u7684\u6B63\u5219\u8868\u8FBE\u5F0F" : "Invalid regular expression"; } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = (e) => { e.preventDefault(); if (validate()) { onSubmit(formData); } }; const handleAddOption = () => { setFormData({ ...formData, options: [...formData.options || [], { label: "", value: "" }] }); }; const handleUpdateOption = (index, field, value) => { const newOptions = [...formData.options || []]; newOptions[index] = { ...newOptions[index], [field]: value }; setFormData({ ...formData, options: newOptions }); }; const handleRemoveOption = (index) => { const newOptions = [...formData.options || []]; newOptions.splice(index, 1); setFormData({ ...formData, options: newOptions }); }; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "variable-form", onSubmit: handleSubmit, children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-group", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { children: [ labels.name, " *" ] }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", value: formData.name, onChange: (e) => setFormData({ ...formData, name: e.target.value }), className: errors.name ? "error" : "" } ), errors.name && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "error-message", children: errors.name }) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-group", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { children: [ labels.type, " *" ] }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "select", { value: formData.type, onChange: (e) => setFormData({ ...formData, type: e.target.value }), children: typeOptions.map((option) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: option.value, children: option.label }, option.value)) } ) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-group", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: labels.description }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "textarea", { value: formData.description, onChange: (e) => setFormData({ ...formData, description: e.target.value }), rows: 2 } ) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-group", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: labels.defaultValue }), formData.type === "boolean" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "checkbox", checked: formData.defaultValue || false, onChange: (e) => setFormData({ ...formData, defaultValue: e.target.checked }) } ) : formData.type === "multiline" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "textarea", { value: formData.defaultValue, onChange: (e) => setFormData({ ...formData, defaultValue: e.target.value }), rows: 2 } ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: formData.type === "number" ? "number" : "text", value: formData.defaultValue, onChange: (e) => setFormData({ ...formData, defaultValue: e.target.value }) } ) ] }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "form-group", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "checkbox", checked: formData.required, onChange: (e) => setFormData({ ...formData, required: e.target.checked }) } ), labels.required ] }) }), formData.type === "select" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-group", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: "Options" }), _optionalChain([formData, 'access', _17 => _17.options, 'optionalAccess', _18 => _18.map, 'call', _19 => _19((option, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "option-row", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", placeholder: labels.optionLabel, value: option.label, onChange: (e) => handleUpdateOption(index, "label", e.target.value) } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", placeholder: labels.optionValue, value: option.value, onChange: (e) => handleUpdateOption(index, "value", e.target.value) } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: () => handleRemoveOption(index), children: "\xD7" }) ] }, index))]), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", onClick: handleAddOption, className: "add-option-btn", children: [ "+ ", labels.addOption ] }), errors.options && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "error-message", children: errors.options }) ] }), (formData.type === "text" || formData.type === "number") && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "details", { className: "form-group", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "summary", { children: labels.validation }), formData.type === "number" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-row", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: labels.minValue }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "number", value: _optionalChain([formData, 'access', _20 => _20.validation, 'optionalAccess', _21 => _21.min]) || "", onChange: (e) => setFormData({ ...formData, validation: { ...formData.validation, min: e.target.value ? Number(e.target.value) : void 0 } }) } ) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-row", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: labels.maxValue }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "number", value: _optionalChain([formData, 'access', _22 => _22.validation, 'optionalAccess', _23 => _23.max]) || "", onChange: (e) => setFormData({ ...formData, validation: { ...formData.validation, max: e.target.value ? Number(e.target.value) : void 0 } }) } ) ] }) ] }), formData.type === "text" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-row", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: labels.pattern }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", value: _optionalChain([formData, 'access', _24 => _24.validation, 'optionalAccess', _25 => _25.pattern]) || "", onChange: (e) => setFormData({ ...formData, validation: { ...formData.validation, pattern: e.target.value } }), className: errors.pattern ? "error" : "" } ), errors.pattern && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "error-message", children: errors.pattern }) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-row", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { children: labels.errorMessage }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", value: _optionalChain([formData, 'access', _26 => _26.validation, 'optionalAccess', _27 => _27.message]) || "", onChange: (e) => setFormData({ ...formData, validation: { ...formData.validation, message: e.target.value } }) } ) ] }) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "form-actions", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: onCancel, className: "btn-secondary", children: labels.cancel }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", className: "btn-primary", children: labels.save }) ] }) ] }); }; // src/components/VariableList.tsx var VariableList = ({ variables, editingVariable, onEdit, onUpdate, onRemove, customTypes, readOnly = false, locale = "en" }) => { const typeLabels = { text: locale === "zh-CN" ? "\u6587\u672C" : "Text", number: locale === "zh-CN" ? "\u6570\u5B57" : "Number", boolean: locale === "zh-CN" ? "\u5E03\u5C14\u503C" : "Boolean", select: locale === "zh-CN" ? "\u9009\u62E9" : "Select", multiline: locale === "zh-CN" ? "\u591A\u884C\u6587\u672C" : "Multiline" }; return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "variable-list", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.AnimatePresence, { children: variables.map((variable) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.motion.div, { className: "variable-item", initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, layout: true, children: editingVariable === variable.name ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, VariableForm, { variable, onSubmit: (updatedVariable) => { onUpdate(variable.name, updatedVariable); onEdit(null); }, onCancel: () => onEdit(null), customTypes, locale } ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__content", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__header", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__info", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "variable-item__name", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: `{{${variable.name}}}` }) }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "variable-item__type", children: typeLabels[variable.type] || variable.type }), variable.required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "variable-item__required", children: "*" }) ] }), !readOnly && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__actions", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { className: "variable-item__action", onClick: () => onEdit(variable.name), title: locale === "zh-CN" ? "\u7F16\u8F91" : "Edit", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditIcon, {}) } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { className: "variable-item__action variable-item__action--danger", onClick: () => onRemove(variable.name), title: locale === "zh-CN" ? "\u5220\u9664" : "Delete", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DeleteIcon, {}) } ) ] }) ] }), variable.description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "variable-item__description", children: variable.description }), variable.defaultValue !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__default", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: locale === "zh-CN" ? "\u9ED8\u8BA4\u503C\uFF1A" : "Default: " }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: JSON.stringify(variable.defaultValue) }) ] }), variable.type === "select" && variable.options && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__options", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: locale === "zh-CN" ? "\u9009\u9879\uFF1A" : "Options: " }), variable.options.map((opt, idx) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "variable-item__option", children: [ opt.label, " (", opt.value, ")" ] }, idx)) ] }), variable.validation && Object.keys(variable.validation).length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-item__validation", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: locale === "zh-CN" ? "\u9A8C\u8BC1\uFF1A" : "Validation: " }), variable.validation.min !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [ "Min: ", variable.validation.min ] }), variable.validation.max !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [ "Max: ", variable.validation.max ] }), variable.validation.pattern && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [ "Pattern: ", /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: variable.validation.pattern }) ] }) ] }) ] }) }, variable.name )) }) }); }; var EditIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M12.146.854a.5.5 0 01.708 0l2.292 2.292a.5.5 0 010 .708l-9 9a.5.5 0 01-.168.11l-5 2a.5.5 0 01-.65-.65l2-5a.5.5 0 01.11-.168l9-9zM12.5 2L14 3.5 12.5 5 11 3.5 12.5 2zm-10 10L1 14l2-1.5L12.5 3 11 1.5 1.5 11z" }) }); var DeleteIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M5.5 5.5A.5.5 0 016 6v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm2.5 0a.5.5 0 01.5.5v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm3 .5a.5.5 0 00-1 0v6a.5.5 0 001 0V6z" }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M14.5 3a1 1 0 01-1 1H13v9a2 2 0 01-2 2H5a2 2 0 01-2-2V4h-.5a1 1 0 01-1-1V2a1 1 0 011-1H6a1 1 0 011-1h2a1 1 0 011 1h3.5a1 1 0 011 1v1zM4 4h8v9a1 1 0 01-1 1H5a1 1 0 01-1-1V4z" }) ] }); // src/components/VariablePanel.tsx var VariablePanel = ({ variables, customTypes, readOnly = false, locale = "en" }) => { const [isAddingVariable, setIsAddingVariable] = _react.useState.call(void 0, false); const [editingVariable, setEditingVariable] = _react.useState.call(void 0, null); const { addVariable, updateVariable, removeVariable } = usePromptEditorStore(); const handleAddVariable = (variable) => { addVariable(variable); setIsAddingVariable(false); }; const handleUpdateVariable = (name, updates) => { updateVariable(name, updates); setEditingVariable(null); }; const handleRemoveVariable = (name) => { if (window.confirm(locale === "zh-CN" ? "\u786E\u5B9A\u5220\u9664\u8BE5\u53D8\u91CF\u5417\uFF1F" : "Are you sure to delete this variable?")) { removeVariable(name); } }; const labels = { en: { title: "Variables", addVariable: "Add Variable", noVariables: "No variables defined", description: "Define variables to make your prompt dynamic" }, "zh-CN": { title: "\u53D8\u91CF", addVariable: "\u6DFB\u52A0\u53D8\u91CF", noVariables: "\u6682\u65E0\u53D8\u91CF", description: "\u5B9A\u4E49\u53D8\u91CF\u4F7F\u63D0\u793A\u8BCD\u66F4\u52A0\u7075\u6D3B" } }[locale]; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-panel", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-panel__header", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { children: labels.title }), !readOnly && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { className: "variable-panel__add-btn", onClick: () => setIsAddingVariable(true), disabled: isAddingVariable, children: [ "+ ", labels.addVariable ] } ) ] }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "variable-panel__content", children: variables.length === 0 && !isAddingVariable ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "variable-panel__empty", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: labels.noVariables }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "small", { children: labels.description }) ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [ isAddingVariable && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, VariableForm, { onSubmit: handleAddVariable, onCancel: () => setIsAddingVariable(false), customTypes, locale } ) } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, VariableList, { variables, editingVariable, onEdit: setEditingVariable, onUpdate: handleUpdateVariable, onRemove: handleRemoveVariable, customTypes, readOnly, locale } ) ] }) }) ] }); }; // src/components/Toolbar.tsx var Toolbar = ({ config, isDirty, onSave, onExport, onImport, locale = "en" }) => { const { undo, redo, history, historyIndex } = usePromptEditorStore(); const canUndo = historyIndex > 0; const canRedo = historyIndex < history.length - 1; const handleImport = () => { const input = document.createElement("input"); input.type = "file"; input.accept = ".json,.yaml,.yml,.txt"; input.onchange = async (e) => { const file = _optionalChain([e, 'access', _28 => _28.target, 'access', _29 => _29.files, 'optionalAccess', _30 => _30[0]]); if (file && onImport) { await onImport(file); } }; input.click(); }; const handleExport = (format) => { if (onExport) { onExport(format); } }; const labels = { en: { save: "Save", export: "Export", import: "Import", undo: "Undo", redo: "Redo", format: "Format", preview: "Preview", settings: "Settings" }, "zh-CN": { save: "\u4FDD\u5B58", export: "\u5BFC\u51FA", import: "\u5BFC\u5165", undo: "\u64A4\u9500", redo: "\u91CD\u505A", format: "\u683C\u5F0F\u5316", preview: "\u9884\u89C8", settings: "\u8BBE\u7F6E" } }[locale]; const defaultConfig = { showSave: true, showExport: true, showImport: true, showUndo: true, showRedo: true, showFormat: false, showPreview: false, showSettings: false, ...config }; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "prompt-editor__toolbar", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "toolbar__group", children: [ defaultConfig.showSave && onSave && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { className: "toolbar__btn toolbar__btn--primary", onClick: onSave, disabled: !isDirty, title: labels.save, children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SaveIcon, {}), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: labels.save }) ] } ), defaultConfig.showUndo && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { className: "toolbar__btn", onClick: undo, disabled: !canUndo, title: labels.undo, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, UndoIcon, {}) } ), defaultConfig.showRedo && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { className: "toolbar__btn", onClick: redo, disabled: !canRedo, title: labels.redo, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RedoIcon, {}) } ) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "toolbar__group", children: [ defaultConfig.showImport && onImport && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { className: "toolbar__btn", onClick: handleImport, title: labels.import, children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ImportIcon, {}), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: labels.import }) ] } ), defaultConfig.showExport && onExport && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "toolbar__dropdown", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { className: "toolbar__btn", title: labels.export, children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExportIcon, {}), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: labels.export }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChevronDownIcon, {}) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "toolbar__dropdown-menu", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleExport("json"), children: "JSON" }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleExport("yaml"), children: "YAML" }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleExport("markdown"), children: "Markdown" }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleExport("txt"), children: "Text" }) ] }) ] }) ] }), defaultConfig.customActions && defaultConfig.customActions.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "toolbar__group", children: defaultConfig.customActions.map((action) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { className: "toolbar__btn", onClick: action.onClick, disabled: action.disabled, title: action.tooltip, children: [ action.icon, /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: action.label }) ] }, action.id )) }) ] }); }; var SaveIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M13.5 2h-11A1.5 1.5 0 001 3.5v9A1.5 1.5 0 002.5 14h11a1.5 1.5 0 001.5-1.5v-9A1.5 1.5 0 0013.5 2zM12 12H4V6h8v6z" }) }); var UndoIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8 3a5 5 0 00-5 5h2a3 3 0 016 0 3 3 0 01-6 0H3l3-3-3-3v2a5 5 0 105 5V8z" }) }); var RedoIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8 3a5 5 0 015 5h-2a3 3 0 00-6 0 3 3 0 006 0h2l-3-3 3-3v2a5 5 0 11-5 5V8z" }) }); var ImportIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8 10l-4-4h3V2h2v4h3l-4 4zm-6 3v1h12v-1H2z" }) }); var ExportIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8 6l4 4H9v4H7v-4H4l4-4zM2 3v1h12V3H2z" }) }); var ChevronDownIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2 4l4 4 4-4H2z" }) }); // src/components/PreviewPanel.tsx var PreviewPanel = ({ template, locale = "en" }) => { const { previewValues, setPreviewValue } = usePromptEditorStore(); const previewContent = _react.useMemo.call(void 0, () => { let content = template.content; template.variables.forEach((variable) => { const value = _nullishCoalesce(_nullishCoalesce(previewValues[variable.name], () => ( variable.defaultValue)), () => ( "")); const regex = new RegExp(`{{\\s*${variable.name}\\s*}}`, "g"); content = content.replace(regex, String(value)); }); return content; }, [template.content, template.variables, previewValues]); const labels = { en: { title: "Preview", variables: "Variables", output: "Output", noContent: "No content to preview" }, "zh-CN": { title: "\u9884\u89C8", variables: "\u53D8\u91CF\u503C", output: "\u8F93\u51FA\u7ED3\u679C", noContent: "\u6682\u65E0\u5185\u5BB9\u53EF\u9884\u89C8" } }[locale]; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "preview-panel", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "preview-panel__header", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { children: labels.title }) }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "preview-panel__content", children: [ template.variables.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "preview-panel__variables", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { children: labels.variables }), template.variables.map((variable) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "preview-panel__variable", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { children: [ variable.name, variable.required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "required", children: "*" }) ] }), renderVariableInput( variable, previewValues[variable.name], (value) => setPreviewValue(variable.name, value) ), variable.description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "small", { children: variable.description }) ] }, variable.name)) ] }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "preview-panel__output", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { children: labels.output }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "preview-panel__output-content", children: previewContent ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "pre", { children: previewContent }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "preview-panel__empty", children: labels.noContent }) }) ] }) ] }) ] }); }; function renderVariableInput(variable, value, onChange) { switch (variable.type) { case "text": return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", value: value || "", onChange: (e) => onChange(e.target.value), placeholder: variable.defaultValue } ); case "number": return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "number", value: value || "", onChange: (e) => onChange(e.target.value ? Number(e.target.value) : ""), min: _optionalChain([variable, 'access', _31 => _31.validation, 'optionalAccess', _32 => _32.min]), max: _optionalChain([variable, 'access', _33 => _33.validation, 'optionalAccess', _34 => _34.max]), placeholder: variable.defaultValue } ); case "boolean": return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "checkbox", checked: _nullishCoalesce(_nullishCoalesce(value, () => ( variable.defaultValue)), () => ( false)), onChange: (e) => onChange(e.target.checked) } ); case "select": return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "select", { value: value || "", onChange: (e) => onChange(e.target.value), children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: "", children: "-- Select --" }), _optionalChain([variable, 'access', _35 => _35.options, 'optionalAccess', _36 => _36.map, 'call', _37 => _37((option) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: option.value, children: option.label }, option.value))]) ] } ); case "multiline": return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "textarea", { value: value || "", onChange: (e) => onChange(e.target.value), placeholder: variable.defaultValue, rows: 3 } ); default: return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { type: "text", value: value || "", onChange: (e) => onChange(e.target.value), placeholder: variable.defaultValue } ); } } // src/components/PromptEditor.tsx var PromptEditor = ({ initialTemplate: initialTemplate2, mode = "light", readOnly = false, showLineNumbers = true, showVariablePanel = true, showPreview = true, height = "600px", width = "100%", theme, locale = "en", onSave, onExport, onImport, customVariableTypes, toolbar, className, style }) => { const { template, isDirty, updateContent, loadTemplate, save } = usePromptEditorStore(); _react.useEffect.call(void 0, () => { if (initialTemplate2) { loadTemplate(initialTemplate2); } }, [initialTemplate2, loadTemplate]); const handleEditorChange = _react.useCallback.call(void 0, (value) => { if (value !== void 0 && !readOnly) { updateContent(value); } }, [updateContent, readOnly]); const handleSave = _react.useCallback.call(void 0, async () => { if (onSave) { await onSave(template); await save(); } else { await save(); } }, [template, onSave, save]); const editorOptions = _react.useMemo.call(void 0, () => ({ readOnly, lineNumbers: showLineNumbers ? "on" : "off", minimap: { enabled: false }, scrollBeyondLastLine: false, wordWrap: "on", fontSize: 14, fontFamily: 'Consolas, "Courier New", monospace', padding: { top: 16, bottom: 16 }, automaticLayout: true }), [readOnly, showLineNumbers]); const monacoTheme = _optionalChain([theme, 'optionalAccess', _38 => _38.monacoTheme]) || (mode === "dark" ? "vs-dark" : "vs"); const containerStyle = { height, width, ...style }; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `prompt-editor prompt-editor--${mode} ${className || ""}`, style: containerStyle, "data-theme": mode, children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Toolbar, { config: toolbar, isDirty, onSave: handleSave, onExport: onExport ? (format) => onExport(template, format) : void 0, onImport, locale } ), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "prompt-editor__main", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.AnimatePresence, { children: showVariablePanel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.motion.div, { className: "prompt-editor__variables", initial: { width: 0, opacity: 0 }, animate: { width: 300, opacity: 1 }, exit: { width: 0, opacity: 0 }, transition: { duration: 0.2 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, VariablePanel, { variables: template.variables, customTypes: customVariableTypes, readOnly, locale } ) } ) }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "prompt-editor__content", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react4.default, { value: template.content, language: "markdown", theme: monacoTheme, options: editorOptions, onChange: handleEditorChange, beforeMount: (monaco) => { registerVariableCompletion(monaco, template.variables); } } ) }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.AnimatePresence, { children: showPreview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _framermotion.motion.div, { className: "prompt-editor__preview", initial: { width: 0, opacity: 0 }, animate: { width: 400, opacity: 1 }, exit: { width: 0, opacity: 0 }, transition: { duration: 0.2 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PreviewPanel, { template, locale } ) } ) }) ] }) ] } ); }; function registerVariableCompletion(monaco, variables) { monaco.languages.registerCompletionItemProvider("markdown", { provideCompletionItems: (model, position) => { const word = model.getWordUntilPosition(position); const range = { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: word.startColumn, endColumn: word.endColumn }; const suggestions = variables.map((variable) => ({ label: `{{${variable.name}}}`, kind: monaco.languages.CompletionItemKind.Variable, documentation: variable.description, insertText: `{{${variable.name}}}`, range })); return { suggestions }; }, triggerCharacters: ["{"] }); } // ../../node_modules/.pnpm/js-yaml@4.1.0/node_modules/js-yaml/dist/js-yaml.mjs function isNothing(subject) { return typeof subject === "undefined" || subject === null; } function isObject(subject) { return typeof subject === "object" && subject !== null; } function toArray(sequence) { if (Array.isArray(sequence)) return sequence; else if (isNothing(sequence)) return []; return [sequence]; } function extend(target, source) { var index, length, key, sourceKeys; if (source) { sourceKeys = Object.keys(source); for (index = 0, length = sourceKeys.length; index < length; index += 1) { key = sourceKeys[index]; target[key] = source[key]; } } return target; } function repeat(string, count) { var result = "", cycle; for (cycle = 0; cycle < count; cycle += 1) { result += string; } return result; } function isNegativeZero(number) { return number === 0 && Number.NEGATIVE_INFINITY === 1 / number; } var isNothing_1 = isNothing; var isObject_1 = isObject; var toArray_1 = toArray; var repeat_1 = repeat; var isNegativeZero_1 = isNegativeZero; var extend_1 = extend; var common = { isNothing: isNothing_1, isObject: isObject_1, toArray: toArray_1, repeat: repeat_1, isNegativeZero: isNegativeZero_1, extend: extend_1 }; function formatError(exception2, compact) { var where = "", message = exception2.reason || "(unknown reason)"; if (!exception2.mark) return message; if (exception2.mark.name) { where += 'in "' + exception2.mark.name + '" '; } where += "(" + (exception2.mark.line + 1) + ":" + (exception2.mark.column + 1) + ")"; if (!compact && exception2.mark.snippet) { where += "\n\n" + exception2.mark.snippet; } return message + " " + where; } function YAMLException$1(reason, mark) { Error.call(this); this.name = "YAMLException"; this.reason = reason; this.mark = mark; this.message = formatError(this, false); if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } else { this.stack = new Error().stack || ""; } } YAMLException$1.prototype = Object.create(Error.prototype); YAMLException$1.prototype.constructor = YAMLException$1; YAMLException$1.prototype.toString = function toString(compact) { return this.name + ": " + formatError(this, compact); }; var exception = YAMLException$1; function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { var head = ""; var tail = ""; var maxHalfLength = Math.floor(maxLineLength / 2) - 1; if (position - lineStart > maxHalfLength) { head = " ... "; lineStart = position - maxHalfLength + head.length; } if (lineEnd - position > maxHalfLength) { tail = " ..."; lineEnd = position + maxHalfLength - tail.length; } return { str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, "\u2192") + tail, pos: position - lineStart + head.length // relative position }; } function padStart(string, max) { return common.repeat(" ", max - string.length) + string; } function makeSnippet(mark, options) { options = Object.create(options || null); if (!mark.buffer) return null; if (!options.maxLength) options.maxLength = 79; if (typeof options.indent !== "number") options.indent = 1; if (typeof options.linesBefore !== "number") options.linesBefore = 3; if (typeof options.linesAfter !==