@quilltap/plugin-utils 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/roleplay-templates/index.ts","../../src/roleplay-templates/builder.ts"],"sourcesContent":["/**\n * Roleplay Template Plugin utilities\n *\n * Provides helper functions for creating and validating roleplay template plugins.\n *\n * @module @quilltap/plugin-utils/roleplay-templates\n */\n\nexport {\n // Builder functions\n createRoleplayTemplatePlugin,\n createSingleTemplatePlugin,\n\n // Validation utilities\n validateTemplateConfig,\n validateRoleplayTemplatePlugin,\n} from './builder';\n\nexport type {\n // Builder option types\n CreateRoleplayTemplatePluginOptions,\n CreateSingleTemplatePluginOptions,\n} from './builder';\n\n// Re-export types from plugin-types for convenience\nexport type {\n RoleplayTemplateConfig,\n RoleplayTemplateMetadata,\n RoleplayTemplatePlugin,\n RoleplayTemplatePluginExport,\n} from '@quilltap/plugin-types';\n","/**\n * Roleplay Template Plugin Builder utilities\n *\n * Provides helper functions for creating and validating roleplay template plugins.\n *\n * @module @quilltap/plugin-utils/roleplay-templates\n */\n\nimport type {\n RoleplayTemplateConfig,\n RoleplayTemplateMetadata,\n RoleplayTemplatePlugin,\n} from '@quilltap/plugin-types';\n\n// ============================================================================\n// BUILDER OPTIONS\n// ============================================================================\n\n/**\n * Options for creating a roleplay template plugin\n */\nexport interface CreateRoleplayTemplatePluginOptions {\n /** Plugin metadata */\n metadata: RoleplayTemplateMetadata;\n\n /**\n * One or more roleplay templates.\n * Pass a single template object or an array of templates.\n */\n templates: RoleplayTemplateConfig | RoleplayTemplateConfig[];\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n/**\n * Simplified options for plugins that provide a single template\n */\nexport interface CreateSingleTemplatePluginOptions {\n /** Unique template identifier (lowercase, hyphens allowed) */\n templateId: string;\n\n /** Human-readable display name */\n displayName: string;\n\n /** Template description */\n description?: string;\n\n /**\n * The system prompt that defines the formatting rules.\n * This is prepended to character system prompts when the template is active.\n */\n systemPrompt: string;\n\n /** Template author */\n author?: string | {\n name: string;\n email?: string;\n url?: string;\n };\n\n /** Tags for categorization and searchability */\n tags?: string[];\n\n /** Template version */\n version?: string;\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n// ============================================================================\n// BUILDER FUNCTIONS\n// ============================================================================\n\n/**\n * Creates a roleplay template plugin with full control over metadata and templates.\n *\n * Use this when you want to provide multiple templates or have fine-grained\n * control over the plugin structure.\n *\n * @param options - Plugin configuration options\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createRoleplayTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createRoleplayTemplatePlugin({\n * metadata: {\n * templateId: 'my-rp-format',\n * displayName: 'My RP Format',\n * description: 'A custom roleplay formatting style',\n * },\n * templates: [\n * {\n * name: 'My RP Format',\n * description: 'Custom formatting with specific syntax',\n * systemPrompt: '[FORMATTING INSTRUCTIONS]...',\n * tags: ['custom'],\n * },\n * ],\n * });\n * ```\n */\nexport function createRoleplayTemplatePlugin(\n options: CreateRoleplayTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const { metadata, templates, initialize, enableLogging: _enableLogging = false } = options;\n\n // Normalize templates to array\n const templateArray = Array.isArray(templates) ? templates : [templates];\n\n // Validate templates\n if (templateArray.length === 0) {\n throw new Error('At least one template is required');\n }\n\n for (const template of templateArray) {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error(`Template \"${template.name}\" requires a systemPrompt`);\n }\n }\n\n // Create the plugin\n const plugin: RoleplayTemplatePlugin = {\n metadata: {\n ...metadata,\n // Ensure tags from templates are included in metadata if not already set\n tags: metadata.tags ?? Array.from(\n new Set(templateArray.flatMap(t => t.tags ?? []))\n ),\n },\n templates: templateArray,\n };\n\n // Add initialize function if provided\n if (initialize) {\n plugin.initialize = async () => {\n await initialize();\n };\n }\n\n return plugin;\n}\n\n/**\n * Creates a simple roleplay template plugin with a single template.\n *\n * This is a convenience function for the common case of a plugin\n * that provides just one roleplay template.\n *\n * @param options - Simplified plugin configuration\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createSingleTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createSingleTemplatePlugin({\n * templateId: 'quilltap-rp',\n * displayName: 'Quilltap RP',\n * description: 'Custom formatting with [actions], {thoughts}, and // OOC',\n * systemPrompt: `[FORMATTING INSTRUCTIONS]\n * 1. DIALOGUE: Write as bare text without quotes\n * 2. ACTIONS: Use [square brackets]\n * 3. THOUGHTS: Use {curly braces}\n * 4. OOC: Use // prefix`,\n * tags: ['quilltap', 'custom'],\n * });\n * ```\n */\nexport function createSingleTemplatePlugin(\n options: CreateSingleTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const {\n templateId,\n displayName,\n description,\n systemPrompt,\n author,\n tags,\n version,\n initialize,\n enableLogging,\n } = options;\n\n return createRoleplayTemplatePlugin({\n metadata: {\n templateId,\n displayName,\n description,\n author,\n tags,\n version,\n },\n templates: {\n name: displayName,\n description,\n systemPrompt,\n tags,\n },\n initialize,\n enableLogging,\n });\n}\n\n// ============================================================================\n// VALIDATION UTILITIES\n// ============================================================================\n\n/**\n * Validates a roleplay template configuration\n *\n * @param template - The template configuration to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateTemplateConfig(template: RoleplayTemplateConfig): boolean {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n\n if (template.name.length > 100) {\n throw new Error('Template name must be 100 characters or less');\n }\n\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error('Template systemPrompt is required');\n }\n\n if (template.description && template.description.length > 500) {\n throw new Error('Template description must be 500 characters or less');\n }\n\n if (template.tags) {\n if (!Array.isArray(template.tags)) {\n throw new Error('Template tags must be an array');\n }\n for (const tag of template.tags) {\n if (typeof tag !== 'string') {\n throw new Error('All tags must be strings');\n }\n }\n }\n\n return true;\n}\n\n/**\n * Validates a complete roleplay template plugin\n *\n * @param plugin - The plugin to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateRoleplayTemplatePlugin(plugin: RoleplayTemplatePlugin): boolean {\n // Validate metadata\n if (!plugin.metadata) {\n throw new Error('Plugin metadata is required');\n }\n\n if (!plugin.metadata.templateId || plugin.metadata.templateId.trim() === '') {\n throw new Error('Plugin metadata.templateId is required');\n }\n\n if (!/^[a-z0-9-]+$/.test(plugin.metadata.templateId)) {\n throw new Error('Plugin templateId must be lowercase alphanumeric with hyphens only');\n }\n\n if (!plugin.metadata.displayName || plugin.metadata.displayName.trim() === '') {\n throw new Error('Plugin metadata.displayName is required');\n }\n\n // Validate templates\n if (!plugin.templates || !Array.isArray(plugin.templates) || plugin.templates.length === 0) {\n throw new Error('Plugin must have at least one template');\n }\n\n for (const template of plugin.templates) {\n validateTemplateConfig(template);\n }\n\n return true;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/roleplay-templates/index.ts","../../src/roleplay-templates/builder.ts"],"sourcesContent":["/**\n * Roleplay Template Plugin utilities\n *\n * Provides helper functions for creating and validating roleplay template plugins.\n *\n * @module @quilltap/plugin-utils/roleplay-templates\n */\n\nexport {\n // Builder functions\n createRoleplayTemplatePlugin,\n createSingleTemplatePlugin,\n\n // Validation utilities\n validateTemplateConfig,\n validateRoleplayTemplatePlugin,\n} from './builder';\n\nexport type {\n // Builder option types\n CreateRoleplayTemplatePluginOptions,\n CreateSingleTemplatePluginOptions,\n} from './builder';\n\n// Re-export types from plugin-types for convenience\nexport type {\n RoleplayTemplateConfig,\n RoleplayTemplateMetadata,\n RoleplayTemplatePlugin,\n RoleplayTemplatePluginExport,\n} from '@quilltap/plugin-types';\n","/**\n * Roleplay Template Plugin Builder utilities\n *\n * Provides helper functions for creating and validating roleplay template plugins.\n *\n * @module @quilltap/plugin-utils/roleplay-templates\n */\n\nimport type {\n NarrationDelimiters,\n RoleplayTemplateConfig,\n RoleplayTemplateMetadata,\n RoleplayTemplatePlugin,\n} from '@quilltap/plugin-types';\n\n// ============================================================================\n// BUILDER OPTIONS\n// ============================================================================\n\n/**\n * Options for creating a roleplay template plugin\n */\nexport interface CreateRoleplayTemplatePluginOptions {\n /** Plugin metadata */\n metadata: RoleplayTemplateMetadata;\n\n /**\n * One or more roleplay templates.\n * Pass a single template object or an array of templates.\n */\n templates: RoleplayTemplateConfig | RoleplayTemplateConfig[];\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n/**\n * Simplified options for plugins that provide a single template\n */\nexport interface CreateSingleTemplatePluginOptions {\n /** Unique template identifier (lowercase, hyphens allowed) */\n templateId: string;\n\n /** Human-readable display name */\n displayName: string;\n\n /** Template description */\n description?: string;\n\n /**\n * The system prompt that defines the formatting rules.\n * This is prepended to character system prompts when the template is active.\n */\n systemPrompt: string;\n\n /** Template author */\n author?: string | {\n name: string;\n email?: string;\n url?: string;\n };\n\n /** Tags for categorization and searchability */\n tags?: string[];\n\n /**\n * Narration delimiters — required.\n * Single string (same open/close, e.g., '*') or [open, close] tuple (e.g., ['[', ']']).\n */\n narrationDelimiters: NarrationDelimiters;\n\n /** Template version */\n version?: string;\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n// ============================================================================\n// BUILDER FUNCTIONS\n// ============================================================================\n\n/**\n * Creates a roleplay template plugin with full control over metadata and templates.\n *\n * Use this when you want to provide multiple templates or have fine-grained\n * control over the plugin structure.\n *\n * @param options - Plugin configuration options\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createRoleplayTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createRoleplayTemplatePlugin({\n * metadata: {\n * templateId: 'my-rp-format',\n * displayName: 'My RP Format',\n * description: 'A custom roleplay formatting style',\n * },\n * templates: [\n * {\n * name: 'My RP Format',\n * description: 'Custom formatting with specific syntax',\n * systemPrompt: '[FORMATTING INSTRUCTIONS]...',\n * tags: ['custom'],\n * },\n * ],\n * });\n * ```\n */\nexport function createRoleplayTemplatePlugin(\n options: CreateRoleplayTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const { metadata, templates, initialize, enableLogging: _enableLogging = false } = options;\n\n // Normalize templates to array\n const templateArray = Array.isArray(templates) ? templates : [templates];\n\n // Validate templates\n if (templateArray.length === 0) {\n throw new Error('At least one template is required');\n }\n\n for (const template of templateArray) {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error(`Template \"${template.name}\" requires a systemPrompt`);\n }\n }\n\n // Create the plugin\n const plugin: RoleplayTemplatePlugin = {\n metadata: {\n ...metadata,\n // Ensure tags from templates are included in metadata if not already set\n tags: metadata.tags ?? Array.from(\n new Set(templateArray.flatMap(t => t.tags ?? []))\n ),\n },\n templates: templateArray,\n };\n\n // Add initialize function if provided\n if (initialize) {\n plugin.initialize = async () => {\n await initialize();\n };\n }\n\n return plugin;\n}\n\n/**\n * Creates a simple roleplay template plugin with a single template.\n *\n * This is a convenience function for the common case of a plugin\n * that provides just one roleplay template.\n *\n * @param options - Simplified plugin configuration\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createSingleTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createSingleTemplatePlugin({\n * templateId: 'quilltap-rp',\n * displayName: 'Quilltap RP',\n * description: 'Custom formatting with [actions], {thoughts}, and // OOC',\n * systemPrompt: `[FORMATTING INSTRUCTIONS]\n * 1. DIALOGUE: Write as bare text without quotes\n * 2. ACTIONS: Use [square brackets]\n * 3. THOUGHTS: Use {curly braces}\n * 4. OOC: Use // prefix`,\n * tags: ['quilltap', 'custom'],\n * });\n * ```\n */\nexport function createSingleTemplatePlugin(\n options: CreateSingleTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const {\n templateId,\n displayName,\n description,\n systemPrompt,\n author,\n tags,\n narrationDelimiters,\n version,\n initialize,\n enableLogging,\n } = options;\n\n return createRoleplayTemplatePlugin({\n metadata: {\n templateId,\n displayName,\n description,\n author,\n tags,\n version,\n },\n templates: {\n name: displayName,\n description,\n systemPrompt,\n tags,\n narrationDelimiters,\n },\n initialize,\n enableLogging,\n });\n}\n\n// ============================================================================\n// VALIDATION UTILITIES\n// ============================================================================\n\n/**\n * Validates a roleplay template configuration\n *\n * @param template - The template configuration to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateTemplateConfig(template: RoleplayTemplateConfig): boolean {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n\n if (template.name.length > 100) {\n throw new Error('Template name must be 100 characters or less');\n }\n\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error('Template systemPrompt is required');\n }\n\n if (template.description && template.description.length > 500) {\n throw new Error('Template description must be 500 characters or less');\n }\n\n if (template.tags) {\n if (!Array.isArray(template.tags)) {\n throw new Error('Template tags must be an array');\n }\n for (const tag of template.tags) {\n if (typeof tag !== 'string') {\n throw new Error('All tags must be strings');\n }\n }\n }\n\n // Validate narrationDelimiters (required)\n if (!template.narrationDelimiters) {\n throw new Error('Template narrationDelimiters is required');\n }\n if (typeof template.narrationDelimiters === 'string') {\n if (template.narrationDelimiters.length === 0) {\n throw new Error('Template narrationDelimiters string must not be empty');\n }\n } else if (Array.isArray(template.narrationDelimiters)) {\n if (template.narrationDelimiters.length !== 2) {\n throw new Error('Template narrationDelimiters array must have exactly 2 elements [open, close]');\n }\n if (!template.narrationDelimiters[0] || !template.narrationDelimiters[1]) {\n throw new Error('Template narrationDelimiters array elements must not be empty');\n }\n } else {\n throw new Error('Template narrationDelimiters must be a string or [string, string] tuple');\n }\n\n return true;\n}\n\n/**\n * Validates a complete roleplay template plugin\n *\n * @param plugin - The plugin to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateRoleplayTemplatePlugin(plugin: RoleplayTemplatePlugin): boolean {\n // Validate metadata\n if (!plugin.metadata) {\n throw new Error('Plugin metadata is required');\n }\n\n if (!plugin.metadata.templateId || plugin.metadata.templateId.trim() === '') {\n throw new Error('Plugin metadata.templateId is required');\n }\n\n if (!/^[a-z0-9-]+$/.test(plugin.metadata.templateId)) {\n throw new Error('Plugin templateId must be lowercase alphanumeric with hyphens only');\n }\n\n if (!plugin.metadata.displayName || plugin.metadata.displayName.trim() === '') {\n throw new Error('Plugin metadata.displayName is required');\n }\n\n // Validate templates\n if (!plugin.templates || !Array.isArray(plugin.templates) || plugin.templates.length === 0) {\n throw new Error('Plugin must have at least one template');\n }\n\n for (const template of plugin.templates) {\n validateTemplateConfig(template);\n }\n\n return true;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACkIO,SAAS,6BACd,SACwB;AACxB,QAAM,EAAE,UAAU,WAAW,YAAY,eAAe,iBAAiB,MAAM,IAAI;AAGnF,QAAM,gBAAgB,MAAM,QAAQ,SAAS,IAAI,YAAY,CAAC,SAAS;AAGvE,MAAI,cAAc,WAAW,GAAG;AAC9B,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,aAAW,YAAY,eAAe;AACpC,QAAI,CAAC,SAAS,QAAQ,SAAS,KAAK,KAAK,MAAM,IAAI;AACjD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AACA,QAAI,CAAC,SAAS,gBAAgB,SAAS,aAAa,KAAK,MAAM,IAAI;AACjE,YAAM,IAAI,MAAM,aAAa,SAAS,IAAI,2BAA2B;AAAA,IACvE;AAAA,EACF;AAGA,QAAM,SAAiC;AAAA,IACrC,UAAU;AAAA,MACR,GAAG;AAAA;AAAA,MAEH,MAAM,SAAS,QAAQ,MAAM;AAAA,QAC3B,IAAI,IAAI,cAAc,QAAQ,OAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,IACA,WAAW;AAAA,EACb;AAGA,MAAI,YAAY;AACd,WAAO,aAAa,YAAY;AAC9B,YAAM,WAAW;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AA4BO,SAAS,2BACd,SACwB;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,SAAO,6BAA6B;AAAA,IAClC,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAYO,SAAS,uBAAuB,UAA2C;AAChF,MAAI,CAAC,SAAS,QAAQ,SAAS,KAAK,KAAK,MAAM,IAAI;AACjD,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AAEA,MAAI,SAAS,KAAK,SAAS,KAAK;AAC9B,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAEA,MAAI,CAAC,SAAS,gBAAgB,SAAS,aAAa,KAAK,MAAM,IAAI;AACjE,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,MAAI,SAAS,eAAe,SAAS,YAAY,SAAS,KAAK;AAC7D,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,MAAI,SAAS,MAAM;AACjB,QAAI,CAAC,MAAM,QAAQ,SAAS,IAAI,GAAG;AACjC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,eAAW,OAAO,SAAS,MAAM;AAC/B,UAAI,OAAO,QAAQ,UAAU;AAC3B,cAAM,IAAI,MAAM,0BAA0B;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,SAAS,qBAAqB;AACjC,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,MAAI,OAAO,SAAS,wBAAwB,UAAU;AACpD,QAAI,SAAS,oBAAoB,WAAW,GAAG;AAC7C,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AAAA,EACF,WAAW,MAAM,QAAQ,SAAS,mBAAmB,GAAG;AACtD,QAAI,SAAS,oBAAoB,WAAW,GAAG;AAC7C,YAAM,IAAI,MAAM,+EAA+E;AAAA,IACjG;AACA,QAAI,CAAC,SAAS,oBAAoB,CAAC,KAAK,CAAC,SAAS,oBAAoB,CAAC,GAAG;AACxE,YAAM,IAAI,MAAM,+DAA+D;AAAA,IACjF;AAAA,EACF,OAAO;AACL,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AAEA,SAAO;AACT;AAQO,SAAS,+BAA+B,QAAyC;AAEtF,MAAI,CAAC,OAAO,UAAU;AACpB,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AAEA,MAAI,CAAC,OAAO,SAAS,cAAc,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI;AAC3E,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AAEA,MAAI,CAAC,eAAe,KAAK,OAAO,SAAS,UAAU,GAAG;AACpD,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AAEA,MAAI,CAAC,OAAO,SAAS,eAAe,OAAO,SAAS,YAAY,KAAK,MAAM,IAAI;AAC7E,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AAGA,MAAI,CAAC,OAAO,aAAa,CAAC,MAAM,QAAQ,OAAO,SAAS,KAAK,OAAO,UAAU,WAAW,GAAG;AAC1F,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AAEA,aAAW,YAAY,OAAO,WAAW;AACvC,2BAAuB,QAAQ;AAAA,EACjC;AAEA,SAAO;AACT;","names":[]}
@@ -38,6 +38,7 @@ function createSingleTemplatePlugin(options) {
38
38
  systemPrompt,
39
39
  author,
40
40
  tags,
41
+ narrationDelimiters,
41
42
  version,
42
43
  initialize,
43
44
  enableLogging
@@ -55,7 +56,8 @@ function createSingleTemplatePlugin(options) {
55
56
  name: displayName,
56
57
  description,
57
58
  systemPrompt,
58
- tags
59
+ tags,
60
+ narrationDelimiters
59
61
  },
60
62
  initialize,
61
63
  enableLogging
@@ -84,6 +86,23 @@ function validateTemplateConfig(template) {
84
86
  }
85
87
  }
86
88
  }
89
+ if (!template.narrationDelimiters) {
90
+ throw new Error("Template narrationDelimiters is required");
91
+ }
92
+ if (typeof template.narrationDelimiters === "string") {
93
+ if (template.narrationDelimiters.length === 0) {
94
+ throw new Error("Template narrationDelimiters string must not be empty");
95
+ }
96
+ } else if (Array.isArray(template.narrationDelimiters)) {
97
+ if (template.narrationDelimiters.length !== 2) {
98
+ throw new Error("Template narrationDelimiters array must have exactly 2 elements [open, close]");
99
+ }
100
+ if (!template.narrationDelimiters[0] || !template.narrationDelimiters[1]) {
101
+ throw new Error("Template narrationDelimiters array elements must not be empty");
102
+ }
103
+ } else {
104
+ throw new Error("Template narrationDelimiters must be a string or [string, string] tuple");
105
+ }
87
106
  return true;
88
107
  }
89
108
  function validateRoleplayTemplatePlugin(plugin) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/roleplay-templates/builder.ts"],"sourcesContent":["/**\n * Roleplay Template Plugin Builder utilities\n *\n * Provides helper functions for creating and validating roleplay template plugins.\n *\n * @module @quilltap/plugin-utils/roleplay-templates\n */\n\nimport type {\n RoleplayTemplateConfig,\n RoleplayTemplateMetadata,\n RoleplayTemplatePlugin,\n} from '@quilltap/plugin-types';\n\n// ============================================================================\n// BUILDER OPTIONS\n// ============================================================================\n\n/**\n * Options for creating a roleplay template plugin\n */\nexport interface CreateRoleplayTemplatePluginOptions {\n /** Plugin metadata */\n metadata: RoleplayTemplateMetadata;\n\n /**\n * One or more roleplay templates.\n * Pass a single template object or an array of templates.\n */\n templates: RoleplayTemplateConfig | RoleplayTemplateConfig[];\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n/**\n * Simplified options for plugins that provide a single template\n */\nexport interface CreateSingleTemplatePluginOptions {\n /** Unique template identifier (lowercase, hyphens allowed) */\n templateId: string;\n\n /** Human-readable display name */\n displayName: string;\n\n /** Template description */\n description?: string;\n\n /**\n * The system prompt that defines the formatting rules.\n * This is prepended to character system prompts when the template is active.\n */\n systemPrompt: string;\n\n /** Template author */\n author?: string | {\n name: string;\n email?: string;\n url?: string;\n };\n\n /** Tags for categorization and searchability */\n tags?: string[];\n\n /** Template version */\n version?: string;\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n// ============================================================================\n// BUILDER FUNCTIONS\n// ============================================================================\n\n/**\n * Creates a roleplay template plugin with full control over metadata and templates.\n *\n * Use this when you want to provide multiple templates or have fine-grained\n * control over the plugin structure.\n *\n * @param options - Plugin configuration options\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createRoleplayTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createRoleplayTemplatePlugin({\n * metadata: {\n * templateId: 'my-rp-format',\n * displayName: 'My RP Format',\n * description: 'A custom roleplay formatting style',\n * },\n * templates: [\n * {\n * name: 'My RP Format',\n * description: 'Custom formatting with specific syntax',\n * systemPrompt: '[FORMATTING INSTRUCTIONS]...',\n * tags: ['custom'],\n * },\n * ],\n * });\n * ```\n */\nexport function createRoleplayTemplatePlugin(\n options: CreateRoleplayTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const { metadata, templates, initialize, enableLogging: _enableLogging = false } = options;\n\n // Normalize templates to array\n const templateArray = Array.isArray(templates) ? templates : [templates];\n\n // Validate templates\n if (templateArray.length === 0) {\n throw new Error('At least one template is required');\n }\n\n for (const template of templateArray) {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error(`Template \"${template.name}\" requires a systemPrompt`);\n }\n }\n\n // Create the plugin\n const plugin: RoleplayTemplatePlugin = {\n metadata: {\n ...metadata,\n // Ensure tags from templates are included in metadata if not already set\n tags: metadata.tags ?? Array.from(\n new Set(templateArray.flatMap(t => t.tags ?? []))\n ),\n },\n templates: templateArray,\n };\n\n // Add initialize function if provided\n if (initialize) {\n plugin.initialize = async () => {\n await initialize();\n };\n }\n\n return plugin;\n}\n\n/**\n * Creates a simple roleplay template plugin with a single template.\n *\n * This is a convenience function for the common case of a plugin\n * that provides just one roleplay template.\n *\n * @param options - Simplified plugin configuration\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createSingleTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createSingleTemplatePlugin({\n * templateId: 'quilltap-rp',\n * displayName: 'Quilltap RP',\n * description: 'Custom formatting with [actions], {thoughts}, and // OOC',\n * systemPrompt: `[FORMATTING INSTRUCTIONS]\n * 1. DIALOGUE: Write as bare text without quotes\n * 2. ACTIONS: Use [square brackets]\n * 3. THOUGHTS: Use {curly braces}\n * 4. OOC: Use // prefix`,\n * tags: ['quilltap', 'custom'],\n * });\n * ```\n */\nexport function createSingleTemplatePlugin(\n options: CreateSingleTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const {\n templateId,\n displayName,\n description,\n systemPrompt,\n author,\n tags,\n version,\n initialize,\n enableLogging,\n } = options;\n\n return createRoleplayTemplatePlugin({\n metadata: {\n templateId,\n displayName,\n description,\n author,\n tags,\n version,\n },\n templates: {\n name: displayName,\n description,\n systemPrompt,\n tags,\n },\n initialize,\n enableLogging,\n });\n}\n\n// ============================================================================\n// VALIDATION UTILITIES\n// ============================================================================\n\n/**\n * Validates a roleplay template configuration\n *\n * @param template - The template configuration to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateTemplateConfig(template: RoleplayTemplateConfig): boolean {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n\n if (template.name.length > 100) {\n throw new Error('Template name must be 100 characters or less');\n }\n\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error('Template systemPrompt is required');\n }\n\n if (template.description && template.description.length > 500) {\n throw new Error('Template description must be 500 characters or less');\n }\n\n if (template.tags) {\n if (!Array.isArray(template.tags)) {\n throw new Error('Template tags must be an array');\n }\n for (const tag of template.tags) {\n if (typeof tag !== 'string') {\n throw new Error('All tags must be strings');\n }\n }\n }\n\n return true;\n}\n\n/**\n * Validates a complete roleplay template plugin\n *\n * @param plugin - The plugin to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateRoleplayTemplatePlugin(plugin: RoleplayTemplatePlugin): boolean {\n // Validate metadata\n if (!plugin.metadata) {\n throw new Error('Plugin metadata is required');\n }\n\n if (!plugin.metadata.templateId || plugin.metadata.templateId.trim() === '') {\n throw new Error('Plugin metadata.templateId is required');\n }\n\n if (!/^[a-z0-9-]+$/.test(plugin.metadata.templateId)) {\n throw new Error('Plugin templateId must be lowercase alphanumeric with hyphens only');\n }\n\n if (!plugin.metadata.displayName || plugin.metadata.displayName.trim() === '') {\n throw new Error('Plugin metadata.displayName is required');\n }\n\n // Validate templates\n if (!plugin.templates || !Array.isArray(plugin.templates) || plugin.templates.length === 0) {\n throw new Error('Plugin must have at least one template');\n }\n\n for (const template of plugin.templates) {\n validateTemplateConfig(template);\n }\n\n return true;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/roleplay-templates/builder.ts"],"sourcesContent":["/**\n * Roleplay Template Plugin Builder utilities\n *\n * Provides helper functions for creating and validating roleplay template plugins.\n *\n * @module @quilltap/plugin-utils/roleplay-templates\n */\n\nimport type {\n NarrationDelimiters,\n RoleplayTemplateConfig,\n RoleplayTemplateMetadata,\n RoleplayTemplatePlugin,\n} from '@quilltap/plugin-types';\n\n// ============================================================================\n// BUILDER OPTIONS\n// ============================================================================\n\n/**\n * Options for creating a roleplay template plugin\n */\nexport interface CreateRoleplayTemplatePluginOptions {\n /** Plugin metadata */\n metadata: RoleplayTemplateMetadata;\n\n /**\n * One or more roleplay templates.\n * Pass a single template object or an array of templates.\n */\n templates: RoleplayTemplateConfig | RoleplayTemplateConfig[];\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n/**\n * Simplified options for plugins that provide a single template\n */\nexport interface CreateSingleTemplatePluginOptions {\n /** Unique template identifier (lowercase, hyphens allowed) */\n templateId: string;\n\n /** Human-readable display name */\n displayName: string;\n\n /** Template description */\n description?: string;\n\n /**\n * The system prompt that defines the formatting rules.\n * This is prepended to character system prompts when the template is active.\n */\n systemPrompt: string;\n\n /** Template author */\n author?: string | {\n name: string;\n email?: string;\n url?: string;\n };\n\n /** Tags for categorization and searchability */\n tags?: string[];\n\n /**\n * Narration delimiters — required.\n * Single string (same open/close, e.g., '*') or [open, close] tuple (e.g., ['[', ']']).\n */\n narrationDelimiters: NarrationDelimiters;\n\n /** Template version */\n version?: string;\n\n /**\n * Optional initialization function.\n * Called when the plugin is loaded.\n */\n initialize?: () => void | Promise<void>;\n\n /**\n * Whether to enable debug logging.\n * Defaults to false.\n */\n enableLogging?: boolean;\n}\n\n// ============================================================================\n// BUILDER FUNCTIONS\n// ============================================================================\n\n/**\n * Creates a roleplay template plugin with full control over metadata and templates.\n *\n * Use this when you want to provide multiple templates or have fine-grained\n * control over the plugin structure.\n *\n * @param options - Plugin configuration options\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createRoleplayTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createRoleplayTemplatePlugin({\n * metadata: {\n * templateId: 'my-rp-format',\n * displayName: 'My RP Format',\n * description: 'A custom roleplay formatting style',\n * },\n * templates: [\n * {\n * name: 'My RP Format',\n * description: 'Custom formatting with specific syntax',\n * systemPrompt: '[FORMATTING INSTRUCTIONS]...',\n * tags: ['custom'],\n * },\n * ],\n * });\n * ```\n */\nexport function createRoleplayTemplatePlugin(\n options: CreateRoleplayTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const { metadata, templates, initialize, enableLogging: _enableLogging = false } = options;\n\n // Normalize templates to array\n const templateArray = Array.isArray(templates) ? templates : [templates];\n\n // Validate templates\n if (templateArray.length === 0) {\n throw new Error('At least one template is required');\n }\n\n for (const template of templateArray) {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error(`Template \"${template.name}\" requires a systemPrompt`);\n }\n }\n\n // Create the plugin\n const plugin: RoleplayTemplatePlugin = {\n metadata: {\n ...metadata,\n // Ensure tags from templates are included in metadata if not already set\n tags: metadata.tags ?? Array.from(\n new Set(templateArray.flatMap(t => t.tags ?? []))\n ),\n },\n templates: templateArray,\n };\n\n // Add initialize function if provided\n if (initialize) {\n plugin.initialize = async () => {\n await initialize();\n };\n }\n\n return plugin;\n}\n\n/**\n * Creates a simple roleplay template plugin with a single template.\n *\n * This is a convenience function for the common case of a plugin\n * that provides just one roleplay template.\n *\n * @param options - Simplified plugin configuration\n * @returns A valid RoleplayTemplatePlugin instance\n *\n * @example\n * ```typescript\n * import { createSingleTemplatePlugin } from '@quilltap/plugin-utils';\n *\n * export const plugin = createSingleTemplatePlugin({\n * templateId: 'quilltap-rp',\n * displayName: 'Quilltap RP',\n * description: 'Custom formatting with [actions], {thoughts}, and // OOC',\n * systemPrompt: `[FORMATTING INSTRUCTIONS]\n * 1. DIALOGUE: Write as bare text without quotes\n * 2. ACTIONS: Use [square brackets]\n * 3. THOUGHTS: Use {curly braces}\n * 4. OOC: Use // prefix`,\n * tags: ['quilltap', 'custom'],\n * });\n * ```\n */\nexport function createSingleTemplatePlugin(\n options: CreateSingleTemplatePluginOptions\n): RoleplayTemplatePlugin {\n const {\n templateId,\n displayName,\n description,\n systemPrompt,\n author,\n tags,\n narrationDelimiters,\n version,\n initialize,\n enableLogging,\n } = options;\n\n return createRoleplayTemplatePlugin({\n metadata: {\n templateId,\n displayName,\n description,\n author,\n tags,\n version,\n },\n templates: {\n name: displayName,\n description,\n systemPrompt,\n tags,\n narrationDelimiters,\n },\n initialize,\n enableLogging,\n });\n}\n\n// ============================================================================\n// VALIDATION UTILITIES\n// ============================================================================\n\n/**\n * Validates a roleplay template configuration\n *\n * @param template - The template configuration to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateTemplateConfig(template: RoleplayTemplateConfig): boolean {\n if (!template.name || template.name.trim() === '') {\n throw new Error('Template name is required');\n }\n\n if (template.name.length > 100) {\n throw new Error('Template name must be 100 characters or less');\n }\n\n if (!template.systemPrompt || template.systemPrompt.trim() === '') {\n throw new Error('Template systemPrompt is required');\n }\n\n if (template.description && template.description.length > 500) {\n throw new Error('Template description must be 500 characters or less');\n }\n\n if (template.tags) {\n if (!Array.isArray(template.tags)) {\n throw new Error('Template tags must be an array');\n }\n for (const tag of template.tags) {\n if (typeof tag !== 'string') {\n throw new Error('All tags must be strings');\n }\n }\n }\n\n // Validate narrationDelimiters (required)\n if (!template.narrationDelimiters) {\n throw new Error('Template narrationDelimiters is required');\n }\n if (typeof template.narrationDelimiters === 'string') {\n if (template.narrationDelimiters.length === 0) {\n throw new Error('Template narrationDelimiters string must not be empty');\n }\n } else if (Array.isArray(template.narrationDelimiters)) {\n if (template.narrationDelimiters.length !== 2) {\n throw new Error('Template narrationDelimiters array must have exactly 2 elements [open, close]');\n }\n if (!template.narrationDelimiters[0] || !template.narrationDelimiters[1]) {\n throw new Error('Template narrationDelimiters array elements must not be empty');\n }\n } else {\n throw new Error('Template narrationDelimiters must be a string or [string, string] tuple');\n }\n\n return true;\n}\n\n/**\n * Validates a complete roleplay template plugin\n *\n * @param plugin - The plugin to validate\n * @returns True if valid, throws Error if invalid\n */\nexport function validateRoleplayTemplatePlugin(plugin: RoleplayTemplatePlugin): boolean {\n // Validate metadata\n if (!plugin.metadata) {\n throw new Error('Plugin metadata is required');\n }\n\n if (!plugin.metadata.templateId || plugin.metadata.templateId.trim() === '') {\n throw new Error('Plugin metadata.templateId is required');\n }\n\n if (!/^[a-z0-9-]+$/.test(plugin.metadata.templateId)) {\n throw new Error('Plugin templateId must be lowercase alphanumeric with hyphens only');\n }\n\n if (!plugin.metadata.displayName || plugin.metadata.displayName.trim() === '') {\n throw new Error('Plugin metadata.displayName is required');\n }\n\n // Validate templates\n if (!plugin.templates || !Array.isArray(plugin.templates) || plugin.templates.length === 0) {\n throw new Error('Plugin must have at least one template');\n }\n\n for (const template of plugin.templates) {\n validateTemplateConfig(template);\n }\n\n return true;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quilltap/plugin-utils",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Utility functions for Quilltap plugin development",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -54,7 +54,7 @@
54
54
  "typecheck": "tsc --noEmit"
55
55
  },
56
56
  "dependencies": {
57
- "@quilltap/plugin-types": "^2.0.0"
57
+ "@quilltap/plugin-types": "^2.1.0"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "openai": "^4.0.0 || ^5.0.0 || ^6.0.0"
@@ -68,7 +68,7 @@
68
68
  }
69
69
  },
70
70
  "devDependencies": {
71
- "openai": "^6.33.0",
71
+ "openai": "^6.34.0",
72
72
  "tsup": "^8.5.1",
73
73
  "typescript": "^5.9.3"
74
74
  },
@@ -90,12 +90,12 @@
90
90
  "license": "MIT",
91
91
  "repository": {
92
92
  "type": "git",
93
- "url": "https://github.com/foundry-9/quilltap.git",
93
+ "url": "https://github.com/foundry-9/quilltap-server.git",
94
94
  "directory": "packages/plugin-utils"
95
95
  },
96
- "homepage": "https://github.com/foundry-9/quilltap/tree/main/packages/plugin-utils#readme",
96
+ "homepage": "https://github.com/foundry-9/quilltap-server/tree/main/packages/plugin-utils#readme",
97
97
  "bugs": {
98
- "url": "https://github.com/foundry-9/quilltap/issues"
98
+ "url": "https://github.com/foundry-9/quilltap-server/issues"
99
99
  },
100
100
  "engines": {
101
101
  "node": ">=18.0.0"