prompts.chat 0.0.7 → 0.0.8

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.
Files changed (40) hide show
  1. package/bin/cli.js +2 -0
  2. package/dist/builder/{index.mjs → index.cjs} +42 -3
  3. package/dist/builder/index.cjs.map +1 -0
  4. package/dist/builder/index.js +2 -41
  5. package/dist/builder/index.js.map +1 -1
  6. package/dist/cli/index.js +1132 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/{index.mjs → index.cjs} +72 -13
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/{index.d.mts → index.d.cts} +5 -5
  11. package/dist/index.js +12 -71
  12. package/dist/index.js.map +1 -1
  13. package/dist/parser/{index.mjs → index.cjs} +32 -3
  14. package/dist/parser/{index.mjs.map → index.cjs.map} +1 -1
  15. package/dist/parser/{index.d.mts → index.d.cts} +1 -1
  16. package/dist/parser/index.js +2 -31
  17. package/dist/parser/index.js.map +1 -1
  18. package/dist/quality/{index.mjs → index.cjs} +31 -3
  19. package/dist/quality/{index.mjs.map → index.cjs.map} +1 -1
  20. package/dist/quality/{index.d.mts → index.d.cts} +1 -1
  21. package/dist/quality/index.js +2 -30
  22. package/dist/quality/index.js.map +1 -1
  23. package/dist/similarity/{index.mjs → index.cjs} +35 -3
  24. package/dist/similarity/{index.mjs.map → index.cjs.map} +1 -1
  25. package/dist/similarity/{index.d.mts → index.d.cts} +1 -1
  26. package/dist/similarity/index.js +2 -34
  27. package/dist/similarity/index.js.map +1 -1
  28. package/dist/variables/{index.mjs → index.cjs} +35 -3
  29. package/dist/variables/{index.mjs.map → index.cjs.map} +1 -1
  30. package/dist/variables/{index.d.mts → index.d.cts} +1 -1
  31. package/dist/variables/index.js +2 -34
  32. package/dist/variables/index.js.map +1 -1
  33. package/package.json +18 -1
  34. package/dist/builder/index.mjs.map +0 -1
  35. package/dist/index.mjs.map +0 -1
  36. /package/dist/builder/{index.d.mts → index.d.cts} +0 -0
  37. /package/dist/{index-BEIO8LCd.d.mts → index-BEIO8LCd.d.cts} +0 -0
  38. /package/dist/{index-CSHEKYfQ.d.mts → index-CSHEKYfQ.d.cts} +0 -0
  39. /package/dist/{index-D41E6D9X.d.mts → index-D41E6D9X.d.cts} +0 -0
  40. /package/dist/{index-DOz8zcA0.d.mts → index-DOz8zcA0.d.cts} +0 -0
@@ -1,4 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
1
20
  // src/parser/index.ts
21
+ var parser_exports = {};
22
+ __export(parser_exports, {
23
+ getSystemPrompt: () => getSystemPrompt,
24
+ interpolate: () => interpolate,
25
+ parse: () => parse,
26
+ toJson: () => toJson,
27
+ toYaml: () => toYaml
28
+ });
29
+ module.exports = __toCommonJS(parser_exports);
2
30
  function parseSimpleYaml(content) {
3
31
  const result = {};
4
32
  const lines = content.split("\n");
@@ -249,11 +277,12 @@ function interpolate(prompt, values) {
249
277
  }))
250
278
  };
251
279
  }
252
- export {
280
+ // Annotate the CommonJS export names for ESM import in node:
281
+ 0 && (module.exports = {
253
282
  getSystemPrompt,
254
283
  interpolate,
255
284
  parse,
256
285
  toJson,
257
286
  toYaml
258
- };
259
- //# sourceMappingURL=index.mjs.map
287
+ });
288
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/parser/index.ts"],"sourcesContent":["/**\n * Prompt Parser - Parse and load prompt files in various formats\n * \n * Supports:\n * - .prompt.yml / .prompt.yaml (YAML format)\n * - .prompt.json (JSON format)\n * - .prompt.md (Markdown with frontmatter)\n * - .txt (Plain text)\n * \n * @example\n * ```ts\n * import { parser } from 'prompts.chat';\n * \n * const prompt = parser.parse(`\n * name: Code Review\n * messages:\n * - role: system\n * content: You are a code reviewer.\n * `);\n * ```\n */\n\nexport interface PromptMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface ParsedPrompt {\n name?: string;\n description?: string;\n model?: string;\n modelParameters?: {\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n };\n messages: PromptMessage[];\n variables?: Record<string, {\n description?: string;\n default?: string;\n required?: boolean;\n }>;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parse YAML content\n * Note: This is a simple YAML parser for common prompt file structures\n * For full YAML support, the consuming project should use a proper YAML library\n */\nfunction parseSimpleYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n \n let currentKey: string | null = null;\n let currentValue: unknown = null;\n let inArray = false;\n let inMultiline = false;\n let multilineContent = '';\n let arrayItems: unknown[] = [];\n let indent = 0;\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n \n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n if (inMultiline) {\n multilineContent += '\\n';\n }\n continue;\n }\n \n // Handle multiline content (|)\n if (inMultiline) {\n const lineIndent = line.search(/\\S/);\n if (lineIndent > indent) {\n multilineContent += (multilineContent ? '\\n' : '') + line.slice(indent + 2);\n continue;\n } else {\n // End of multiline\n if (inArray && currentKey) {\n const lastItem = arrayItems[arrayItems.length - 1] as Record<string, unknown>;\n if (lastItem && typeof lastItem === 'object') {\n const keys = Object.keys(lastItem);\n const lastKey = keys[keys.length - 1];\n lastItem[lastKey] = multilineContent.trim();\n }\n } else if (currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n inMultiline = false;\n multilineContent = '';\n }\n }\n \n // Handle array items\n if (trimmed.startsWith('- ')) {\n if (!inArray && currentKey) {\n inArray = true;\n arrayItems = [];\n }\n \n const itemContent = trimmed.slice(2);\n \n // Check if it's a key-value pair\n const kvMatch = itemContent.match(/^(\\w+):\\s*(.*)$/);\n if (kvMatch) {\n const obj: Record<string, unknown> = {};\n obj[kvMatch[1]] = kvMatch[2] === '|' ? '' : (kvMatch[2] || '');\n \n if (kvMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n \n arrayItems.push(obj);\n } else {\n arrayItems.push(itemContent);\n }\n continue;\n }\n \n // Handle nested object properties in arrays\n if (inArray && line.startsWith(' ')) {\n const propMatch = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (propMatch && arrayItems.length > 0) {\n const lastItem = arrayItems[arrayItems.length - 1];\n if (typeof lastItem === 'object' && lastItem !== null) {\n (lastItem as Record<string, unknown>)[propMatch[1]] = \n propMatch[2] === '|' ? '' : (propMatch[2] || '');\n \n if (propMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n }\n }\n continue;\n }\n \n // End array if we're back to root level\n if (inArray && !line.startsWith(' ') && !line.startsWith('\\t')) {\n if (currentKey) {\n result[currentKey] = arrayItems;\n }\n inArray = false;\n arrayItems = [];\n }\n \n // Handle key-value pairs\n const match = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (match) {\n currentKey = match[1];\n const value = match[2];\n \n if (value === '' || value === '|' || value === '>') {\n // Multiline or nested content\n if (value === '|' || value === '>') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n } else if (value.startsWith('\"') && value.endsWith('\"')) {\n result[currentKey] = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n result[currentKey] = value.slice(1, -1);\n } else if (value === 'true') {\n result[currentKey] = true;\n } else if (value === 'false') {\n result[currentKey] = false;\n } else if (!isNaN(Number(value))) {\n result[currentKey] = Number(value);\n } else {\n result[currentKey] = value;\n }\n }\n }\n \n // Handle remaining array\n if (inArray && currentKey) {\n result[currentKey] = arrayItems;\n }\n \n // Handle remaining multiline\n if (inMultiline && currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n \n return result;\n}\n\n/**\n * Parse JSON content\n */\nfunction parseJson(content: string): Record<string, unknown> {\n return JSON.parse(content);\n}\n\n/**\n * Parse Markdown with frontmatter\n */\nfunction parseMarkdown(content: string): Record<string, unknown> {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n \n if (frontmatterMatch) {\n const frontmatter = parseSimpleYaml(frontmatterMatch[1]);\n const body = frontmatterMatch[2].trim();\n \n return {\n ...frontmatter,\n messages: [{ role: 'system', content: body }],\n };\n }\n \n // No frontmatter, treat entire content as system message\n return {\n messages: [{ role: 'system', content: content.trim() }],\n };\n}\n\n/**\n * Normalize parsed data to ParsedPrompt format\n */\nfunction normalize(data: Record<string, unknown>): ParsedPrompt {\n const messages: PromptMessage[] = [];\n \n // Handle messages array\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n if (typeof msg === 'object' && msg !== null) {\n const m = msg as Record<string, unknown>;\n messages.push({\n role: (m.role as PromptMessage['role']) || 'user',\n content: String(m.content || ''),\n });\n }\n }\n }\n \n // Handle single content field\n if (messages.length === 0 && typeof data.content === 'string') {\n messages.push({ role: 'system', content: data.content });\n }\n \n // Handle prompt field (alias for content)\n if (messages.length === 0 && typeof data.prompt === 'string') {\n messages.push({ role: 'system', content: data.prompt });\n }\n \n return {\n name: data.name as string | undefined,\n description: data.description as string | undefined,\n model: data.model as string | undefined,\n modelParameters: data.modelParameters as ParsedPrompt['modelParameters'],\n messages,\n variables: data.variables as ParsedPrompt['variables'],\n metadata: data.metadata as Record<string, unknown>,\n };\n}\n\n/**\n * Parse prompt content in various formats\n */\nexport function parse(content: string, format?: 'yaml' | 'json' | 'markdown' | 'text'): ParsedPrompt {\n const trimmed = content.trim();\n \n // Auto-detect format if not specified\n if (!format) {\n if (trimmed.startsWith('{')) {\n format = 'json';\n } else if (trimmed.startsWith('---')) {\n format = 'markdown';\n } else if (trimmed.includes(':') && (trimmed.includes('\\n ') || trimmed.includes('\\n-'))) {\n format = 'yaml';\n } else {\n format = 'text';\n }\n }\n \n let data: Record<string, unknown>;\n \n switch (format) {\n case 'json':\n data = parseJson(trimmed);\n break;\n case 'yaml':\n data = parseSimpleYaml(trimmed);\n break;\n case 'markdown':\n data = parseMarkdown(trimmed);\n break;\n case 'text':\n default:\n data = { messages: [{ role: 'system', content: trimmed }] };\n break;\n }\n \n return normalize(data);\n}\n\n/**\n * Serialize a ParsedPrompt to YAML format\n */\nexport function toYaml(prompt: ParsedPrompt): string {\n const lines: string[] = [];\n \n if (prompt.name) {\n lines.push(`name: ${prompt.name}`);\n }\n \n if (prompt.description) {\n lines.push(`description: ${prompt.description}`);\n }\n \n if (prompt.model) {\n lines.push(`model: ${prompt.model}`);\n }\n \n if (prompt.modelParameters) {\n lines.push('modelParameters:');\n for (const [key, value] of Object.entries(prompt.modelParameters)) {\n if (value !== undefined) {\n lines.push(` ${key}: ${value}`);\n }\n }\n }\n \n if (prompt.messages.length > 0) {\n lines.push('messages:');\n for (const msg of prompt.messages) {\n lines.push(` - role: ${msg.role}`);\n if (msg.content.includes('\\n')) {\n lines.push(' content: |');\n for (const line of msg.content.split('\\n')) {\n lines.push(` ${line}`);\n }\n } else {\n lines.push(` content: \"${msg.content.replace(/\"/g, '\\\\\"')}\"`);\n }\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Serialize a ParsedPrompt to JSON format\n */\nexport function toJson(prompt: ParsedPrompt, pretty: boolean = true): string {\n return JSON.stringify(prompt, null, pretty ? 2 : 0);\n}\n\n/**\n * Get the system message content from a parsed prompt\n */\nexport function getSystemPrompt(prompt: ParsedPrompt): string {\n const systemMessage = prompt.messages.find(m => m.role === 'system');\n return systemMessage?.content || '';\n}\n\n/**\n * Interpolate variables in a prompt\n */\nexport function interpolate(\n prompt: ParsedPrompt,\n values: Record<string, string>\n): ParsedPrompt {\n const interpolateString = (str: string): string => {\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n if (key in values) return values[key];\n if (prompt.variables?.[key]?.default) return prompt.variables[key].default!;\n return match;\n });\n };\n \n return {\n ...prompt,\n messages: prompt.messages.map(msg => ({\n ...msg,\n content: interpolateString(msg.content),\n })),\n };\n}\n"],"mappings":";AAoDA,SAAS,gBAAgB,SAA0C;AACjE,QAAM,SAAkC,CAAC;AACzC,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAEhC,MAAI,aAA4B;AAChC,MAAI,eAAwB;AAC5B,MAAI,UAAU;AACd,MAAI,cAAc;AAClB,MAAI,mBAAmB;AACvB,MAAI,aAAwB,CAAC;AAC7B,MAAI,SAAS;AAEb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,UAAU,KAAK,KAAK;AAG1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,GAAG;AACvC,UAAI,aAAa;AACf,4BAAoB;AAAA,MACtB;AACA;AAAA,IACF;AAGA,QAAI,aAAa;AACf,YAAM,aAAa,KAAK,OAAO,IAAI;AACnC,UAAI,aAAa,QAAQ;AACvB,6BAAqB,mBAAmB,OAAO,MAAM,KAAK,MAAM,SAAS,CAAC;AAC1E;AAAA,MACF,OAAO;AAEL,YAAI,WAAW,YAAY;AACzB,gBAAM,WAAW,WAAW,WAAW,SAAS,CAAC;AACjD,cAAI,YAAY,OAAO,aAAa,UAAU;AAC5C,kBAAM,OAAO,OAAO,KAAK,QAAQ;AACjC,kBAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,qBAAS,OAAO,IAAI,iBAAiB,KAAK;AAAA,UAC5C;AAAA,QACF,WAAW,YAAY;AACrB,iBAAO,UAAU,IAAI,iBAAiB,KAAK;AAAA,QAC7C;AACA,sBAAc;AACd,2BAAmB;AAAA,MACrB;AAAA,IACF;AAGA,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,UAAI,CAAC,WAAW,YAAY;AAC1B,kBAAU;AACV,qBAAa,CAAC;AAAA,MAChB;AAEA,YAAM,cAAc,QAAQ,MAAM,CAAC;AAGnC,YAAM,UAAU,YAAY,MAAM,iBAAiB;AACnD,UAAI,SAAS;AACX,cAAM,MAA+B,CAAC;AACtC,YAAI,QAAQ,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,MAAM,KAAM,QAAQ,CAAC,KAAK;AAE3D,YAAI,QAAQ,CAAC,MAAM,KAAK;AACtB,wBAAc;AACd,mBAAS,KAAK,OAAO,IAAI;AACzB,6BAAmB;AAAA,QACrB;AAEA,mBAAW,KAAK,GAAG;AAAA,MACrB,OAAO;AACL,mBAAW,KAAK,WAAW;AAAA,MAC7B;AACA;AAAA,IACF;AAGA,QAAI,WAAW,KAAK,WAAW,MAAM,GAAG;AACtC,YAAM,YAAY,QAAQ,MAAM,iBAAiB;AACjD,UAAI,aAAa,WAAW,SAAS,GAAG;AACtC,cAAM,WAAW,WAAW,WAAW,SAAS,CAAC;AACjD,YAAI,OAAO,aAAa,YAAY,aAAa,MAAM;AACrD,UAAC,SAAqC,UAAU,CAAC,CAAC,IAChD,UAAU,CAAC,MAAM,MAAM,KAAM,UAAU,CAAC,KAAK;AAE/C,cAAI,UAAU,CAAC,MAAM,KAAK;AACxB,0BAAc;AACd,qBAAS,KAAK,OAAO,IAAI;AACzB,+BAAmB;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,WAAW,CAAC,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,WAAW,GAAI,GAAG;AAC9D,UAAI,YAAY;AACd,eAAO,UAAU,IAAI;AAAA,MACvB;AACA,gBAAU;AACV,mBAAa,CAAC;AAAA,IAChB;AAGA,UAAM,QAAQ,QAAQ,MAAM,iBAAiB;AAC7C,QAAI,OAAO;AACT,mBAAa,MAAM,CAAC;AACpB,YAAM,QAAQ,MAAM,CAAC;AAErB,UAAI,UAAU,MAAM,UAAU,OAAO,UAAU,KAAK;AAElD,YAAI,UAAU,OAAO,UAAU,KAAK;AAClC,wBAAc;AACd,mBAAS,KAAK,OAAO,IAAI;AACzB,6BAAmB;AAAA,QACrB;AAAA,MACF,WAAW,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AACvD,eAAO,UAAU,IAAI,MAAM,MAAM,GAAG,EAAE;AAAA,MACxC,WAAW,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AACvD,eAAO,UAAU,IAAI,MAAM,MAAM,GAAG,EAAE;AAAA,MACxC,WAAW,UAAU,QAAQ;AAC3B,eAAO,UAAU,IAAI;AAAA,MACvB,WAAW,UAAU,SAAS;AAC5B,eAAO,UAAU,IAAI;AAAA,MACvB,WAAW,CAAC,MAAM,OAAO,KAAK,CAAC,GAAG;AAChC,eAAO,UAAU,IAAI,OAAO,KAAK;AAAA,MACnC,OAAO;AACL,eAAO,UAAU,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,WAAW,YAAY;AACzB,WAAO,UAAU,IAAI;AAAA,EACvB;AAGA,MAAI,eAAe,YAAY;AAC7B,WAAO,UAAU,IAAI,iBAAiB,KAAK;AAAA,EAC7C;AAEA,SAAO;AACT;AAKA,SAAS,UAAU,SAA0C;AAC3D,SAAO,KAAK,MAAM,OAAO;AAC3B;AAKA,SAAS,cAAc,SAA0C;AAC/D,QAAM,mBAAmB,QAAQ,MAAM,mCAAmC;AAE1E,MAAI,kBAAkB;AACpB,UAAM,cAAc,gBAAgB,iBAAiB,CAAC,CAAC;AACvD,UAAM,OAAO,iBAAiB,CAAC,EAAE,KAAK;AAEtC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,KAAK,CAAC;AAAA,IAC9C;AAAA,EACF;AAGA,SAAO;AAAA,IACL,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,QAAQ,KAAK,EAAE,CAAC;AAAA,EACxD;AACF;AAKA,SAAS,UAAU,MAA6C;AAC9D,QAAM,WAA4B,CAAC;AAGnC,MAAI,MAAM,QAAQ,KAAK,QAAQ,GAAG;AAChC,eAAW,OAAO,KAAK,UAAU;AAC/B,UAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,cAAM,IAAI;AACV,iBAAS,KAAK;AAAA,UACZ,MAAO,EAAE,QAAkC;AAAA,UAC3C,SAAS,OAAO,EAAE,WAAW,EAAE;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,WAAW,KAAK,OAAO,KAAK,YAAY,UAAU;AAC7D,aAAS,KAAK,EAAE,MAAM,UAAU,SAAS,KAAK,QAAQ,CAAC;AAAA,EACzD;AAGA,MAAI,SAAS,WAAW,KAAK,OAAO,KAAK,WAAW,UAAU;AAC5D,aAAS,KAAK,EAAE,MAAM,UAAU,SAAS,KAAK,OAAO,CAAC;AAAA,EACxD;AAEA,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,OAAO,KAAK;AAAA,IACZ,iBAAiB,KAAK;AAAA,IACtB;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,UAAU,KAAK;AAAA,EACjB;AACF;AAKO,SAAS,MAAM,SAAiB,QAA8D;AACnG,QAAM,UAAU,QAAQ,KAAK;AAG7B,MAAI,CAAC,QAAQ;AACX,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,eAAS;AAAA,IACX,WAAW,QAAQ,WAAW,KAAK,GAAG;AACpC,eAAS;AAAA,IACX,WAAW,QAAQ,SAAS,GAAG,MAAM,QAAQ,SAAS,MAAM,KAAK,QAAQ,SAAS,KAAK,IAAI;AACzF,eAAS;AAAA,IACX,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI;AAEJ,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,UAAU,OAAO;AACxB;AAAA,IACF,KAAK;AACH,aAAO,gBAAgB,OAAO;AAC9B;AAAA,IACF,KAAK;AACH,aAAO,cAAc,OAAO;AAC5B;AAAA,IACF,KAAK;AAAA,IACL;AACE,aAAO,EAAE,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,QAAQ,CAAC,EAAE;AAC1D;AAAA,EACJ;AAEA,SAAO,UAAU,IAAI;AACvB;AAKO,SAAS,OAAO,QAA8B;AACnD,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO,MAAM;AACf,UAAM,KAAK,SAAS,OAAO,IAAI,EAAE;AAAA,EACnC;AAEA,MAAI,OAAO,aAAa;AACtB,UAAM,KAAK,gBAAgB,OAAO,WAAW,EAAE;AAAA,EACjD;AAEA,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,UAAU,OAAO,KAAK,EAAE;AAAA,EACrC;AAEA,MAAI,OAAO,iBAAiB;AAC1B,UAAM,KAAK,kBAAkB;AAC7B,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,eAAe,GAAG;AACjE,UAAI,UAAU,QAAW;AACvB,cAAM,KAAK,KAAK,GAAG,KAAK,KAAK,EAAE;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM,KAAK,WAAW;AACtB,eAAW,OAAO,OAAO,UAAU;AACjC,YAAM,KAAK,aAAa,IAAI,IAAI,EAAE;AAClC,UAAI,IAAI,QAAQ,SAAS,IAAI,GAAG;AAC9B,cAAM,KAAK,gBAAgB;AAC3B,mBAAW,QAAQ,IAAI,QAAQ,MAAM,IAAI,GAAG;AAC1C,gBAAM,KAAK,SAAS,IAAI,EAAE;AAAA,QAC5B;AAAA,MACF,OAAO;AACL,cAAM,KAAK,iBAAiB,IAAI,QAAQ,QAAQ,MAAM,KAAK,CAAC,GAAG;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,OAAO,QAAsB,SAAkB,MAAc;AAC3E,SAAO,KAAK,UAAU,QAAQ,MAAM,SAAS,IAAI,CAAC;AACpD;AAKO,SAAS,gBAAgB,QAA8B;AAC5D,QAAM,gBAAgB,OAAO,SAAS,KAAK,OAAK,EAAE,SAAS,QAAQ;AACnE,SAAO,eAAe,WAAW;AACnC;AAKO,SAAS,YACd,QACA,QACc;AACd,QAAM,oBAAoB,CAAC,QAAwB;AACjD,WAAO,IAAI,QAAQ,kBAAkB,CAAC,OAAO,QAAQ;AACnD,UAAI,OAAO,OAAQ,QAAO,OAAO,GAAG;AACpC,UAAI,OAAO,YAAY,GAAG,GAAG,QAAS,QAAO,OAAO,UAAU,GAAG,EAAE;AACnE,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,OAAO,SAAS,IAAI,UAAQ;AAAA,MACpC,GAAG;AAAA,MACH,SAAS,kBAAkB,IAAI,OAAO;AAAA,IACxC,EAAE;AAAA,EACJ;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/parser/index.ts"],"sourcesContent":["/**\n * Prompt Parser - Parse and load prompt files in various formats\n * \n * Supports:\n * - .prompt.yml / .prompt.yaml (YAML format)\n * - .prompt.json (JSON format)\n * - .prompt.md (Markdown with frontmatter)\n * - .txt (Plain text)\n * \n * @example\n * ```ts\n * import { parser } from 'prompts.chat';\n * \n * const prompt = parser.parse(`\n * name: Code Review\n * messages:\n * - role: system\n * content: You are a code reviewer.\n * `);\n * ```\n */\n\nexport interface PromptMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface ParsedPrompt {\n name?: string;\n description?: string;\n model?: string;\n modelParameters?: {\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n };\n messages: PromptMessage[];\n variables?: Record<string, {\n description?: string;\n default?: string;\n required?: boolean;\n }>;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parse YAML content\n * Note: This is a simple YAML parser for common prompt file structures\n * For full YAML support, the consuming project should use a proper YAML library\n */\nfunction parseSimpleYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n \n let currentKey: string | null = null;\n let currentValue: unknown = null;\n let inArray = false;\n let inMultiline = false;\n let multilineContent = '';\n let arrayItems: unknown[] = [];\n let indent = 0;\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n \n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n if (inMultiline) {\n multilineContent += '\\n';\n }\n continue;\n }\n \n // Handle multiline content (|)\n if (inMultiline) {\n const lineIndent = line.search(/\\S/);\n if (lineIndent > indent) {\n multilineContent += (multilineContent ? '\\n' : '') + line.slice(indent + 2);\n continue;\n } else {\n // End of multiline\n if (inArray && currentKey) {\n const lastItem = arrayItems[arrayItems.length - 1] as Record<string, unknown>;\n if (lastItem && typeof lastItem === 'object') {\n const keys = Object.keys(lastItem);\n const lastKey = keys[keys.length - 1];\n lastItem[lastKey] = multilineContent.trim();\n }\n } else if (currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n inMultiline = false;\n multilineContent = '';\n }\n }\n \n // Handle array items\n if (trimmed.startsWith('- ')) {\n if (!inArray && currentKey) {\n inArray = true;\n arrayItems = [];\n }\n \n const itemContent = trimmed.slice(2);\n \n // Check if it's a key-value pair\n const kvMatch = itemContent.match(/^(\\w+):\\s*(.*)$/);\n if (kvMatch) {\n const obj: Record<string, unknown> = {};\n obj[kvMatch[1]] = kvMatch[2] === '|' ? '' : (kvMatch[2] || '');\n \n if (kvMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n \n arrayItems.push(obj);\n } else {\n arrayItems.push(itemContent);\n }\n continue;\n }\n \n // Handle nested object properties in arrays\n if (inArray && line.startsWith(' ')) {\n const propMatch = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (propMatch && arrayItems.length > 0) {\n const lastItem = arrayItems[arrayItems.length - 1];\n if (typeof lastItem === 'object' && lastItem !== null) {\n (lastItem as Record<string, unknown>)[propMatch[1]] = \n propMatch[2] === '|' ? '' : (propMatch[2] || '');\n \n if (propMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n }\n }\n continue;\n }\n \n // End array if we're back to root level\n if (inArray && !line.startsWith(' ') && !line.startsWith('\\t')) {\n if (currentKey) {\n result[currentKey] = arrayItems;\n }\n inArray = false;\n arrayItems = [];\n }\n \n // Handle key-value pairs\n const match = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (match) {\n currentKey = match[1];\n const value = match[2];\n \n if (value === '' || value === '|' || value === '>') {\n // Multiline or nested content\n if (value === '|' || value === '>') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n } else if (value.startsWith('\"') && value.endsWith('\"')) {\n result[currentKey] = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n result[currentKey] = value.slice(1, -1);\n } else if (value === 'true') {\n result[currentKey] = true;\n } else if (value === 'false') {\n result[currentKey] = false;\n } else if (!isNaN(Number(value))) {\n result[currentKey] = Number(value);\n } else {\n result[currentKey] = value;\n }\n }\n }\n \n // Handle remaining array\n if (inArray && currentKey) {\n result[currentKey] = arrayItems;\n }\n \n // Handle remaining multiline\n if (inMultiline && currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n \n return result;\n}\n\n/**\n * Parse JSON content\n */\nfunction parseJson(content: string): Record<string, unknown> {\n return JSON.parse(content);\n}\n\n/**\n * Parse Markdown with frontmatter\n */\nfunction parseMarkdown(content: string): Record<string, unknown> {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n \n if (frontmatterMatch) {\n const frontmatter = parseSimpleYaml(frontmatterMatch[1]);\n const body = frontmatterMatch[2].trim();\n \n return {\n ...frontmatter,\n messages: [{ role: 'system', content: body }],\n };\n }\n \n // No frontmatter, treat entire content as system message\n return {\n messages: [{ role: 'system', content: content.trim() }],\n };\n}\n\n/**\n * Normalize parsed data to ParsedPrompt format\n */\nfunction normalize(data: Record<string, unknown>): ParsedPrompt {\n const messages: PromptMessage[] = [];\n \n // Handle messages array\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n if (typeof msg === 'object' && msg !== null) {\n const m = msg as Record<string, unknown>;\n messages.push({\n role: (m.role as PromptMessage['role']) || 'user',\n content: String(m.content || ''),\n });\n }\n }\n }\n \n // Handle single content field\n if (messages.length === 0 && typeof data.content === 'string') {\n messages.push({ role: 'system', content: data.content });\n }\n \n // Handle prompt field (alias for content)\n if (messages.length === 0 && typeof data.prompt === 'string') {\n messages.push({ role: 'system', content: data.prompt });\n }\n \n return {\n name: data.name as string | undefined,\n description: data.description as string | undefined,\n model: data.model as string | undefined,\n modelParameters: data.modelParameters as ParsedPrompt['modelParameters'],\n messages,\n variables: data.variables as ParsedPrompt['variables'],\n metadata: data.metadata as Record<string, unknown>,\n };\n}\n\n/**\n * Parse prompt content in various formats\n */\nexport function parse(content: string, format?: 'yaml' | 'json' | 'markdown' | 'text'): ParsedPrompt {\n const trimmed = content.trim();\n \n // Auto-detect format if not specified\n if (!format) {\n if (trimmed.startsWith('{')) {\n format = 'json';\n } else if (trimmed.startsWith('---')) {\n format = 'markdown';\n } else if (trimmed.includes(':') && (trimmed.includes('\\n ') || trimmed.includes('\\n-'))) {\n format = 'yaml';\n } else {\n format = 'text';\n }\n }\n \n let data: Record<string, unknown>;\n \n switch (format) {\n case 'json':\n data = parseJson(trimmed);\n break;\n case 'yaml':\n data = parseSimpleYaml(trimmed);\n break;\n case 'markdown':\n data = parseMarkdown(trimmed);\n break;\n case 'text':\n default:\n data = { messages: [{ role: 'system', content: trimmed }] };\n break;\n }\n \n return normalize(data);\n}\n\n/**\n * Serialize a ParsedPrompt to YAML format\n */\nexport function toYaml(prompt: ParsedPrompt): string {\n const lines: string[] = [];\n \n if (prompt.name) {\n lines.push(`name: ${prompt.name}`);\n }\n \n if (prompt.description) {\n lines.push(`description: ${prompt.description}`);\n }\n \n if (prompt.model) {\n lines.push(`model: ${prompt.model}`);\n }\n \n if (prompt.modelParameters) {\n lines.push('modelParameters:');\n for (const [key, value] of Object.entries(prompt.modelParameters)) {\n if (value !== undefined) {\n lines.push(` ${key}: ${value}`);\n }\n }\n }\n \n if (prompt.messages.length > 0) {\n lines.push('messages:');\n for (const msg of prompt.messages) {\n lines.push(` - role: ${msg.role}`);\n if (msg.content.includes('\\n')) {\n lines.push(' content: |');\n for (const line of msg.content.split('\\n')) {\n lines.push(` ${line}`);\n }\n } else {\n lines.push(` content: \"${msg.content.replace(/\"/g, '\\\\\"')}\"`);\n }\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Serialize a ParsedPrompt to JSON format\n */\nexport function toJson(prompt: ParsedPrompt, pretty: boolean = true): string {\n return JSON.stringify(prompt, null, pretty ? 2 : 0);\n}\n\n/**\n * Get the system message content from a parsed prompt\n */\nexport function getSystemPrompt(prompt: ParsedPrompt): string {\n const systemMessage = prompt.messages.find(m => m.role === 'system');\n return systemMessage?.content || '';\n}\n\n/**\n * Interpolate variables in a prompt\n */\nexport function interpolate(\n prompt: ParsedPrompt,\n values: Record<string, string>\n): ParsedPrompt {\n const interpolateString = (str: string): string => {\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n if (key in values) return values[key];\n if (prompt.variables?.[key]?.default) return prompt.variables[key].default!;\n return match;\n });\n };\n \n return {\n ...prompt,\n messages: prompt.messages.map(msg => ({\n ...msg,\n content: interpolateString(msg.content),\n })),\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- export { P as ParsedPrompt, c as PromptMessage, g as getSystemPrompt, b as interpolate, p as parse, a as toJson, t as toYaml } from '../index-D41E6D9X.mjs';
1
+ export { P as ParsedPrompt, c as PromptMessage, g as getSystemPrompt, b as interpolate, p as parse, a as toJson, t as toYaml } from '../index-D41E6D9X.cjs';
@@ -1,32 +1,4 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
1
  // src/parser/index.ts
21
- var parser_exports = {};
22
- __export(parser_exports, {
23
- getSystemPrompt: () => getSystemPrompt,
24
- interpolate: () => interpolate,
25
- parse: () => parse,
26
- toJson: () => toJson,
27
- toYaml: () => toYaml
28
- });
29
- module.exports = __toCommonJS(parser_exports);
30
2
  function parseSimpleYaml(content) {
31
3
  const result = {};
32
4
  const lines = content.split("\n");
@@ -277,12 +249,11 @@ function interpolate(prompt, values) {
277
249
  }))
278
250
  };
279
251
  }
280
- // Annotate the CommonJS export names for ESM import in node:
281
- 0 && (module.exports = {
252
+ export {
282
253
  getSystemPrompt,
283
254
  interpolate,
284
255
  parse,
285
256
  toJson,
286
257
  toYaml
287
- });
258
+ };
288
259
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/parser/index.ts"],"sourcesContent":["/**\n * Prompt Parser - Parse and load prompt files in various formats\n * \n * Supports:\n * - .prompt.yml / .prompt.yaml (YAML format)\n * - .prompt.json (JSON format)\n * - .prompt.md (Markdown with frontmatter)\n * - .txt (Plain text)\n * \n * @example\n * ```ts\n * import { parser } from 'prompts.chat';\n * \n * const prompt = parser.parse(`\n * name: Code Review\n * messages:\n * - role: system\n * content: You are a code reviewer.\n * `);\n * ```\n */\n\nexport interface PromptMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface ParsedPrompt {\n name?: string;\n description?: string;\n model?: string;\n modelParameters?: {\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n };\n messages: PromptMessage[];\n variables?: Record<string, {\n description?: string;\n default?: string;\n required?: boolean;\n }>;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parse YAML content\n * Note: This is a simple YAML parser for common prompt file structures\n * For full YAML support, the consuming project should use a proper YAML library\n */\nfunction parseSimpleYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n \n let currentKey: string | null = null;\n let currentValue: unknown = null;\n let inArray = false;\n let inMultiline = false;\n let multilineContent = '';\n let arrayItems: unknown[] = [];\n let indent = 0;\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n \n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n if (inMultiline) {\n multilineContent += '\\n';\n }\n continue;\n }\n \n // Handle multiline content (|)\n if (inMultiline) {\n const lineIndent = line.search(/\\S/);\n if (lineIndent > indent) {\n multilineContent += (multilineContent ? '\\n' : '') + line.slice(indent + 2);\n continue;\n } else {\n // End of multiline\n if (inArray && currentKey) {\n const lastItem = arrayItems[arrayItems.length - 1] as Record<string, unknown>;\n if (lastItem && typeof lastItem === 'object') {\n const keys = Object.keys(lastItem);\n const lastKey = keys[keys.length - 1];\n lastItem[lastKey] = multilineContent.trim();\n }\n } else if (currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n inMultiline = false;\n multilineContent = '';\n }\n }\n \n // Handle array items\n if (trimmed.startsWith('- ')) {\n if (!inArray && currentKey) {\n inArray = true;\n arrayItems = [];\n }\n \n const itemContent = trimmed.slice(2);\n \n // Check if it's a key-value pair\n const kvMatch = itemContent.match(/^(\\w+):\\s*(.*)$/);\n if (kvMatch) {\n const obj: Record<string, unknown> = {};\n obj[kvMatch[1]] = kvMatch[2] === '|' ? '' : (kvMatch[2] || '');\n \n if (kvMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n \n arrayItems.push(obj);\n } else {\n arrayItems.push(itemContent);\n }\n continue;\n }\n \n // Handle nested object properties in arrays\n if (inArray && line.startsWith(' ')) {\n const propMatch = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (propMatch && arrayItems.length > 0) {\n const lastItem = arrayItems[arrayItems.length - 1];\n if (typeof lastItem === 'object' && lastItem !== null) {\n (lastItem as Record<string, unknown>)[propMatch[1]] = \n propMatch[2] === '|' ? '' : (propMatch[2] || '');\n \n if (propMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n }\n }\n continue;\n }\n \n // End array if we're back to root level\n if (inArray && !line.startsWith(' ') && !line.startsWith('\\t')) {\n if (currentKey) {\n result[currentKey] = arrayItems;\n }\n inArray = false;\n arrayItems = [];\n }\n \n // Handle key-value pairs\n const match = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (match) {\n currentKey = match[1];\n const value = match[2];\n \n if (value === '' || value === '|' || value === '>') {\n // Multiline or nested content\n if (value === '|' || value === '>') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n } else if (value.startsWith('\"') && value.endsWith('\"')) {\n result[currentKey] = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n result[currentKey] = value.slice(1, -1);\n } else if (value === 'true') {\n result[currentKey] = true;\n } else if (value === 'false') {\n result[currentKey] = false;\n } else if (!isNaN(Number(value))) {\n result[currentKey] = Number(value);\n } else {\n result[currentKey] = value;\n }\n }\n }\n \n // Handle remaining array\n if (inArray && currentKey) {\n result[currentKey] = arrayItems;\n }\n \n // Handle remaining multiline\n if (inMultiline && currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n \n return result;\n}\n\n/**\n * Parse JSON content\n */\nfunction parseJson(content: string): Record<string, unknown> {\n return JSON.parse(content);\n}\n\n/**\n * Parse Markdown with frontmatter\n */\nfunction parseMarkdown(content: string): Record<string, unknown> {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n \n if (frontmatterMatch) {\n const frontmatter = parseSimpleYaml(frontmatterMatch[1]);\n const body = frontmatterMatch[2].trim();\n \n return {\n ...frontmatter,\n messages: [{ role: 'system', content: body }],\n };\n }\n \n // No frontmatter, treat entire content as system message\n return {\n messages: [{ role: 'system', content: content.trim() }],\n };\n}\n\n/**\n * Normalize parsed data to ParsedPrompt format\n */\nfunction normalize(data: Record<string, unknown>): ParsedPrompt {\n const messages: PromptMessage[] = [];\n \n // Handle messages array\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n if (typeof msg === 'object' && msg !== null) {\n const m = msg as Record<string, unknown>;\n messages.push({\n role: (m.role as PromptMessage['role']) || 'user',\n content: String(m.content || ''),\n });\n }\n }\n }\n \n // Handle single content field\n if (messages.length === 0 && typeof data.content === 'string') {\n messages.push({ role: 'system', content: data.content });\n }\n \n // Handle prompt field (alias for content)\n if (messages.length === 0 && typeof data.prompt === 'string') {\n messages.push({ role: 'system', content: data.prompt });\n }\n \n return {\n name: data.name as string | undefined,\n description: data.description as string | undefined,\n model: data.model as string | undefined,\n modelParameters: data.modelParameters as ParsedPrompt['modelParameters'],\n messages,\n variables: data.variables as ParsedPrompt['variables'],\n metadata: data.metadata as Record<string, unknown>,\n };\n}\n\n/**\n * Parse prompt content in various formats\n */\nexport function parse(content: string, format?: 'yaml' | 'json' | 'markdown' | 'text'): ParsedPrompt {\n const trimmed = content.trim();\n \n // Auto-detect format if not specified\n if (!format) {\n if (trimmed.startsWith('{')) {\n format = 'json';\n } else if (trimmed.startsWith('---')) {\n format = 'markdown';\n } else if (trimmed.includes(':') && (trimmed.includes('\\n ') || trimmed.includes('\\n-'))) {\n format = 'yaml';\n } else {\n format = 'text';\n }\n }\n \n let data: Record<string, unknown>;\n \n switch (format) {\n case 'json':\n data = parseJson(trimmed);\n break;\n case 'yaml':\n data = parseSimpleYaml(trimmed);\n break;\n case 'markdown':\n data = parseMarkdown(trimmed);\n break;\n case 'text':\n default:\n data = { messages: [{ role: 'system', content: trimmed }] };\n break;\n }\n \n return normalize(data);\n}\n\n/**\n * Serialize a ParsedPrompt to YAML format\n */\nexport function toYaml(prompt: ParsedPrompt): string {\n const lines: string[] = [];\n \n if (prompt.name) {\n lines.push(`name: ${prompt.name}`);\n }\n \n if (prompt.description) {\n lines.push(`description: ${prompt.description}`);\n }\n \n if (prompt.model) {\n lines.push(`model: ${prompt.model}`);\n }\n \n if (prompt.modelParameters) {\n lines.push('modelParameters:');\n for (const [key, value] of Object.entries(prompt.modelParameters)) {\n if (value !== undefined) {\n lines.push(` ${key}: ${value}`);\n }\n }\n }\n \n if (prompt.messages.length > 0) {\n lines.push('messages:');\n for (const msg of prompt.messages) {\n lines.push(` - role: ${msg.role}`);\n if (msg.content.includes('\\n')) {\n lines.push(' content: |');\n for (const line of msg.content.split('\\n')) {\n lines.push(` ${line}`);\n }\n } else {\n lines.push(` content: \"${msg.content.replace(/\"/g, '\\\\\"')}\"`);\n }\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Serialize a ParsedPrompt to JSON format\n */\nexport function toJson(prompt: ParsedPrompt, pretty: boolean = true): string {\n return JSON.stringify(prompt, null, pretty ? 2 : 0);\n}\n\n/**\n * Get the system message content from a parsed prompt\n */\nexport function getSystemPrompt(prompt: ParsedPrompt): string {\n const systemMessage = prompt.messages.find(m => m.role === 'system');\n return systemMessage?.content || '';\n}\n\n/**\n * Interpolate variables in a prompt\n */\nexport function interpolate(\n prompt: ParsedPrompt,\n values: Record<string, string>\n): ParsedPrompt {\n const interpolateString = (str: string): string => {\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n if (key in values) return values[key];\n if (prompt.variables?.[key]?.default) return prompt.variables[key].default!;\n return match;\n });\n };\n \n return {\n ...prompt,\n messages: prompt.messages.map(msg => ({\n ...msg,\n content: interpolateString(msg.content),\n })),\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/parser/index.ts"],"sourcesContent":["/**\n * Prompt Parser - Parse and load prompt files in various formats\n * \n * Supports:\n * - .prompt.yml / .prompt.yaml (YAML format)\n * - .prompt.json (JSON format)\n * - .prompt.md (Markdown with frontmatter)\n * - .txt (Plain text)\n * \n * @example\n * ```ts\n * import { parser } from 'prompts.chat';\n * \n * const prompt = parser.parse(`\n * name: Code Review\n * messages:\n * - role: system\n * content: You are a code reviewer.\n * `);\n * ```\n */\n\nexport interface PromptMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface ParsedPrompt {\n name?: string;\n description?: string;\n model?: string;\n modelParameters?: {\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n };\n messages: PromptMessage[];\n variables?: Record<string, {\n description?: string;\n default?: string;\n required?: boolean;\n }>;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parse YAML content\n * Note: This is a simple YAML parser for common prompt file structures\n * For full YAML support, the consuming project should use a proper YAML library\n */\nfunction parseSimpleYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n \n let currentKey: string | null = null;\n let currentValue: unknown = null;\n let inArray = false;\n let inMultiline = false;\n let multilineContent = '';\n let arrayItems: unknown[] = [];\n let indent = 0;\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n \n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n if (inMultiline) {\n multilineContent += '\\n';\n }\n continue;\n }\n \n // Handle multiline content (|)\n if (inMultiline) {\n const lineIndent = line.search(/\\S/);\n if (lineIndent > indent) {\n multilineContent += (multilineContent ? '\\n' : '') + line.slice(indent + 2);\n continue;\n } else {\n // End of multiline\n if (inArray && currentKey) {\n const lastItem = arrayItems[arrayItems.length - 1] as Record<string, unknown>;\n if (lastItem && typeof lastItem === 'object') {\n const keys = Object.keys(lastItem);\n const lastKey = keys[keys.length - 1];\n lastItem[lastKey] = multilineContent.trim();\n }\n } else if (currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n inMultiline = false;\n multilineContent = '';\n }\n }\n \n // Handle array items\n if (trimmed.startsWith('- ')) {\n if (!inArray && currentKey) {\n inArray = true;\n arrayItems = [];\n }\n \n const itemContent = trimmed.slice(2);\n \n // Check if it's a key-value pair\n const kvMatch = itemContent.match(/^(\\w+):\\s*(.*)$/);\n if (kvMatch) {\n const obj: Record<string, unknown> = {};\n obj[kvMatch[1]] = kvMatch[2] === '|' ? '' : (kvMatch[2] || '');\n \n if (kvMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n \n arrayItems.push(obj);\n } else {\n arrayItems.push(itemContent);\n }\n continue;\n }\n \n // Handle nested object properties in arrays\n if (inArray && line.startsWith(' ')) {\n const propMatch = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (propMatch && arrayItems.length > 0) {\n const lastItem = arrayItems[arrayItems.length - 1];\n if (typeof lastItem === 'object' && lastItem !== null) {\n (lastItem as Record<string, unknown>)[propMatch[1]] = \n propMatch[2] === '|' ? '' : (propMatch[2] || '');\n \n if (propMatch[2] === '|') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n }\n }\n continue;\n }\n \n // End array if we're back to root level\n if (inArray && !line.startsWith(' ') && !line.startsWith('\\t')) {\n if (currentKey) {\n result[currentKey] = arrayItems;\n }\n inArray = false;\n arrayItems = [];\n }\n \n // Handle key-value pairs\n const match = trimmed.match(/^(\\w+):\\s*(.*)$/);\n if (match) {\n currentKey = match[1];\n const value = match[2];\n \n if (value === '' || value === '|' || value === '>') {\n // Multiline or nested content\n if (value === '|' || value === '>') {\n inMultiline = true;\n indent = line.search(/\\S/);\n multilineContent = '';\n }\n } else if (value.startsWith('\"') && value.endsWith('\"')) {\n result[currentKey] = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n result[currentKey] = value.slice(1, -1);\n } else if (value === 'true') {\n result[currentKey] = true;\n } else if (value === 'false') {\n result[currentKey] = false;\n } else if (!isNaN(Number(value))) {\n result[currentKey] = Number(value);\n } else {\n result[currentKey] = value;\n }\n }\n }\n \n // Handle remaining array\n if (inArray && currentKey) {\n result[currentKey] = arrayItems;\n }\n \n // Handle remaining multiline\n if (inMultiline && currentKey) {\n result[currentKey] = multilineContent.trim();\n }\n \n return result;\n}\n\n/**\n * Parse JSON content\n */\nfunction parseJson(content: string): Record<string, unknown> {\n return JSON.parse(content);\n}\n\n/**\n * Parse Markdown with frontmatter\n */\nfunction parseMarkdown(content: string): Record<string, unknown> {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n \n if (frontmatterMatch) {\n const frontmatter = parseSimpleYaml(frontmatterMatch[1]);\n const body = frontmatterMatch[2].trim();\n \n return {\n ...frontmatter,\n messages: [{ role: 'system', content: body }],\n };\n }\n \n // No frontmatter, treat entire content as system message\n return {\n messages: [{ role: 'system', content: content.trim() }],\n };\n}\n\n/**\n * Normalize parsed data to ParsedPrompt format\n */\nfunction normalize(data: Record<string, unknown>): ParsedPrompt {\n const messages: PromptMessage[] = [];\n \n // Handle messages array\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n if (typeof msg === 'object' && msg !== null) {\n const m = msg as Record<string, unknown>;\n messages.push({\n role: (m.role as PromptMessage['role']) || 'user',\n content: String(m.content || ''),\n });\n }\n }\n }\n \n // Handle single content field\n if (messages.length === 0 && typeof data.content === 'string') {\n messages.push({ role: 'system', content: data.content });\n }\n \n // Handle prompt field (alias for content)\n if (messages.length === 0 && typeof data.prompt === 'string') {\n messages.push({ role: 'system', content: data.prompt });\n }\n \n return {\n name: data.name as string | undefined,\n description: data.description as string | undefined,\n model: data.model as string | undefined,\n modelParameters: data.modelParameters as ParsedPrompt['modelParameters'],\n messages,\n variables: data.variables as ParsedPrompt['variables'],\n metadata: data.metadata as Record<string, unknown>,\n };\n}\n\n/**\n * Parse prompt content in various formats\n */\nexport function parse(content: string, format?: 'yaml' | 'json' | 'markdown' | 'text'): ParsedPrompt {\n const trimmed = content.trim();\n \n // Auto-detect format if not specified\n if (!format) {\n if (trimmed.startsWith('{')) {\n format = 'json';\n } else if (trimmed.startsWith('---')) {\n format = 'markdown';\n } else if (trimmed.includes(':') && (trimmed.includes('\\n ') || trimmed.includes('\\n-'))) {\n format = 'yaml';\n } else {\n format = 'text';\n }\n }\n \n let data: Record<string, unknown>;\n \n switch (format) {\n case 'json':\n data = parseJson(trimmed);\n break;\n case 'yaml':\n data = parseSimpleYaml(trimmed);\n break;\n case 'markdown':\n data = parseMarkdown(trimmed);\n break;\n case 'text':\n default:\n data = { messages: [{ role: 'system', content: trimmed }] };\n break;\n }\n \n return normalize(data);\n}\n\n/**\n * Serialize a ParsedPrompt to YAML format\n */\nexport function toYaml(prompt: ParsedPrompt): string {\n const lines: string[] = [];\n \n if (prompt.name) {\n lines.push(`name: ${prompt.name}`);\n }\n \n if (prompt.description) {\n lines.push(`description: ${prompt.description}`);\n }\n \n if (prompt.model) {\n lines.push(`model: ${prompt.model}`);\n }\n \n if (prompt.modelParameters) {\n lines.push('modelParameters:');\n for (const [key, value] of Object.entries(prompt.modelParameters)) {\n if (value !== undefined) {\n lines.push(` ${key}: ${value}`);\n }\n }\n }\n \n if (prompt.messages.length > 0) {\n lines.push('messages:');\n for (const msg of prompt.messages) {\n lines.push(` - role: ${msg.role}`);\n if (msg.content.includes('\\n')) {\n lines.push(' content: |');\n for (const line of msg.content.split('\\n')) {\n lines.push(` ${line}`);\n }\n } else {\n lines.push(` content: \"${msg.content.replace(/\"/g, '\\\\\"')}\"`);\n }\n }\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Serialize a ParsedPrompt to JSON format\n */\nexport function toJson(prompt: ParsedPrompt, pretty: boolean = true): string {\n return JSON.stringify(prompt, null, pretty ? 2 : 0);\n}\n\n/**\n * Get the system message content from a parsed prompt\n */\nexport function getSystemPrompt(prompt: ParsedPrompt): string {\n const systemMessage = prompt.messages.find(m => m.role === 'system');\n return systemMessage?.content || '';\n}\n\n/**\n * Interpolate variables in a prompt\n */\nexport function interpolate(\n prompt: ParsedPrompt,\n values: Record<string, string>\n): ParsedPrompt {\n const interpolateString = (str: string): string => {\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n if (key in values) return values[key];\n if (prompt.variables?.[key]?.default) return prompt.variables[key].default!;\n return match;\n });\n };\n \n return {\n ...prompt,\n messages: prompt.messages.map(msg => ({\n ...msg,\n content: interpolateString(msg.content),\n })),\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,31 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
1
20
  // src/quality/index.ts
21
+ var quality_exports = {};
22
+ __export(quality_exports, {
23
+ check: () => check,
24
+ getSuggestions: () => getSuggestions,
25
+ isValid: () => isValid,
26
+ validate: () => validate
27
+ });
28
+ module.exports = __toCommonJS(quality_exports);
2
29
  var MIN_CHAR_COUNT = 20;
3
30
  var MIN_WORD_COUNT = 5;
4
31
  var OPTIMAL_MIN_WORDS = 20;
@@ -175,10 +202,11 @@ function getSuggestions(prompt) {
175
202
  }
176
203
  return suggestions;
177
204
  }
178
- export {
205
+ // Annotate the CommonJS export names for ESM import in node:
206
+ 0 && (module.exports = {
179
207
  check,
180
208
  getSuggestions,
181
209
  isValid,
182
210
  validate
183
- };
184
- //# sourceMappingURL=index.mjs.map
211
+ });
212
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/quality/index.ts"],"sourcesContent":["/**\n * Prompt Quality Checker - Local validation for prompt quality\n * \n * @example\n * ```ts\n * import { quality } from 'prompts.chat';\n * \n * const result = quality.check(\"Act as a developer...\");\n * console.log(result.score); // 0.85\n * console.log(result.issues); // []\n * ```\n */\n\nexport interface QualityIssue {\n type: 'error' | 'warning' | 'suggestion';\n code: string;\n message: string;\n position?: { start: number; end: number };\n}\n\nexport interface QualityResult {\n valid: boolean;\n score: number; // 0-1\n issues: QualityIssue[];\n stats: {\n characterCount: number;\n wordCount: number;\n sentenceCount: number;\n variableCount: number;\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n };\n}\n\n// Minimum thresholds\nconst MIN_CHAR_COUNT = 20;\nconst MIN_WORD_COUNT = 5;\nconst OPTIMAL_MIN_WORDS = 20;\nconst OPTIMAL_MAX_WORDS = 2000;\n\n/**\n * Check if text looks like gibberish\n */\nfunction isGibberish(text: string): boolean {\n // Check for repeated characters\n if (/(.)\\1{4,}/.test(text)) return true;\n \n // Check for keyboard patterns\n const keyboardPatterns = ['qwerty', 'asdfgh', 'zxcvbn', 'qwertz', 'azerty'];\n const lower = text.toLowerCase();\n if (keyboardPatterns.some(p => lower.includes(p))) return true;\n \n // Check consonant/vowel ratio (gibberish often has unusual ratios)\n const vowels = (text.match(/[aeiouAEIOU]/g) || []).length;\n const consonants = (text.match(/[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]/g) || []).length;\n \n if (consonants > 0 && vowels / consonants < 0.1) return true;\n \n return false;\n}\n\n/**\n * Detect common prompt patterns\n */\nfunction detectPatterns(text: string): {\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n} {\n const lower = text.toLowerCase();\n \n return {\n hasRole: /\\b(act as|you are|imagine you|pretend to be|role:|persona:)\\b/i.test(text),\n hasTask: /\\b(your task|you (will|should|must)|please|help me|i need|i want you to)\\b/i.test(text),\n hasConstraints: /\\b(do not|don't|never|always|must|should not|avoid|only|limit)\\b/i.test(text) ||\n /\\b(rule|constraint|requirement|guideline)\\b/i.test(lower),\n hasExamples: /\\b(example|for instance|such as|e\\.g\\.|like this)\\b/i.test(lower) ||\n /```[\\s\\S]*```/.test(text),\n };\n}\n\n/**\n * Count variables in the prompt\n */\nfunction countVariables(text: string): number {\n // Match various variable formats\n const patterns = [\n /\\$\\{[^}]+\\}/g, // ${var}\n /\\{\\{[^}]+\\}\\}/g, // {{var}}\n /\\[\\[[^\\]]+\\]\\]/g, // [[var]]\n /\\[[A-Z][A-Z0-9_\\s]*\\]/g, // [VAR]\n ];\n \n let count = 0;\n for (const pattern of patterns) {\n const matches = text.match(pattern);\n if (matches) count += matches.length;\n }\n \n return count;\n}\n\n/**\n * Calculate quality score based on various factors\n */\nfunction calculateScore(\n stats: QualityResult['stats'],\n issues: QualityIssue[]\n): number {\n let score = 1.0;\n \n // Deduct for errors\n const errors = issues.filter(i => i.type === 'error').length;\n const warnings = issues.filter(i => i.type === 'warning').length;\n \n score -= errors * 0.2;\n score -= warnings * 0.05;\n \n // Bonus for good structure\n if (stats.hasRole) score += 0.05;\n if (stats.hasTask) score += 0.05;\n if (stats.hasConstraints) score += 0.03;\n if (stats.hasExamples) score += 0.05;\n \n // Penalty for being too short\n if (stats.wordCount < OPTIMAL_MIN_WORDS) {\n score -= 0.1 * (1 - stats.wordCount / OPTIMAL_MIN_WORDS);\n }\n \n // Slight penalty for being very long\n if (stats.wordCount > OPTIMAL_MAX_WORDS) {\n score -= 0.05;\n }\n \n // Bonus for having variables (indicates reusability)\n if (stats.variableCount > 0) {\n score += 0.05;\n }\n \n return Math.max(0, Math.min(1, score));\n}\n\n/**\n * Check prompt quality locally (no API needed)\n */\nexport function check(prompt: string): QualityResult {\n const issues: QualityIssue[] = [];\n const trimmed = prompt.trim();\n \n // Basic stats\n const characterCount = trimmed.length;\n const words = trimmed.split(/\\s+/).filter(w => w.length > 0);\n const wordCount = words.length;\n const sentenceCount = (trimmed.match(/[.!?]+/g) || []).length || 1;\n const variableCount = countVariables(trimmed);\n const patterns = detectPatterns(trimmed);\n \n // Check for empty or too short\n if (characterCount === 0) {\n issues.push({\n type: 'error',\n code: 'EMPTY',\n message: 'Prompt is empty',\n });\n } else if (characterCount < MIN_CHAR_COUNT) {\n issues.push({\n type: 'error',\n code: 'TOO_SHORT',\n message: `Prompt is too short (${characterCount} chars, minimum ${MIN_CHAR_COUNT})`,\n });\n }\n \n if (wordCount > 0 && wordCount < MIN_WORD_COUNT) {\n issues.push({\n type: 'warning',\n code: 'FEW_WORDS',\n message: `Prompt has very few words (${wordCount} words, recommended ${OPTIMAL_MIN_WORDS}+)`,\n });\n }\n \n // Check for gibberish\n if (isGibberish(trimmed)) {\n issues.push({\n type: 'error',\n code: 'GIBBERISH',\n message: 'Prompt appears to contain gibberish or random characters',\n });\n }\n \n // Check for common issues\n if (!patterns.hasTask && !patterns.hasRole) {\n issues.push({\n type: 'suggestion',\n code: 'NO_CLEAR_INSTRUCTION',\n message: 'Consider adding a clear task or role definition',\n });\n }\n \n // Check for unbalanced brackets/quotes\n const brackets = [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n ];\n \n for (const { open, close } of brackets) {\n const openCount = (trimmed.match(new RegExp(`\\\\${open}`, 'g')) || []).length;\n const closeCount = (trimmed.match(new RegExp(`\\\\${close}`, 'g')) || []).length;\n \n if (openCount !== closeCount) {\n issues.push({\n type: 'warning',\n code: 'UNBALANCED_BRACKETS',\n message: `Unbalanced ${open}${close} brackets (${openCount} open, ${closeCount} close)`,\n });\n }\n }\n \n // Check for very long lines (readability)\n const lines = trimmed.split('\\n');\n const longLines = lines.filter(l => l.length > 500);\n if (longLines.length > 0) {\n issues.push({\n type: 'suggestion',\n code: 'LONG_LINES',\n message: 'Some lines are very long. Consider breaking them up for readability.',\n });\n }\n \n const stats = {\n characterCount,\n wordCount,\n sentenceCount,\n variableCount,\n ...patterns,\n };\n \n const score = calculateScore(stats, issues);\n const hasErrors = issues.some(i => i.type === 'error');\n \n return {\n valid: !hasErrors,\n score,\n issues,\n stats,\n };\n}\n\n/**\n * Validate a prompt and throw if invalid\n */\nexport function validate(prompt: string): void {\n const result = check(prompt);\n \n if (!result.valid) {\n const errors = result.issues\n .filter(i => i.type === 'error')\n .map(i => i.message)\n .join('; ');\n \n throw new Error(`Invalid prompt: ${errors}`);\n }\n}\n\n/**\n * Check if a prompt is valid\n */\nexport function isValid(prompt: string): boolean {\n return check(prompt).valid;\n}\n\n/**\n * Get suggestions for improving a prompt\n */\nexport function getSuggestions(prompt: string): string[] {\n const result = check(prompt);\n const suggestions: string[] = [];\n \n // From issues\n suggestions.push(\n ...result.issues\n .filter(i => i.type === 'suggestion' || i.type === 'warning')\n .map(i => i.message)\n );\n \n // Additional suggestions based on stats\n if (!result.stats.hasRole) {\n suggestions.push('Add a role definition (e.g., \"Act as a...\")');\n }\n \n if (!result.stats.hasConstraints && result.stats.wordCount > 50) {\n suggestions.push('Consider adding constraints or rules for better control');\n }\n \n if (!result.stats.hasExamples && result.stats.wordCount > 100) {\n suggestions.push('Adding examples can improve output quality');\n }\n \n if (result.stats.variableCount === 0 && result.stats.wordCount > 30) {\n suggestions.push('Consider adding variables (${var}) to make the prompt reusable');\n }\n \n return suggestions;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/quality/index.ts"],"sourcesContent":["/**\n * Prompt Quality Checker - Local validation for prompt quality\n * \n * @example\n * ```ts\n * import { quality } from 'prompts.chat';\n * \n * const result = quality.check(\"Act as a developer...\");\n * console.log(result.score); // 0.85\n * console.log(result.issues); // []\n * ```\n */\n\nexport interface QualityIssue {\n type: 'error' | 'warning' | 'suggestion';\n code: string;\n message: string;\n position?: { start: number; end: number };\n}\n\nexport interface QualityResult {\n valid: boolean;\n score: number; // 0-1\n issues: QualityIssue[];\n stats: {\n characterCount: number;\n wordCount: number;\n sentenceCount: number;\n variableCount: number;\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n };\n}\n\n// Minimum thresholds\nconst MIN_CHAR_COUNT = 20;\nconst MIN_WORD_COUNT = 5;\nconst OPTIMAL_MIN_WORDS = 20;\nconst OPTIMAL_MAX_WORDS = 2000;\n\n/**\n * Check if text looks like gibberish\n */\nfunction isGibberish(text: string): boolean {\n // Check for repeated characters\n if (/(.)\\1{4,}/.test(text)) return true;\n \n // Check for keyboard patterns\n const keyboardPatterns = ['qwerty', 'asdfgh', 'zxcvbn', 'qwertz', 'azerty'];\n const lower = text.toLowerCase();\n if (keyboardPatterns.some(p => lower.includes(p))) return true;\n \n // Check consonant/vowel ratio (gibberish often has unusual ratios)\n const vowels = (text.match(/[aeiouAEIOU]/g) || []).length;\n const consonants = (text.match(/[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]/g) || []).length;\n \n if (consonants > 0 && vowels / consonants < 0.1) return true;\n \n return false;\n}\n\n/**\n * Detect common prompt patterns\n */\nfunction detectPatterns(text: string): {\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n} {\n const lower = text.toLowerCase();\n \n return {\n hasRole: /\\b(act as|you are|imagine you|pretend to be|role:|persona:)\\b/i.test(text),\n hasTask: /\\b(your task|you (will|should|must)|please|help me|i need|i want you to)\\b/i.test(text),\n hasConstraints: /\\b(do not|don't|never|always|must|should not|avoid|only|limit)\\b/i.test(text) ||\n /\\b(rule|constraint|requirement|guideline)\\b/i.test(lower),\n hasExamples: /\\b(example|for instance|such as|e\\.g\\.|like this)\\b/i.test(lower) ||\n /```[\\s\\S]*```/.test(text),\n };\n}\n\n/**\n * Count variables in the prompt\n */\nfunction countVariables(text: string): number {\n // Match various variable formats\n const patterns = [\n /\\$\\{[^}]+\\}/g, // ${var}\n /\\{\\{[^}]+\\}\\}/g, // {{var}}\n /\\[\\[[^\\]]+\\]\\]/g, // [[var]]\n /\\[[A-Z][A-Z0-9_\\s]*\\]/g, // [VAR]\n ];\n \n let count = 0;\n for (const pattern of patterns) {\n const matches = text.match(pattern);\n if (matches) count += matches.length;\n }\n \n return count;\n}\n\n/**\n * Calculate quality score based on various factors\n */\nfunction calculateScore(\n stats: QualityResult['stats'],\n issues: QualityIssue[]\n): number {\n let score = 1.0;\n \n // Deduct for errors\n const errors = issues.filter(i => i.type === 'error').length;\n const warnings = issues.filter(i => i.type === 'warning').length;\n \n score -= errors * 0.2;\n score -= warnings * 0.05;\n \n // Bonus for good structure\n if (stats.hasRole) score += 0.05;\n if (stats.hasTask) score += 0.05;\n if (stats.hasConstraints) score += 0.03;\n if (stats.hasExamples) score += 0.05;\n \n // Penalty for being too short\n if (stats.wordCount < OPTIMAL_MIN_WORDS) {\n score -= 0.1 * (1 - stats.wordCount / OPTIMAL_MIN_WORDS);\n }\n \n // Slight penalty for being very long\n if (stats.wordCount > OPTIMAL_MAX_WORDS) {\n score -= 0.05;\n }\n \n // Bonus for having variables (indicates reusability)\n if (stats.variableCount > 0) {\n score += 0.05;\n }\n \n return Math.max(0, Math.min(1, score));\n}\n\n/**\n * Check prompt quality locally (no API needed)\n */\nexport function check(prompt: string): QualityResult {\n const issues: QualityIssue[] = [];\n const trimmed = prompt.trim();\n \n // Basic stats\n const characterCount = trimmed.length;\n const words = trimmed.split(/\\s+/).filter(w => w.length > 0);\n const wordCount = words.length;\n const sentenceCount = (trimmed.match(/[.!?]+/g) || []).length || 1;\n const variableCount = countVariables(trimmed);\n const patterns = detectPatterns(trimmed);\n \n // Check for empty or too short\n if (characterCount === 0) {\n issues.push({\n type: 'error',\n code: 'EMPTY',\n message: 'Prompt is empty',\n });\n } else if (characterCount < MIN_CHAR_COUNT) {\n issues.push({\n type: 'error',\n code: 'TOO_SHORT',\n message: `Prompt is too short (${characterCount} chars, minimum ${MIN_CHAR_COUNT})`,\n });\n }\n \n if (wordCount > 0 && wordCount < MIN_WORD_COUNT) {\n issues.push({\n type: 'warning',\n code: 'FEW_WORDS',\n message: `Prompt has very few words (${wordCount} words, recommended ${OPTIMAL_MIN_WORDS}+)`,\n });\n }\n \n // Check for gibberish\n if (isGibberish(trimmed)) {\n issues.push({\n type: 'error',\n code: 'GIBBERISH',\n message: 'Prompt appears to contain gibberish or random characters',\n });\n }\n \n // Check for common issues\n if (!patterns.hasTask && !patterns.hasRole) {\n issues.push({\n type: 'suggestion',\n code: 'NO_CLEAR_INSTRUCTION',\n message: 'Consider adding a clear task or role definition',\n });\n }\n \n // Check for unbalanced brackets/quotes\n const brackets = [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n ];\n \n for (const { open, close } of brackets) {\n const openCount = (trimmed.match(new RegExp(`\\\\${open}`, 'g')) || []).length;\n const closeCount = (trimmed.match(new RegExp(`\\\\${close}`, 'g')) || []).length;\n \n if (openCount !== closeCount) {\n issues.push({\n type: 'warning',\n code: 'UNBALANCED_BRACKETS',\n message: `Unbalanced ${open}${close} brackets (${openCount} open, ${closeCount} close)`,\n });\n }\n }\n \n // Check for very long lines (readability)\n const lines = trimmed.split('\\n');\n const longLines = lines.filter(l => l.length > 500);\n if (longLines.length > 0) {\n issues.push({\n type: 'suggestion',\n code: 'LONG_LINES',\n message: 'Some lines are very long. Consider breaking them up for readability.',\n });\n }\n \n const stats = {\n characterCount,\n wordCount,\n sentenceCount,\n variableCount,\n ...patterns,\n };\n \n const score = calculateScore(stats, issues);\n const hasErrors = issues.some(i => i.type === 'error');\n \n return {\n valid: !hasErrors,\n score,\n issues,\n stats,\n };\n}\n\n/**\n * Validate a prompt and throw if invalid\n */\nexport function validate(prompt: string): void {\n const result = check(prompt);\n \n if (!result.valid) {\n const errors = result.issues\n .filter(i => i.type === 'error')\n .map(i => i.message)\n .join('; ');\n \n throw new Error(`Invalid prompt: ${errors}`);\n }\n}\n\n/**\n * Check if a prompt is valid\n */\nexport function isValid(prompt: string): boolean {\n return check(prompt).valid;\n}\n\n/**\n * Get suggestions for improving a prompt\n */\nexport function getSuggestions(prompt: string): string[] {\n const result = check(prompt);\n const suggestions: string[] = [];\n \n // From issues\n suggestions.push(\n ...result.issues\n .filter(i => i.type === 'suggestion' || i.type === 'warning')\n .map(i => i.message)\n );\n \n // Additional suggestions based on stats\n if (!result.stats.hasRole) {\n suggestions.push('Add a role definition (e.g., \"Act as a...\")');\n }\n \n if (!result.stats.hasConstraints && result.stats.wordCount > 50) {\n suggestions.push('Consider adding constraints or rules for better control');\n }\n \n if (!result.stats.hasExamples && result.stats.wordCount > 100) {\n suggestions.push('Adding examples can improve output quality');\n }\n \n if (result.stats.variableCount === 0 && result.stats.wordCount > 30) {\n suggestions.push('Consider adding variables (${var}) to make the prompt reusable');\n }\n \n return suggestions;\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- export { b as QualityIssue, Q as QualityResult, c as check, g as getSuggestions, a as isValid, v as validate } from '../index-CSHEKYfQ.mjs';
1
+ export { b as QualityIssue, Q as QualityResult, c as check, g as getSuggestions, a as isValid, v as validate } from '../index-CSHEKYfQ.cjs';
@@ -1,31 +1,4 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
1
  // src/quality/index.ts
21
- var quality_exports = {};
22
- __export(quality_exports, {
23
- check: () => check,
24
- getSuggestions: () => getSuggestions,
25
- isValid: () => isValid,
26
- validate: () => validate
27
- });
28
- module.exports = __toCommonJS(quality_exports);
29
2
  var MIN_CHAR_COUNT = 20;
30
3
  var MIN_WORD_COUNT = 5;
31
4
  var OPTIMAL_MIN_WORDS = 20;
@@ -202,11 +175,10 @@ function getSuggestions(prompt) {
202
175
  }
203
176
  return suggestions;
204
177
  }
205
- // Annotate the CommonJS export names for ESM import in node:
206
- 0 && (module.exports = {
178
+ export {
207
179
  check,
208
180
  getSuggestions,
209
181
  isValid,
210
182
  validate
211
- });
183
+ };
212
184
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/quality/index.ts"],"sourcesContent":["/**\n * Prompt Quality Checker - Local validation for prompt quality\n * \n * @example\n * ```ts\n * import { quality } from 'prompts.chat';\n * \n * const result = quality.check(\"Act as a developer...\");\n * console.log(result.score); // 0.85\n * console.log(result.issues); // []\n * ```\n */\n\nexport interface QualityIssue {\n type: 'error' | 'warning' | 'suggestion';\n code: string;\n message: string;\n position?: { start: number; end: number };\n}\n\nexport interface QualityResult {\n valid: boolean;\n score: number; // 0-1\n issues: QualityIssue[];\n stats: {\n characterCount: number;\n wordCount: number;\n sentenceCount: number;\n variableCount: number;\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n };\n}\n\n// Minimum thresholds\nconst MIN_CHAR_COUNT = 20;\nconst MIN_WORD_COUNT = 5;\nconst OPTIMAL_MIN_WORDS = 20;\nconst OPTIMAL_MAX_WORDS = 2000;\n\n/**\n * Check if text looks like gibberish\n */\nfunction isGibberish(text: string): boolean {\n // Check for repeated characters\n if (/(.)\\1{4,}/.test(text)) return true;\n \n // Check for keyboard patterns\n const keyboardPatterns = ['qwerty', 'asdfgh', 'zxcvbn', 'qwertz', 'azerty'];\n const lower = text.toLowerCase();\n if (keyboardPatterns.some(p => lower.includes(p))) return true;\n \n // Check consonant/vowel ratio (gibberish often has unusual ratios)\n const vowels = (text.match(/[aeiouAEIOU]/g) || []).length;\n const consonants = (text.match(/[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]/g) || []).length;\n \n if (consonants > 0 && vowels / consonants < 0.1) return true;\n \n return false;\n}\n\n/**\n * Detect common prompt patterns\n */\nfunction detectPatterns(text: string): {\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n} {\n const lower = text.toLowerCase();\n \n return {\n hasRole: /\\b(act as|you are|imagine you|pretend to be|role:|persona:)\\b/i.test(text),\n hasTask: /\\b(your task|you (will|should|must)|please|help me|i need|i want you to)\\b/i.test(text),\n hasConstraints: /\\b(do not|don't|never|always|must|should not|avoid|only|limit)\\b/i.test(text) ||\n /\\b(rule|constraint|requirement|guideline)\\b/i.test(lower),\n hasExamples: /\\b(example|for instance|such as|e\\.g\\.|like this)\\b/i.test(lower) ||\n /```[\\s\\S]*```/.test(text),\n };\n}\n\n/**\n * Count variables in the prompt\n */\nfunction countVariables(text: string): number {\n // Match various variable formats\n const patterns = [\n /\\$\\{[^}]+\\}/g, // ${var}\n /\\{\\{[^}]+\\}\\}/g, // {{var}}\n /\\[\\[[^\\]]+\\]\\]/g, // [[var]]\n /\\[[A-Z][A-Z0-9_\\s]*\\]/g, // [VAR]\n ];\n \n let count = 0;\n for (const pattern of patterns) {\n const matches = text.match(pattern);\n if (matches) count += matches.length;\n }\n \n return count;\n}\n\n/**\n * Calculate quality score based on various factors\n */\nfunction calculateScore(\n stats: QualityResult['stats'],\n issues: QualityIssue[]\n): number {\n let score = 1.0;\n \n // Deduct for errors\n const errors = issues.filter(i => i.type === 'error').length;\n const warnings = issues.filter(i => i.type === 'warning').length;\n \n score -= errors * 0.2;\n score -= warnings * 0.05;\n \n // Bonus for good structure\n if (stats.hasRole) score += 0.05;\n if (stats.hasTask) score += 0.05;\n if (stats.hasConstraints) score += 0.03;\n if (stats.hasExamples) score += 0.05;\n \n // Penalty for being too short\n if (stats.wordCount < OPTIMAL_MIN_WORDS) {\n score -= 0.1 * (1 - stats.wordCount / OPTIMAL_MIN_WORDS);\n }\n \n // Slight penalty for being very long\n if (stats.wordCount > OPTIMAL_MAX_WORDS) {\n score -= 0.05;\n }\n \n // Bonus for having variables (indicates reusability)\n if (stats.variableCount > 0) {\n score += 0.05;\n }\n \n return Math.max(0, Math.min(1, score));\n}\n\n/**\n * Check prompt quality locally (no API needed)\n */\nexport function check(prompt: string): QualityResult {\n const issues: QualityIssue[] = [];\n const trimmed = prompt.trim();\n \n // Basic stats\n const characterCount = trimmed.length;\n const words = trimmed.split(/\\s+/).filter(w => w.length > 0);\n const wordCount = words.length;\n const sentenceCount = (trimmed.match(/[.!?]+/g) || []).length || 1;\n const variableCount = countVariables(trimmed);\n const patterns = detectPatterns(trimmed);\n \n // Check for empty or too short\n if (characterCount === 0) {\n issues.push({\n type: 'error',\n code: 'EMPTY',\n message: 'Prompt is empty',\n });\n } else if (characterCount < MIN_CHAR_COUNT) {\n issues.push({\n type: 'error',\n code: 'TOO_SHORT',\n message: `Prompt is too short (${characterCount} chars, minimum ${MIN_CHAR_COUNT})`,\n });\n }\n \n if (wordCount > 0 && wordCount < MIN_WORD_COUNT) {\n issues.push({\n type: 'warning',\n code: 'FEW_WORDS',\n message: `Prompt has very few words (${wordCount} words, recommended ${OPTIMAL_MIN_WORDS}+)`,\n });\n }\n \n // Check for gibberish\n if (isGibberish(trimmed)) {\n issues.push({\n type: 'error',\n code: 'GIBBERISH',\n message: 'Prompt appears to contain gibberish or random characters',\n });\n }\n \n // Check for common issues\n if (!patterns.hasTask && !patterns.hasRole) {\n issues.push({\n type: 'suggestion',\n code: 'NO_CLEAR_INSTRUCTION',\n message: 'Consider adding a clear task or role definition',\n });\n }\n \n // Check for unbalanced brackets/quotes\n const brackets = [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n ];\n \n for (const { open, close } of brackets) {\n const openCount = (trimmed.match(new RegExp(`\\\\${open}`, 'g')) || []).length;\n const closeCount = (trimmed.match(new RegExp(`\\\\${close}`, 'g')) || []).length;\n \n if (openCount !== closeCount) {\n issues.push({\n type: 'warning',\n code: 'UNBALANCED_BRACKETS',\n message: `Unbalanced ${open}${close} brackets (${openCount} open, ${closeCount} close)`,\n });\n }\n }\n \n // Check for very long lines (readability)\n const lines = trimmed.split('\\n');\n const longLines = lines.filter(l => l.length > 500);\n if (longLines.length > 0) {\n issues.push({\n type: 'suggestion',\n code: 'LONG_LINES',\n message: 'Some lines are very long. Consider breaking them up for readability.',\n });\n }\n \n const stats = {\n characterCount,\n wordCount,\n sentenceCount,\n variableCount,\n ...patterns,\n };\n \n const score = calculateScore(stats, issues);\n const hasErrors = issues.some(i => i.type === 'error');\n \n return {\n valid: !hasErrors,\n score,\n issues,\n stats,\n };\n}\n\n/**\n * Validate a prompt and throw if invalid\n */\nexport function validate(prompt: string): void {\n const result = check(prompt);\n \n if (!result.valid) {\n const errors = result.issues\n .filter(i => i.type === 'error')\n .map(i => i.message)\n .join('; ');\n \n throw new Error(`Invalid prompt: ${errors}`);\n }\n}\n\n/**\n * Check if a prompt is valid\n */\nexport function isValid(prompt: string): boolean {\n return check(prompt).valid;\n}\n\n/**\n * Get suggestions for improving a prompt\n */\nexport function getSuggestions(prompt: string): string[] {\n const result = check(prompt);\n const suggestions: string[] = [];\n \n // From issues\n suggestions.push(\n ...result.issues\n .filter(i => i.type === 'suggestion' || i.type === 'warning')\n .map(i => i.message)\n );\n \n // Additional suggestions based on stats\n if (!result.stats.hasRole) {\n suggestions.push('Add a role definition (e.g., \"Act as a...\")');\n }\n \n if (!result.stats.hasConstraints && result.stats.wordCount > 50) {\n suggestions.push('Consider adding constraints or rules for better control');\n }\n \n if (!result.stats.hasExamples && result.stats.wordCount > 100) {\n suggestions.push('Adding examples can improve output quality');\n }\n \n if (result.stats.variableCount === 0 && result.stats.wordCount > 30) {\n suggestions.push('Consider adding variables (${var}) to make the prompt reusable');\n }\n \n return suggestions;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/quality/index.ts"],"sourcesContent":["/**\n * Prompt Quality Checker - Local validation for prompt quality\n * \n * @example\n * ```ts\n * import { quality } from 'prompts.chat';\n * \n * const result = quality.check(\"Act as a developer...\");\n * console.log(result.score); // 0.85\n * console.log(result.issues); // []\n * ```\n */\n\nexport interface QualityIssue {\n type: 'error' | 'warning' | 'suggestion';\n code: string;\n message: string;\n position?: { start: number; end: number };\n}\n\nexport interface QualityResult {\n valid: boolean;\n score: number; // 0-1\n issues: QualityIssue[];\n stats: {\n characterCount: number;\n wordCount: number;\n sentenceCount: number;\n variableCount: number;\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n };\n}\n\n// Minimum thresholds\nconst MIN_CHAR_COUNT = 20;\nconst MIN_WORD_COUNT = 5;\nconst OPTIMAL_MIN_WORDS = 20;\nconst OPTIMAL_MAX_WORDS = 2000;\n\n/**\n * Check if text looks like gibberish\n */\nfunction isGibberish(text: string): boolean {\n // Check for repeated characters\n if (/(.)\\1{4,}/.test(text)) return true;\n \n // Check for keyboard patterns\n const keyboardPatterns = ['qwerty', 'asdfgh', 'zxcvbn', 'qwertz', 'azerty'];\n const lower = text.toLowerCase();\n if (keyboardPatterns.some(p => lower.includes(p))) return true;\n \n // Check consonant/vowel ratio (gibberish often has unusual ratios)\n const vowels = (text.match(/[aeiouAEIOU]/g) || []).length;\n const consonants = (text.match(/[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]/g) || []).length;\n \n if (consonants > 0 && vowels / consonants < 0.1) return true;\n \n return false;\n}\n\n/**\n * Detect common prompt patterns\n */\nfunction detectPatterns(text: string): {\n hasRole: boolean;\n hasTask: boolean;\n hasConstraints: boolean;\n hasExamples: boolean;\n} {\n const lower = text.toLowerCase();\n \n return {\n hasRole: /\\b(act as|you are|imagine you|pretend to be|role:|persona:)\\b/i.test(text),\n hasTask: /\\b(your task|you (will|should|must)|please|help me|i need|i want you to)\\b/i.test(text),\n hasConstraints: /\\b(do not|don't|never|always|must|should not|avoid|only|limit)\\b/i.test(text) ||\n /\\b(rule|constraint|requirement|guideline)\\b/i.test(lower),\n hasExamples: /\\b(example|for instance|such as|e\\.g\\.|like this)\\b/i.test(lower) ||\n /```[\\s\\S]*```/.test(text),\n };\n}\n\n/**\n * Count variables in the prompt\n */\nfunction countVariables(text: string): number {\n // Match various variable formats\n const patterns = [\n /\\$\\{[^}]+\\}/g, // ${var}\n /\\{\\{[^}]+\\}\\}/g, // {{var}}\n /\\[\\[[^\\]]+\\]\\]/g, // [[var]]\n /\\[[A-Z][A-Z0-9_\\s]*\\]/g, // [VAR]\n ];\n \n let count = 0;\n for (const pattern of patterns) {\n const matches = text.match(pattern);\n if (matches) count += matches.length;\n }\n \n return count;\n}\n\n/**\n * Calculate quality score based on various factors\n */\nfunction calculateScore(\n stats: QualityResult['stats'],\n issues: QualityIssue[]\n): number {\n let score = 1.0;\n \n // Deduct for errors\n const errors = issues.filter(i => i.type === 'error').length;\n const warnings = issues.filter(i => i.type === 'warning').length;\n \n score -= errors * 0.2;\n score -= warnings * 0.05;\n \n // Bonus for good structure\n if (stats.hasRole) score += 0.05;\n if (stats.hasTask) score += 0.05;\n if (stats.hasConstraints) score += 0.03;\n if (stats.hasExamples) score += 0.05;\n \n // Penalty for being too short\n if (stats.wordCount < OPTIMAL_MIN_WORDS) {\n score -= 0.1 * (1 - stats.wordCount / OPTIMAL_MIN_WORDS);\n }\n \n // Slight penalty for being very long\n if (stats.wordCount > OPTIMAL_MAX_WORDS) {\n score -= 0.05;\n }\n \n // Bonus for having variables (indicates reusability)\n if (stats.variableCount > 0) {\n score += 0.05;\n }\n \n return Math.max(0, Math.min(1, score));\n}\n\n/**\n * Check prompt quality locally (no API needed)\n */\nexport function check(prompt: string): QualityResult {\n const issues: QualityIssue[] = [];\n const trimmed = prompt.trim();\n \n // Basic stats\n const characterCount = trimmed.length;\n const words = trimmed.split(/\\s+/).filter(w => w.length > 0);\n const wordCount = words.length;\n const sentenceCount = (trimmed.match(/[.!?]+/g) || []).length || 1;\n const variableCount = countVariables(trimmed);\n const patterns = detectPatterns(trimmed);\n \n // Check for empty or too short\n if (characterCount === 0) {\n issues.push({\n type: 'error',\n code: 'EMPTY',\n message: 'Prompt is empty',\n });\n } else if (characterCount < MIN_CHAR_COUNT) {\n issues.push({\n type: 'error',\n code: 'TOO_SHORT',\n message: `Prompt is too short (${characterCount} chars, minimum ${MIN_CHAR_COUNT})`,\n });\n }\n \n if (wordCount > 0 && wordCount < MIN_WORD_COUNT) {\n issues.push({\n type: 'warning',\n code: 'FEW_WORDS',\n message: `Prompt has very few words (${wordCount} words, recommended ${OPTIMAL_MIN_WORDS}+)`,\n });\n }\n \n // Check for gibberish\n if (isGibberish(trimmed)) {\n issues.push({\n type: 'error',\n code: 'GIBBERISH',\n message: 'Prompt appears to contain gibberish or random characters',\n });\n }\n \n // Check for common issues\n if (!patterns.hasTask && !patterns.hasRole) {\n issues.push({\n type: 'suggestion',\n code: 'NO_CLEAR_INSTRUCTION',\n message: 'Consider adding a clear task or role definition',\n });\n }\n \n // Check for unbalanced brackets/quotes\n const brackets = [\n { open: '{', close: '}' },\n { open: '[', close: ']' },\n { open: '(', close: ')' },\n ];\n \n for (const { open, close } of brackets) {\n const openCount = (trimmed.match(new RegExp(`\\\\${open}`, 'g')) || []).length;\n const closeCount = (trimmed.match(new RegExp(`\\\\${close}`, 'g')) || []).length;\n \n if (openCount !== closeCount) {\n issues.push({\n type: 'warning',\n code: 'UNBALANCED_BRACKETS',\n message: `Unbalanced ${open}${close} brackets (${openCount} open, ${closeCount} close)`,\n });\n }\n }\n \n // Check for very long lines (readability)\n const lines = trimmed.split('\\n');\n const longLines = lines.filter(l => l.length > 500);\n if (longLines.length > 0) {\n issues.push({\n type: 'suggestion',\n code: 'LONG_LINES',\n message: 'Some lines are very long. Consider breaking them up for readability.',\n });\n }\n \n const stats = {\n characterCount,\n wordCount,\n sentenceCount,\n variableCount,\n ...patterns,\n };\n \n const score = calculateScore(stats, issues);\n const hasErrors = issues.some(i => i.type === 'error');\n \n return {\n valid: !hasErrors,\n score,\n issues,\n stats,\n };\n}\n\n/**\n * Validate a prompt and throw if invalid\n */\nexport function validate(prompt: string): void {\n const result = check(prompt);\n \n if (!result.valid) {\n const errors = result.issues\n .filter(i => i.type === 'error')\n .map(i => i.message)\n .join('; ');\n \n throw new Error(`Invalid prompt: ${errors}`);\n }\n}\n\n/**\n * Check if a prompt is valid\n */\nexport function isValid(prompt: string): boolean {\n return check(prompt).valid;\n}\n\n/**\n * Get suggestions for improving a prompt\n */\nexport function getSuggestions(prompt: string): string[] {\n const result = check(prompt);\n const suggestions: string[] = [];\n \n // From issues\n suggestions.push(\n ...result.issues\n .filter(i => i.type === 'suggestion' || i.type === 'warning')\n .map(i => i.message)\n );\n \n // Additional suggestions based on stats\n if (!result.stats.hasRole) {\n suggestions.push('Add a role definition (e.g., \"Act as a...\")');\n }\n \n if (!result.stats.hasConstraints && result.stats.wordCount > 50) {\n suggestions.push('Consider adding constraints or rules for better control');\n }\n \n if (!result.stats.hasExamples && result.stats.wordCount > 100) {\n suggestions.push('Adding examples can improve output quality');\n }\n \n if (result.stats.variableCount === 0 && result.stats.wordCount > 30) {\n suggestions.push('Consider adding variables (${var}) to make the prompt reusable');\n }\n \n return suggestions;\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,35 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
1
20
  // src/similarity/index.ts
21
+ var similarity_exports = {};
22
+ __export(similarity_exports, {
23
+ calculate: () => calculate,
24
+ calculateSimilarity: () => calculateSimilarity,
25
+ deduplicate: () => deduplicate,
26
+ findDuplicates: () => findDuplicates,
27
+ getContentFingerprint: () => getContentFingerprint,
28
+ isDuplicate: () => isDuplicate,
29
+ isSimilarContent: () => isSimilarContent,
30
+ normalizeContent: () => normalizeContent
31
+ });
32
+ module.exports = __toCommonJS(similarity_exports);
2
33
  function normalizeContent(content) {
3
34
  return content.replace(/\$\{[^}]+\}/g, "").replace(/\[[^\]]+\]/g, "").replace(/<[^>]+>/g, "").toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, " ").trim();
4
35
  }
@@ -78,7 +109,8 @@ function deduplicate(prompts, threshold = 0.85) {
78
109
  }
79
110
  return result;
80
111
  }
81
- export {
112
+ // Annotate the CommonJS export names for ESM import in node:
113
+ 0 && (module.exports = {
82
114
  calculate,
83
115
  calculateSimilarity,
84
116
  deduplicate,
@@ -87,5 +119,5 @@ export {
87
119
  isDuplicate,
88
120
  isSimilarContent,
89
121
  normalizeContent
90
- };
91
- //# sourceMappingURL=index.mjs.map
122
+ });
123
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/similarity/index.ts"],"sourcesContent":["/**\n * Content similarity utilities for duplicate detection\n */\n\n/**\n * Normalize content for comparison by:\n * - Removing variables (${...} patterns)\n * - Converting to lowercase\n * - Removing extra whitespace\n * - Removing punctuation\n */\nexport function normalizeContent(content: string): string {\n return content\n // Remove variables like ${variable} or ${variable:default}\n .replace(/\\$\\{[^}]+\\}/g, \"\")\n // Remove common placeholder patterns like [placeholder] or <placeholder>\n .replace(/\\[[^\\]]+\\]/g, \"\")\n .replace(/<[^>]+>/g, \"\")\n // Convert to lowercase\n .toLowerCase()\n // Remove punctuation\n .replace(/[^\\w\\s]/g, \"\")\n // Normalize whitespace\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Calculate Jaccard similarity between two strings\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nfunction jaccardSimilarity(str1: string, str2: string): number {\n const set1 = new Set(str1.split(\" \").filter(Boolean));\n const set2 = new Set(str2.split(\" \").filter(Boolean));\n \n if (set1.size === 0 && set2.size === 0) return 1;\n if (set1.size === 0 || set2.size === 0) return 0;\n \n const intersection = new Set([...set1].filter(x => set2.has(x)));\n const union = new Set([...set1, ...set2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Calculate n-gram similarity for better sequence matching\n * Uses trigrams (3-character sequences) by default\n */\nfunction ngramSimilarity(str1: string, str2: string, n: number = 3): number {\n const getNgrams = (str: string): Set<string> => {\n const ngrams = new Set<string>();\n const padded = \" \".repeat(n - 1) + str + \" \".repeat(n - 1);\n for (let i = 0; i <= padded.length - n; i++) {\n ngrams.add(padded.slice(i, i + n));\n }\n return ngrams;\n };\n \n const ngrams1 = getNgrams(str1);\n const ngrams2 = getNgrams(str2);\n \n if (ngrams1.size === 0 && ngrams2.size === 0) return 1;\n if (ngrams1.size === 0 || ngrams2.size === 0) return 0;\n \n const intersection = new Set([...ngrams1].filter(x => ngrams2.has(x)));\n const union = new Set([...ngrams1, ...ngrams2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Combined similarity score using multiple algorithms\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nexport function calculateSimilarity(content1: string, content2: string): number {\n const normalized1 = normalizeContent(content1);\n const normalized2 = normalizeContent(content2);\n \n // Exact match after normalization\n if (normalized1 === normalized2) return 1;\n \n // Empty content edge case\n if (!normalized1 || !normalized2) return 0;\n \n // Combine Jaccard (word-level) and n-gram (character-level) similarities\n const jaccard = jaccardSimilarity(normalized1, normalized2);\n const ngram = ngramSimilarity(normalized1, normalized2);\n \n // Weighted average: 60% Jaccard (word overlap), 40% n-gram (sequence similarity)\n return jaccard * 0.6 + ngram * 0.4;\n}\n\n/**\n * Alias for calculateSimilarity\n */\nexport const calculate = calculateSimilarity;\n\n/**\n * Check if two contents are similar enough to be considered duplicates\n * Default threshold is 0.85 (85% similar)\n */\nexport function isSimilarContent(\n content1: string, \n content2: string, \n threshold: number = 0.85\n): boolean {\n return calculateSimilarity(content1, content2) >= threshold;\n}\n\n/**\n * Alias for isSimilarContent\n */\nexport const isDuplicate = isSimilarContent;\n\n/**\n * Get normalized content hash for database indexing/comparison\n * This is a simple hash for quick lookups before full similarity check\n */\nexport function getContentFingerprint(content: string): string {\n const normalized = normalizeContent(content);\n // Take first 500 chars of normalized content as fingerprint\n return normalized.slice(0, 500);\n}\n\n/**\n * Find duplicates in an array of prompts\n * Returns groups of similar prompts\n */\nexport function findDuplicates<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[][] {\n const groups: T[][] = [];\n const used = new Set<number>();\n\n for (let i = 0; i < prompts.length; i++) {\n if (used.has(i)) continue;\n\n const group: T[] = [prompts[i]];\n used.add(i);\n\n for (let j = i + 1; j < prompts.length; j++) {\n if (used.has(j)) continue;\n\n if (isSimilarContent(prompts[i].content, prompts[j].content, threshold)) {\n group.push(prompts[j]);\n used.add(j);\n }\n }\n\n if (group.length > 1) {\n groups.push(group);\n }\n }\n\n return groups;\n}\n\n/**\n * Deduplicate an array of prompts, keeping the first occurrence\n */\nexport function deduplicate<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[] {\n const result: T[] = [];\n\n for (const prompt of prompts) {\n const isDupe = result.some(existing => \n isSimilarContent(existing.content, prompt.content, threshold)\n );\n\n if (!isDupe) {\n result.push(prompt);\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/similarity/index.ts"],"sourcesContent":["/**\n * Content similarity utilities for duplicate detection\n */\n\n/**\n * Normalize content for comparison by:\n * - Removing variables (${...} patterns)\n * - Converting to lowercase\n * - Removing extra whitespace\n * - Removing punctuation\n */\nexport function normalizeContent(content: string): string {\n return content\n // Remove variables like ${variable} or ${variable:default}\n .replace(/\\$\\{[^}]+\\}/g, \"\")\n // Remove common placeholder patterns like [placeholder] or <placeholder>\n .replace(/\\[[^\\]]+\\]/g, \"\")\n .replace(/<[^>]+>/g, \"\")\n // Convert to lowercase\n .toLowerCase()\n // Remove punctuation\n .replace(/[^\\w\\s]/g, \"\")\n // Normalize whitespace\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Calculate Jaccard similarity between two strings\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nfunction jaccardSimilarity(str1: string, str2: string): number {\n const set1 = new Set(str1.split(\" \").filter(Boolean));\n const set2 = new Set(str2.split(\" \").filter(Boolean));\n \n if (set1.size === 0 && set2.size === 0) return 1;\n if (set1.size === 0 || set2.size === 0) return 0;\n \n const intersection = new Set([...set1].filter(x => set2.has(x)));\n const union = new Set([...set1, ...set2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Calculate n-gram similarity for better sequence matching\n * Uses trigrams (3-character sequences) by default\n */\nfunction ngramSimilarity(str1: string, str2: string, n: number = 3): number {\n const getNgrams = (str: string): Set<string> => {\n const ngrams = new Set<string>();\n const padded = \" \".repeat(n - 1) + str + \" \".repeat(n - 1);\n for (let i = 0; i <= padded.length - n; i++) {\n ngrams.add(padded.slice(i, i + n));\n }\n return ngrams;\n };\n \n const ngrams1 = getNgrams(str1);\n const ngrams2 = getNgrams(str2);\n \n if (ngrams1.size === 0 && ngrams2.size === 0) return 1;\n if (ngrams1.size === 0 || ngrams2.size === 0) return 0;\n \n const intersection = new Set([...ngrams1].filter(x => ngrams2.has(x)));\n const union = new Set([...ngrams1, ...ngrams2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Combined similarity score using multiple algorithms\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nexport function calculateSimilarity(content1: string, content2: string): number {\n const normalized1 = normalizeContent(content1);\n const normalized2 = normalizeContent(content2);\n \n // Exact match after normalization\n if (normalized1 === normalized2) return 1;\n \n // Empty content edge case\n if (!normalized1 || !normalized2) return 0;\n \n // Combine Jaccard (word-level) and n-gram (character-level) similarities\n const jaccard = jaccardSimilarity(normalized1, normalized2);\n const ngram = ngramSimilarity(normalized1, normalized2);\n \n // Weighted average: 60% Jaccard (word overlap), 40% n-gram (sequence similarity)\n return jaccard * 0.6 + ngram * 0.4;\n}\n\n/**\n * Alias for calculateSimilarity\n */\nexport const calculate = calculateSimilarity;\n\n/**\n * Check if two contents are similar enough to be considered duplicates\n * Default threshold is 0.85 (85% similar)\n */\nexport function isSimilarContent(\n content1: string, \n content2: string, \n threshold: number = 0.85\n): boolean {\n return calculateSimilarity(content1, content2) >= threshold;\n}\n\n/**\n * Alias for isSimilarContent\n */\nexport const isDuplicate = isSimilarContent;\n\n/**\n * Get normalized content hash for database indexing/comparison\n * This is a simple hash for quick lookups before full similarity check\n */\nexport function getContentFingerprint(content: string): string {\n const normalized = normalizeContent(content);\n // Take first 500 chars of normalized content as fingerprint\n return normalized.slice(0, 500);\n}\n\n/**\n * Find duplicates in an array of prompts\n * Returns groups of similar prompts\n */\nexport function findDuplicates<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[][] {\n const groups: T[][] = [];\n const used = new Set<number>();\n\n for (let i = 0; i < prompts.length; i++) {\n if (used.has(i)) continue;\n\n const group: T[] = [prompts[i]];\n used.add(i);\n\n for (let j = i + 1; j < prompts.length; j++) {\n if (used.has(j)) continue;\n\n if (isSimilarContent(prompts[i].content, prompts[j].content, threshold)) {\n group.push(prompts[j]);\n used.add(j);\n }\n }\n\n if (group.length > 1) {\n groups.push(group);\n }\n }\n\n return groups;\n}\n\n/**\n * Deduplicate an array of prompts, keeping the first occurrence\n */\nexport function deduplicate<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[] {\n const result: T[] = [];\n\n for (const prompt of prompts) {\n const isDupe = result.some(existing => \n isSimilarContent(existing.content, prompt.content, threshold)\n );\n\n if (!isDupe) {\n result.push(prompt);\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- export { b as calculate, c as calculateSimilarity, d as deduplicate, f as findDuplicates, g as getContentFingerprint, e as isDuplicate, a as isSimilarContent, n as normalizeContent } from '../index-BEIO8LCd.mjs';
1
+ export { b as calculate, c as calculateSimilarity, d as deduplicate, f as findDuplicates, g as getContentFingerprint, e as isDuplicate, a as isSimilarContent, n as normalizeContent } from '../index-BEIO8LCd.cjs';