{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/reader.ts","../src/writer.ts","../src/macros.ts","../src/mapper.ts","../src/merge.ts","../src/loss.ts","../src/enricher.ts"],"sourcesContent":["/**\n * @character-foundry/voxta\n *\n * Voxta package format reader, writer, and mapper.\n */\n\n// Types\nexport type {\n  CompressionLevel,\n  VoxtaPackage,\n  VoxtaTtsConfig,\n  VoxtaScript,\n  VoxtaCharacter,\n  VoxtaBookItem,\n  VoxtaBook,\n  VoxtaAction,\n  VoxtaScenario,\n  VoxtaCollection,\n  VoxtaCollectionFolder,\n  VoxtaCollectionItem,\n  VoxtaCollectionRoot,\n  VoxtaResourceRef,\n  ExtractedVoxtaAsset,\n  ExtractedVoxtaCharacter,\n  ExtractedVoxtaScenario,\n  ExtractedVoxtaBook,\n  ExtractedVoxtaCollection,\n  VoxtaData,\n  VoxtaReadOptions,\n  VoxtaWriteAsset,\n  VoxtaWriteOptions,\n  VoxtaBuildResult,\n  VoxtaExtensionData,\n  VoxtaLossReport,\n  VoxtaExportType,\n} from './types.js';\n\nexport { VoxtaResourceKind } from './types.js';\n\n// Reader\nexport {\n  isVoxta,\n  readVoxta,\n  readVoxtaAsync,\n} from './reader.js';\n\n// Writer\nexport {\n  writeVoxta,\n  writeVoxtaAsync,\n} from './writer.js';\n\n// Mapper\nexport {\n  voxtaToCCv3,\n  ccv3ToVoxta,\n  ccv3LorebookToVoxtaBook,\n} from './mapper.js';\n\n// Macros\nexport {\n  voxtaToStandard,\n  standardToVoxta,\n} from './macros.js';\n\n// Merge utilities\nexport {\n  mergeCharacterEdits,\n  mergeBookEdits,\n  applyVoxtaDeltas,\n  applyVoxtaDeltasAsync,\n  getPackageManifest,\n  extractCharacterPackage,\n  addCharacterToPackage,\n  type CCv3Edits,\n  type VoxtaDeltas,\n  type ApplyDeltaOptions,\n  type ManifestCharacter,\n  type ManifestBook,\n  type ManifestScenario,\n  type PackageManifest,\n  type ExtractCharacterOptions,\n  type AddCharacterOptions,\n} from './merge.js';\n\n// Loss reporting\nexport {\n  checkVoxtaLoss,\n  isVoxtaExportLossless,\n  formatVoxtaLossReport,\n} from './loss.js';\n\n// Enricher\nexport {\n  enrichVoxtaAsset,\n  type EnrichedAssetMetadata,\n} from './enricher.js';\n\n","/**\n * Voxta Types\n *\n * Type definitions for Voxta package format.\n */\n\nimport type { BinaryData } from '@character-foundry/core';\n\n/**\n * Valid compression levels\n */\nexport type CompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;\n\n/**\n * Voxta resource kind enumeration\n * Used in EntryResource, ThumbnailResource, and Collection references\n */\nexport enum VoxtaResourceKind {\n  Character = 1,\n  Book = 2,\n  Scenario = 3,\n}\n\n/**\n * Voxta resource reference\n */\nexport interface VoxtaResourceRef {\n  Kind: VoxtaResourceKind | number;\n  Id: string;\n}\n\n/**\n * Voxta package metadata\n */\nexport interface VoxtaPackage {\n  $type: 'package';\n  Id: string;\n  Name: string;\n  Version: string;\n  Description?: string;\n  Creator?: string;\n  ExplicitContent?: boolean;\n  EntryResource?: VoxtaResourceRef;\n  ThumbnailResource?: VoxtaResourceRef;\n  DateCreated?: string;\n  DateModified?: string;\n}\n\n/**\n * Voxta TTS configuration\n */\nexport interface VoxtaTtsConfig {\n  Voice: {\n    parameters: {\n      VoiceBackend?: string;\n      VoiceId?: string;\n      Gender?: string;\n      Filename?: string;\n      FinetuneVoice?: string;\n      [key: string]: unknown;\n    };\n    label: string;\n  };\n  Service: {\n    ServiceName: string;\n    ServiceId: string;\n  };\n}\n\n/**\n * Voxta script\n */\nexport interface VoxtaScript {\n  Name: string;\n  Content: string;\n}\n\n/**\n * Voxta character\n */\nexport interface VoxtaCharacter {\n  $type: 'character';\n  Id: string;\n  Name: string;\n  Label?: string;           // Optional nickname/display name\n  Version?: string;\n  PackageId?: string;\n\n  // Core Info\n  Description?: string;     // Physical/visual appearance\n  Personality?: string;\n  Profile?: string;         // Profile/Backstory\n  Scenario?: string;\n  FirstMessage?: string;\n  AlternativeFirstMessages?: string[]; // Alternate greetings (maps to CCv3 alternate_greetings)\n  MessageExamples?: string;\n\n  // System prompts\n  SystemPrompt?: string;           // System prompt (additive)\n  PostHistoryInstructions?: string; // UJB - added at end of messages\n  Context?: string;                // Context field\n  Instructions?: string;           // User instructions (not read by LLM)\n\n  // Persona overrides\n  UserNameOverride?: string;\n  UserDescriptionOverride?: string;\n\n  // Metadata\n  Creator?: string;\n  CreatorNotes?: string;\n  Tags?: string[];\n  ExplicitContent?: boolean;\n  Culture?: string;\n  ImportedFrom?: string;    // Source tracking\n\n  // References\n  MemoryBooks?: string[];\n  DefaultScenarios?: string[];\n\n  // TTS\n  TextToSpeech?: VoxtaTtsConfig[];\n\n  // AI Settings\n  ChatStyle?: number;\n  EnableThinkingSpeech?: boolean;\n  NotifyUserAwayReturn?: boolean;\n  TimeAware?: boolean;\n  UseMemory?: boolean;\n  MaxTokens?: number;\n  MaxSentences?: number;\n  SystemPromptOverrideType?: number;\n\n  // Simulation Settings\n  ClimaxSensitivity?: number;\n  PleasureDecay?: number;\n\n  // Advanced\n  Scripts?: VoxtaScript[];\n  Augmentations?: unknown[];\n\n  Thumbnail?: {\n    RandomizedETag?: string;\n    ContentType?: string;\n  };\n\n  DateCreated?: string;   // ISO timestamp\n  DateModified?: string;  // ISO timestamp\n}\n\n/**\n * Voxta book item\n */\nexport interface VoxtaBookItem {\n  Id: string;\n  Keywords: string[];\n  Text: string;\n  Weight?: number;\n  Deleted?: boolean;\n  CreatedAt?: string;\n  LastUpdated?: string;\n  DeletedAt?: string;\n}\n\n/**\n * Voxta book (lorebook)\n */\nexport interface VoxtaBook {\n  $type: 'book';\n  Id: string;\n  Name: string;\n  Version?: string;\n  PackageId?: string;\n  Description?: string;\n  ExplicitContent?: boolean;\n  Creator?: string;\n  Items: VoxtaBookItem[];\n  DateCreated?: string;\n  DateModified?: string;\n}\n\n/**\n * Voxta collection item (reference to a resource)\n */\nexport interface VoxtaCollectionItem {\n  Resource: VoxtaResourceRef;\n}\n\n/**\n * Voxta collection folder (organizational grouping)\n */\nexport interface VoxtaCollectionFolder {\n  Name: string;\n  Description?: string;\n  /** Kind of resources in this folder (1=Character, 2=Book, 3=Scenario) */\n  Kind: VoxtaResourceKind | number;\n  Items: VoxtaCollectionItem[];\n  /** Nested folders (if any) */\n  Folders?: VoxtaCollectionFolder[];\n}\n\n/**\n * Voxta collection root structure\n */\nexport interface VoxtaCollectionRoot {\n  Folders: VoxtaCollectionFolder[];\n}\n\n/**\n * Voxta collection - organizes resources into themed groups\n */\nexport interface VoxtaCollection {\n  $type: 'collection';\n  Id: string;\n  Name: string;\n  Version?: string;\n  PackageId?: string;\n  ExplicitContent?: boolean;\n  Root: VoxtaCollectionRoot;\n  Thumbnail?: {\n    RandomizedETag?: string;\n    ContentType?: string;\n  };\n  DateCreated?: string;\n  DateModified?: string;\n}\n\n/**\n * Voxta scenario action\n */\nexport interface VoxtaAction {\n  Name: string;\n  Layer?: string;\n  Arguments?: unknown[];\n  FinalLayer?: boolean;\n  Timing?: number;\n  Description?: string;\n  Disabled?: boolean;\n  Once?: boolean;\n  FlagsFilter?: string;\n  EvaluateNextEvent?: boolean;\n  Effect?: {\n    SetFlags?: string[];\n    Script?: string;\n    Event?: string;\n    Story?: string;\n    Secret?: string;\n    Instructions?: string;\n    MaxSentences?: number;\n    MaxTokens?: number;\n    [key: string]: unknown;\n  };\n}\n\n/**\n * Voxta scenario event (similar to action but for event triggers)\n */\nexport interface VoxtaEvent {\n  Id?: string;\n  Name: string;\n  Layer?: string;\n  Timing?: number;\n  Description?: string;\n  Arguments?: unknown[];\n  Disabled?: boolean;\n  FinalLayer?: boolean;\n  Once?: boolean;\n  FlagsFilter?: string;\n  EvaluateNextEvent?: boolean;\n  Effect?: {\n    SetFlags?: string[];\n    Script?: string;\n    Event?: string;\n    Story?: string;\n    Secret?: string;\n    Instructions?: string;\n    MaxSentences?: number;\n    MaxTokens?: number;\n    [key: string]: unknown;\n  };\n}\n\n/**\n * Voxta scenario context (conditional context blocks)\n */\nexport interface VoxtaContext {\n  Name: string;\n  Text: string;\n  FlagsFilter?: string;\n  Disabled?: boolean;\n}\n\n/**\n * Voxta scenario role - maps characters to scenario slots\n */\nexport interface VoxtaRole {\n  Name: string;\n  Description?: string;\n  DefaultCharacterId: string;\n  EnabledOnStart?: boolean;\n}\n\n/**\n * Voxta impersonation (user persona override)\n */\nexport interface VoxtaImpersonation {\n  Name: string;\n  Description?: string;\n}\n\n/**\n * Voxta scenario\n */\nexport interface VoxtaScenario {\n  $type: 'scenario';\n  Id: string;\n  Name: string;\n  Version?: string;\n  ParentId?: string;\n  PackageId?: string;\n  Client?: string;\n  Creator?: string;\n  Description?: string;\n\n  // Core content\n  Template?: string;\n  Messages?: string;\n  SystemPrompt?: string;\n  SystemPromptOverrideType?: number;\n\n  // Character mappings\n  Roles?: VoxtaRole[];\n  NarratorCharacterId?: string;\n  Impersonation?: VoxtaImpersonation;\n\n  // Scripting/automation\n  SharedScripts?: VoxtaScript[];\n  Actions?: VoxtaAction[];\n  Events?: VoxtaEvent[];\n  Contexts?: VoxtaContext[];\n\n  // Settings\n  ExplicitContent?: boolean;\n  ChatFlow?: number;\n  ChatStyle?: number;\n  MemoryBooks?: string[];\n\n  // Metadata\n  Thumbnail?: {\n    ETag?: number;\n    RandomizedETag?: string;\n    ContentType?: string;\n  };\n  DateCreated?: string;\n  DateModified?: string;\n\n  // App control (optional)\n  UserId?: string;\n  AppControlled?: boolean;\n  Locked?: boolean;\n}\n\n/**\n * Extracted Voxta asset\n */\nexport interface ExtractedVoxtaAsset {\n  path: string;\n  buffer: BinaryData;\n  characterId?: string;\n}\n\n/**\n * Extracted Voxta character with assets\n */\nexport interface ExtractedVoxtaCharacter {\n  id: string;\n  data: VoxtaCharacter;\n  thumbnail?: BinaryData;\n  assets: ExtractedVoxtaAsset[];\n}\n\n/**\n * Extracted Voxta scenario\n */\nexport interface ExtractedVoxtaScenario {\n  id: string;\n  data: VoxtaScenario;\n  thumbnail?: BinaryData;\n}\n\n/**\n * Extracted Voxta book\n */\nexport interface ExtractedVoxtaBook {\n  id: string;\n  data: VoxtaBook;\n}\n\n/**\n * Extracted Voxta collection with assets\n */\nexport interface ExtractedVoxtaCollection {\n  id: string;\n  data: VoxtaCollection;\n  thumbnail?: BinaryData;\n}\n\n/**\n * Voxta export type\n * - 'package': Has package.json with full metadata\n * - 'scenario': Has Scenarios/ folder but no package.json (scenario export)\n * - 'character': Only has Characters/ folder (single/multi character export)\n * - 'collection': Has Collections/ folder (bundled content with organization)\n */\nexport type VoxtaExportType = 'package' | 'scenario' | 'character' | 'collection';\n\n/**\n * Complete extracted Voxta data\n */\nexport interface VoxtaData {\n  package?: VoxtaPackage;\n  characters: ExtractedVoxtaCharacter[];\n  scenarios: ExtractedVoxtaScenario[];\n  books: ExtractedVoxtaBook[];\n  collections: ExtractedVoxtaCollection[];\n\n  /**\n   * Type of export detected:\n   * - 'package': Has package.json\n   * - 'scenario': Has Scenarios/ but no package.json\n   * - 'character': Only Characters/ (no package.json or Scenarios/)\n   * - 'collection': Has Collections/ folder\n   */\n  exportType: VoxtaExportType;\n}\n\n/**\n * Options for Voxta extraction\n */\nexport interface VoxtaReadOptions {\n  maxFileSize?: number;\n  maxAssetSize?: number;\n  maxTotalSize?: number;\n}\n\n/**\n * Asset to include in Voxta export\n */\nexport interface VoxtaWriteAsset {\n  type: string;\n  name: string;\n  ext: string;\n  data: BinaryData;\n  tags?: string[];\n  isMain?: boolean;\n}\n\n/**\n * Options for building Voxta package\n */\nexport interface VoxtaWriteOptions {\n  compressionLevel?: CompressionLevel;\n  includePackageJson?: boolean;\n  characterId?: string;\n  packageId?: string;\n  /** Scenario to include - uses scenario.Id as the key */\n  scenario?: VoxtaScenario;\n  /** Scenario thumbnail */\n  scenarioThumbnail?: BinaryData;\n}\n\n/**\n * Result of building a Voxta package\n */\nexport interface VoxtaBuildResult {\n  buffer: BinaryData;\n  assetCount: number;\n  totalSize: number;\n  characterId: string;\n  /** Scenario ID if a scenario was included */\n  scenarioId?: string;\n}\n\n/**\n * Voxta extension data stored in CCv3 extensions\n */\nexport interface VoxtaExtensionData {\n  id: string;\n  version?: string;\n  packageId?: string;\n  label?: string;\n  textToSpeech?: VoxtaTtsConfig[];\n  appearance?: string;\n  context?: string;\n  instructions?: string;\n  userNameOverride?: string;\n  userDescriptionOverride?: string;\n  culture?: string;\n  importedFrom?: string;\n  chatSettings?: {\n    chatStyle?: number;\n    enableThinkingSpeech?: boolean;\n    notifyUserAwayReturn?: boolean;\n    timeAware?: boolean;\n    useMemory?: boolean;\n    maxTokens?: number;\n    maxSentences?: number;\n    systemPromptOverrideType?: number;\n  };\n  simulationSettings?: {\n    climaxSensitivity?: number;\n    pleasureDecay?: number;\n  };\n  scripts?: VoxtaScript[];\n  augmentations?: unknown[];\n  scenario?: {\n    actions?: VoxtaAction[];\n    sharedScripts?: VoxtaScript[];\n  };\n  original?: Partial<VoxtaCharacter>;\n}\n\n/**\n * Loss report for Voxta export\n */\nexport interface VoxtaLossReport {\n  lostFields: string[];\n  lostAssets: string[];\n  warnings: string[];\n  reason: string;\n}\n","/**\n * Voxta Reader\n *\n * Extracts and parses .voxpkg files.\n */\n\nimport {\n  type BinaryData,\n  toString,\n  ParseError,\n  SizeLimitError,\n} from '@character-foundry/core';\nimport {\n  type Unzipped,\n  findZipStart,\n  getZipOffset,\n  streamingUnzipSync,\n  ZipPreflightError,\n} from '@character-foundry/core/zip';\nimport type {\n  VoxtaData,\n  VoxtaReadOptions,\n  ExtractedVoxtaCharacter,\n  ExtractedVoxtaScenario,\n  ExtractedVoxtaBook,\n  ExtractedVoxtaCollection,\n  VoxtaPackage,\n  VoxtaCharacter,\n  VoxtaScenario,\n  VoxtaBook,\n  VoxtaCollection,\n} from './types.js';\n\nconst DEFAULT_OPTIONS: Required<VoxtaReadOptions> = {\n  maxFileSize: 50 * 1024 * 1024,    // 50MB\n  maxAssetSize: 50 * 1024 * 1024,   // 50MB\n  maxTotalSize: 500 * 1024 * 1024,  // 500MB - Voxta packages can be large\n};\n\n// ZIP End of Central Directory signature\nconst EOCD_SIGNATURE = new Uint8Array([0x50, 0x4b, 0x05, 0x06]);\n// ZIP Central Directory File Header signature\nconst CDFH_SIGNATURE = new Uint8Array([0x50, 0x4b, 0x01, 0x02]);\n\n/**\n * Scan ZIP central directory for filenames matching Voxta markers.\n * The central directory is at the END of the ZIP file, so we must parse\n * the EOCD record to find it.\n */\nfunction scanZipCentralDirectory(zipData: BinaryData, markers: string[]): boolean {\n  // Find EOCD (End of Central Directory) - scan from end\n  // EOCD is at least 22 bytes, search within last 64KB (comment can be up to 64KB)\n  const searchSize = Math.min(zipData.length, 65536 + 22);\n  let eocdOffset = -1;\n\n  for (let i = zipData.length - 22; i >= zipData.length - searchSize; i--) {\n    if (\n      zipData[i] === EOCD_SIGNATURE[0] &&\n      zipData[i + 1] === EOCD_SIGNATURE[1] &&\n      zipData[i + 2] === EOCD_SIGNATURE[2] &&\n      zipData[i + 3] === EOCD_SIGNATURE[3]\n    ) {\n      eocdOffset = i;\n      break;\n    }\n  }\n\n  if (eocdOffset < 0) return false;\n\n  // EOCD structure (22 bytes minimum):\n  // 0-3:   signature (PK\\x05\\x06)\n  // 4-5:   disk number\n  // 6-7:   disk with central directory\n  // 8-9:   entries on this disk\n  // 10-11: total entries\n  // 12-15: central directory size\n  // 16-19: central directory offset\n  // 20-21: comment length\n\n  // Read central directory offset (little-endian uint32 at offset 16)\n  const cdOffset =\n    zipData[eocdOffset + 16]! |\n    (zipData[eocdOffset + 17]! << 8) |\n    (zipData[eocdOffset + 18]! << 16) |\n    (zipData[eocdOffset + 19]! << 24);\n\n  // Read number of entries (little-endian uint16 at offset 10)\n  const numEntries = zipData[eocdOffset + 10]! | (zipData[eocdOffset + 11]! << 8);\n\n  if (cdOffset < 0 || cdOffset >= zipData.length) return false;\n\n  // Iterate through central directory entries\n  let pos = cdOffset;\n  const decoder = new TextDecoder();\n\n  for (let entry = 0; entry < numEntries && pos < eocdOffset; entry++) {\n    // Verify CDFH signature\n    if (\n      zipData[pos] !== CDFH_SIGNATURE[0] ||\n      zipData[pos + 1] !== CDFH_SIGNATURE[1] ||\n      zipData[pos + 2] !== CDFH_SIGNATURE[2] ||\n      zipData[pos + 3] !== CDFH_SIGNATURE[3]\n    ) {\n      break; // Invalid entry, stop parsing\n    }\n\n    // Central Directory File Header structure:\n    // 0-3:   signature\n    // 4-5:   version made by\n    // 6-7:   version needed\n    // 8-9:   flags\n    // 10-11: compression method\n    // 12-13: last mod time\n    // 14-15: last mod date\n    // 16-19: CRC-32\n    // 20-23: compressed size\n    // 24-27: uncompressed size\n    // 28-29: filename length\n    // 30-31: extra field length\n    // 32-33: comment length\n    // 34-35: disk number start\n    // 36-37: internal attributes\n    // 38-41: external attributes\n    // 42-45: local header offset\n    // 46+:   filename, extra field, comment\n\n    const fileNameLen = zipData[pos + 28]! | (zipData[pos + 29]! << 8);\n    const extraLen = zipData[pos + 30]! | (zipData[pos + 31]! << 8);\n    const commentLen = zipData[pos + 32]! | (zipData[pos + 33]! << 8);\n\n    if (pos + 46 + fileNameLen > zipData.length) break;\n\n    // Extract filename\n    const fileName = decoder.decode(zipData.subarray(pos + 46, pos + 46 + fileNameLen));\n\n    // Check against markers\n    for (const marker of markers) {\n      if (fileName === marker || fileName.startsWith(marker)) {\n        return true;\n      }\n    }\n\n    // Move to next entry\n    pos += 46 + fileNameLen + extraLen + commentLen;\n  }\n\n  return false;\n}\n\n/**\n * Check if data is a Voxta package\n */\nexport function isVoxta(data: BinaryData): boolean {\n  const zipOffset = getZipOffset(data);\n  if (zipOffset < 0) return false;\n\n  const zipData = data.subarray(zipOffset);\n\n  // Voxta markers - package.json is the primary indicator\n  const markers = [\n    'package.json',\n    'character.json',\n    'Characters/',\n    'MemoryBooks/',\n    'Scenarios/',\n    'Collections/',\n  ];\n\n  return scanZipCentralDirectory(zipData, markers);\n}\n\n/**\n * Extract and parse a Voxta package\n */\nexport function readVoxta(\n  data: BinaryData,\n  options: VoxtaReadOptions = {}\n): VoxtaData {\n  const opts = { ...DEFAULT_OPTIONS, ...options };\n\n  // SECURITY: Streaming unzip with real-time byte limit enforcement\n  // This tracks ACTUAL decompressed bytes and aborts if limits exceeded,\n  // protecting against malicious archives that lie about sizes in central directory\n  let unzipped: Unzipped;\n  try {\n    unzipped = streamingUnzipSync(data, {\n      maxFileSize: opts.maxAssetSize,\n      maxTotalSize: opts.maxTotalSize,\n      maxFiles: 10000, // Voxta packages can have many files\n    });\n  } catch (err) {\n    if (err instanceof ZipPreflightError) {\n      throw new SizeLimitError(\n        err.totalSize || err.entrySize || 0,\n        err.maxSize || err.maxEntrySize || opts.maxTotalSize,\n        err.oversizedEntry || 'Voxta package'\n      );\n    }\n    throw new ParseError(\n      `Failed to unzip Voxta package: ${err instanceof Error ? err.message : String(err)}`,\n      'voxta'\n    );\n  }\n\n  const result: VoxtaData = {\n    characters: [],\n    scenarios: [],\n    books: [],\n    collections: [],\n    exportType: 'character', // Default, will be updated based on contents\n  };\n\n  // Temporary maps to aggregate data parts\n  const charMap = new Map<string, Partial<ExtractedVoxtaCharacter>>();\n  const scenarioMap = new Map<string, Partial<ExtractedVoxtaScenario>>();\n  const bookMap = new Map<string, Partial<ExtractedVoxtaBook>>();\n  const collectionMap = new Map<string, Partial<ExtractedVoxtaCollection>>();\n\n  // Process entries (size limits already enforced by streamingUnzipSync)\n  for (const [fileName, fileData] of Object.entries(unzipped)) {\n    // Skip directories\n    if (fileName.endsWith('/') || fileData.length === 0) continue;\n\n    // 1. Package Metadata\n    if (fileName === 'package.json') {\n      if (fileData.length > opts.maxFileSize) {\n        throw new SizeLimitError(fileData.length, opts.maxFileSize, 'package.json');\n      }\n      try {\n        result.package = JSON.parse(toString(fileData)) as VoxtaPackage;\n      } catch (err) {\n        throw new ParseError(\n          `Failed to parse package.json: ${err instanceof Error ? err.message : String(err)}`,\n          'voxta'\n        );\n      }\n      continue;\n    }\n\n    // 2. Characters - Path: Characters/{uuid}/...\n    const charMatch = fileName.match(/^Characters\\/([^/]+)\\/(.+)$/);\n    if (charMatch) {\n      const [, charId, subPath] = charMatch;\n\n      if (!charMap.has(charId!)) {\n        charMap.set(charId!, { id: charId, assets: [] });\n      }\n      const charEntry = charMap.get(charId!)!;\n\n      if (subPath === 'character.json') {\n        try {\n          charEntry.data = JSON.parse(toString(fileData)) as VoxtaCharacter;\n        } catch (err) {\n          throw new ParseError(\n            `Failed to parse character.json for ${charId}: ${err instanceof Error ? err.message : String(err)}`,\n            'voxta'\n          );\n        }\n      } else if (subPath!.startsWith('thumbnail.')) {\n        charEntry.thumbnail = fileData;\n      } else if (subPath!.startsWith('Assets/')) {\n        charEntry.assets!.push({\n          path: subPath!,\n          buffer: fileData,\n          characterId: charId,\n        });\n      }\n      continue;\n    }\n\n    // 3. Scenarios - Path: Scenarios/{uuid}/...\n    const scenarioMatch = fileName.match(/^Scenarios\\/([^/]+)\\/(.+)$/);\n    if (scenarioMatch) {\n      const [, scenarioId, subPath] = scenarioMatch;\n\n      if (!scenarioMap.has(scenarioId!)) {\n        scenarioMap.set(scenarioId!, { id: scenarioId });\n      }\n      const scenarioEntry = scenarioMap.get(scenarioId!)!;\n\n      if (subPath === 'scenario.json') {\n        try {\n          scenarioEntry.data = JSON.parse(toString(fileData)) as VoxtaScenario;\n        } catch (err) {\n          throw new ParseError(\n            `Failed to parse scenario.json for ${scenarioId}: ${err instanceof Error ? err.message : String(err)}`,\n            'voxta'\n          );\n        }\n      } else if (subPath!.startsWith('thumbnail.')) {\n        scenarioEntry.thumbnail = fileData;\n      }\n      continue;\n    }\n\n    // 4. Books - Path: Books/{uuid}/...\n    const bookMatch = fileName.match(/^Books\\/([^/]+)\\/(.+)$/);\n    if (bookMatch) {\n      const [, bookId, subPath] = bookMatch;\n\n      if (!bookMap.has(bookId!)) {\n        bookMap.set(bookId!, { id: bookId });\n      }\n      const bookEntry = bookMap.get(bookId!)!;\n\n      if (subPath === 'book.json') {\n        try {\n          bookEntry.data = JSON.parse(toString(fileData)) as VoxtaBook;\n        } catch (err) {\n          throw new ParseError(\n            `Failed to parse book.json for ${bookId}: ${err instanceof Error ? err.message : String(err)}`,\n            'voxta'\n          );\n        }\n      }\n      continue;\n    }\n\n    // 5. Collections - Path: Collections/{uuid}/...\n    const collectionMatch = fileName.match(/^Collections\\/([^/]+)\\/(.+)$/);\n    if (collectionMatch) {\n      const [, collectionId, subPath] = collectionMatch;\n\n      if (!collectionMap.has(collectionId!)) {\n        collectionMap.set(collectionId!, { id: collectionId });\n      }\n      const collectionEntry = collectionMap.get(collectionId!)!;\n\n      if (subPath === 'collection.json') {\n        try {\n          collectionEntry.data = JSON.parse(toString(fileData)) as VoxtaCollection;\n        } catch (err) {\n          throw new ParseError(\n            `Failed to parse collection.json for ${collectionId}: ${err instanceof Error ? err.message : String(err)}`,\n            'voxta'\n          );\n        }\n      } else if (subPath!.startsWith('thumbnail.')) {\n        collectionEntry.thumbnail = fileData;\n      }\n      continue;\n    }\n  }\n\n  // Assemble final results - filter incomplete entries\n  for (const [, char] of charMap) {\n    if (char.data) {\n      result.characters.push(char as ExtractedVoxtaCharacter);\n    }\n  }\n\n  for (const [, scenario] of scenarioMap) {\n    if (scenario.data) {\n      result.scenarios.push(scenario as ExtractedVoxtaScenario);\n    }\n  }\n\n  for (const [, book] of bookMap) {\n    if (book.data) {\n      result.books.push(book as ExtractedVoxtaBook);\n    }\n  }\n\n  for (const [, collection] of collectionMap) {\n    if (collection.data) {\n      result.collections.push(collection as ExtractedVoxtaCollection);\n    }\n  }\n\n  // Determine export type based on contents\n  if (result.package) {\n    result.exportType = 'package';\n  } else if (result.collections.length > 0) {\n    // Collections without package.json = collection export\n    result.exportType = 'collection';\n  } else if (result.scenarios.length > 0) {\n    result.exportType = 'scenario';\n  }\n  // else stays 'character' (default)\n\n  return result;\n}\n\n/**\n * Async version of readVoxta\n */\nexport async function readVoxtaAsync(\n  data: BinaryData,\n  options: VoxtaReadOptions = {}\n): Promise<VoxtaData> {\n  return readVoxta(data, options);\n}\n","/**\n * Voxta Writer\n *\n * Creates .voxpkg files from CCv3 card data.\n */\n\nimport { zipSync, type Zippable } from 'fflate';\nimport { type BinaryData, fromString, generateUUID } from '@character-foundry/core';\nimport { detectImageFormat, getExtension } from '@character-foundry/media';\nimport type { CCv3Data } from '@character-foundry/schemas';\nimport type {\n  VoxtaWriteAsset,\n  VoxtaWriteOptions,\n  VoxtaBuildResult,\n  VoxtaCharacter,\n  VoxtaScenario,\n  VoxtaExtensionData,\n  CompressionLevel,\n} from './types.js';\nimport { standardToVoxta } from './macros.js';\nimport { ccv3LorebookToVoxtaBook } from './mapper.js';\n\n/**\n * Sanitize a name for use in file paths\n */\nfunction sanitizeName(name: string, ext: string): string {\n  let safeName = name;\n\n  if (safeName.toLowerCase().endsWith(`.${ext.toLowerCase()}`)) {\n    safeName = safeName.substring(0, safeName.length - (ext.length + 1));\n  }\n\n  safeName = safeName\n    .replace(/[._]/g, '-')\n    .replace(/[^a-zA-Z0-9-]/g, '-')\n    .replace(/-+/g, '-')\n    .replace(/^-+|-+$/g, '');\n\n  if (!safeName) safeName = 'asset';\n\n  return safeName;\n}\n\n/**\n * Build a Voxta package from CCv3 card data\n */\nexport function writeVoxta(\n  card: CCv3Data,\n  assets: VoxtaWriteAsset[],\n  options: VoxtaWriteOptions = {}\n): VoxtaBuildResult {\n  let { compressionLevel = 6, includePackageJson = false } = options;\n  const cardData = card.data;\n\n  // Get Voxta extension data if present\n  const extensions = cardData.extensions as Record<string, unknown> | undefined;\n  const voxtaExt = extensions?.voxta as VoxtaExtensionData | undefined;\n\n  // Generate IDs\n  const characterId = options.characterId || voxtaExt?.id || generateUUID();\n  const packageId = options.packageId || voxtaExt?.packageId || generateUUID();\n  const dateNow = new Date().toISOString();\n\n  // Get appearance from voxta extension or visual_description\n  const appearance = voxtaExt?.appearance || (extensions?.visual_description as string) || '';\n\n  // Create ZIP entries\n  const zipEntries: Zippable = {};\n\n  // Handle Lorebook (MemoryBook)\n  const book = ccv3LorebookToVoxtaBook(card);\n  const memoryBooks: string[] = voxtaExt?.original?.MemoryBooks || [];\n\n  if (book) {\n    // Ensure we have a unique ID for the book\n    if (!book.Id) book.Id = generateUUID();\n\n    // Add to memory books list if not already present\n    if (!memoryBooks.includes(book.Id)) {\n      memoryBooks.push(book.Id);\n    }\n\n    // Write book to ZIP - character will reference it via MemoryBooks\n    zipEntries[`Books/${book.Id}/book.json`] = [\n      fromString(JSON.stringify(book, null, 2)),\n      { level: compressionLevel as CompressionLevel },\n    ];\n\n    // Note: We no longer force includePackageJson = true here.\n    // The Books/ folder is valid alongside Characters/ without package.json.\n    // This allows single-character exports with lorebooks.\n  }\n\n  // 1. Package.json (optional)\n  if (includePackageJson) {\n    const packageMeta = {\n      $type: 'package',\n      Id: packageId,\n      Name: cardData.name,\n      Version: cardData.character_version || '1.0.0',\n      Description: cardData.description,\n      Creator: cardData.creator,\n      ExplicitContent: true,\n      EntryResource: { Kind: 1, Id: characterId },\n      ThumbnailResource: { Kind: 1, Id: characterId },\n      DateCreated: voxtaExt?.original?.DateCreated || dateNow,\n      DateModified: dateNow,\n    };\n    zipEntries['package.json'] = [\n      fromString(JSON.stringify(packageMeta, null, 2)),\n      { level: compressionLevel as CompressionLevel },\n    ];\n  }\n\n  // 2. Character.json\n  const character: VoxtaCharacter = {\n    $type: 'character',\n    Id: characterId,\n    PackageId: packageId,\n    Name: cardData.name,\n    Version: cardData.character_version,\n\n    // Core Info - apply macro conversion (handle nullable personality/mes_example)\n    Description: appearance,\n    Personality: standardToVoxta(cardData.personality ?? ''),\n    Profile: standardToVoxta(cardData.description),\n    Scenario: standardToVoxta(cardData.scenario),\n    FirstMessage: standardToVoxta(cardData.first_mes),\n    AlternativeFirstMessages: (cardData.alternate_greetings || []).map(standardToVoxta),\n    MessageExamples: standardToVoxta(cardData.mes_example ?? ''),\n\n    // System prompts - Voxta supports these\n    SystemPrompt: cardData.system_prompt ? standardToVoxta(cardData.system_prompt) : undefined,\n    PostHistoryInstructions: cardData.post_history_instructions ? standardToVoxta(cardData.post_history_instructions) : undefined,\n\n    // Metadata\n    Creator: cardData.creator,\n    CreatorNotes: cardData.creator_notes,\n    Tags: cardData.tags,\n\n    // References\n    MemoryBooks: memoryBooks.length > 0 ? memoryBooks : undefined,\n\n    // Voxta-specific from extension\n    TextToSpeech: voxtaExt?.textToSpeech,\n    ChatStyle: voxtaExt?.chatSettings?.chatStyle,\n    EnableThinkingSpeech: voxtaExt?.chatSettings?.enableThinkingSpeech,\n    NotifyUserAwayReturn: voxtaExt?.chatSettings?.notifyUserAwayReturn,\n    TimeAware: voxtaExt?.chatSettings?.timeAware,\n    UseMemory: voxtaExt?.chatSettings?.useMemory,\n    MaxTokens: voxtaExt?.chatSettings?.maxTokens,\n    MaxSentences: voxtaExt?.chatSettings?.maxSentences,\n    SystemPromptOverrideType: voxtaExt?.chatSettings?.systemPromptOverrideType,\n    \n    // Simulation Settings\n    ClimaxSensitivity: voxtaExt?.simulationSettings?.climaxSensitivity,\n    PleasureDecay: voxtaExt?.simulationSettings?.pleasureDecay,\n\n    Scripts: voxtaExt?.scripts,\n\n    DateCreated: voxtaExt?.original?.DateCreated || dateNow,\n    DateModified: dateNow,\n  };\n\n  zipEntries[`Characters/${characterId}/character.json`] = [\n    fromString(JSON.stringify(character, null, 2)),\n    { level: compressionLevel as CompressionLevel },\n  ];\n\n  // 3. Add assets\n  let assetCount = 0;\n  let mainThumbnail: VoxtaWriteAsset | undefined;\n\n  for (const asset of assets) {\n    const safeName = sanitizeName(asset.name, asset.ext);\n    const finalFilename = `${safeName}.${asset.ext}`;\n    let voxtaPath = '';\n\n    const tags = asset.tags || [];\n\n    // Check if this is the main icon (used as thumbnail only, not in Assets folder)\n    const isMainIcon = asset.type === 'icon' && (\n      tags.includes('portrait-override') ||\n      asset.name === 'main' ||\n      asset.isMain\n    );\n\n    if (asset.type === 'sound' || tags.includes('voice')) {\n      voxtaPath = `Characters/${characterId}/Assets/VoiceSamples/${finalFilename}`;\n    } else if (asset.type === 'icon' || asset.type === 'emotion') {\n      // Track main icon for thumbnail (but don't add to Assets folder)\n      if (asset.type === 'icon') {\n        if (tags.includes('portrait-override')) {\n          mainThumbnail = asset;\n        } else if (!mainThumbnail && (asset.name === 'main' || asset.isMain)) {\n          mainThumbnail = asset;\n        }\n      }\n\n      // Skip adding main icon to Assets folder - it will only be the thumbnail\n      if (isMainIcon) {\n        continue;\n      }\n\n      voxtaPath = `Characters/${characterId}/Assets/Avatars/Default/${finalFilename}`;\n    } else {\n      voxtaPath = `Characters/${characterId}/Assets/Misc/${finalFilename}`;\n    }\n\n    zipEntries[voxtaPath] = [asset.data, { level: compressionLevel as CompressionLevel }];\n    assetCount++;\n  }\n\n  // 4. Add thumbnail (detect format - supports PNG, WebP, JPEG)\n  if (!mainThumbnail && assets.length > 0) {\n    mainThumbnail = assets.find((a) => a.type === 'icon');\n  }\n\n  if (mainThumbnail) {\n    const thumbData =\n      mainThumbnail.data instanceof Uint8Array\n        ? mainThumbnail.data\n        : new Uint8Array(mainThumbnail.data);\n    const thumbFormat = detectImageFormat(thumbData);\n    const thumbExt = thumbFormat ? getExtension(thumbFormat) : 'png';\n\n    zipEntries[`Characters/${characterId}/thumbnail.${thumbExt}`] = [\n      mainThumbnail.data,\n      { level: compressionLevel as CompressionLevel },\n    ];\n  }\n\n  // 5. Add scenario if provided (uses scenario.Id as key)\n  let scenarioId: string | undefined;\n  if (options.scenario) {\n    const scenario = options.scenario;\n    scenarioId = scenario.Id;\n\n    // Ensure scenario has required fields\n    const scenarioData: VoxtaScenario = {\n      ...scenario,\n      $type: 'scenario',\n      PackageId: packageId,\n      DateModified: dateNow,\n    };\n\n    // Write scenario.json\n    zipEntries[`Scenarios/${scenarioId}/scenario.json`] = [\n      fromString(JSON.stringify(scenarioData, null, 2)),\n      { level: compressionLevel as CompressionLevel },\n    ];\n\n    // Add scenario thumbnail if provided (detect format)\n    if (options.scenarioThumbnail) {\n      const scenarioThumbData =\n        options.scenarioThumbnail instanceof Uint8Array\n          ? options.scenarioThumbnail\n          : new Uint8Array(options.scenarioThumbnail);\n      const scenarioThumbFormat = detectImageFormat(scenarioThumbData);\n      const scenarioThumbExt = scenarioThumbFormat ? getExtension(scenarioThumbFormat) : 'png';\n\n      zipEntries[`Scenarios/${scenarioId}/thumbnail.${scenarioThumbExt}`] = [\n        options.scenarioThumbnail,\n        { level: compressionLevel as CompressionLevel },\n      ];\n    }\n\n    // Update package.json EntryResource to point to scenario (Kind: 3)\n    if (includePackageJson) {\n      const packageMeta = {\n        $type: 'package',\n        Id: packageId,\n        Name: scenario.Name || cardData.name,\n        Version: scenario.Version || cardData.character_version || '1.0.0',\n        Description: scenario.Description || cardData.description,\n        Creator: scenario.Creator || cardData.creator,\n        ExplicitContent: scenario.ExplicitContent ?? true,\n        EntryResource: { Kind: 3, Id: scenarioId }, // Kind 3 = Scenario\n        ThumbnailResource: { Kind: 3, Id: scenarioId },\n        DateCreated: scenario.DateCreated || voxtaExt?.original?.DateCreated || dateNow,\n        DateModified: dateNow,\n      };\n      zipEntries['package.json'] = [\n        fromString(JSON.stringify(packageMeta, null, 2)),\n        { level: compressionLevel as CompressionLevel },\n      ];\n    }\n  }\n\n  // Create ZIP\n  const buffer = zipSync(zipEntries);\n\n  return {\n    buffer,\n    assetCount,\n    totalSize: buffer.length,\n    characterId,\n    scenarioId,\n  };\n}\n\n/**\n * Async version of writeVoxta\n */\nexport async function writeVoxtaAsync(\n  card: CCv3Data,\n  assets: VoxtaWriteAsset[],\n  options: VoxtaWriteOptions = {}\n): Promise<VoxtaBuildResult> {\n  return writeVoxta(card, assets, options);\n}\n","/**\n * Macro Conversion\n *\n * Converts between Voxta-style macros (with spaces) and standard macros.\n *\n * Voxta uses: {{ user }}, {{ char }}\n * Standard uses: {{user}}, {{char}}\n */\n\n/**\n * Convert Voxta-style macros to standard format (no spaces)\n */\nexport function voxtaToStandard(text: string): string {\n  if (!text) return text;\n\n  let result = text;\n\n  // Replace {{ user }} variants with {{user}}\n  result = result.replace(/\\{\\{\\s*user\\s*\\}\\}/gi, (match) => {\n    const isUpperCase = match.includes('User') || match.includes('USER');\n    return isUpperCase ? '{{User}}' : '{{user}}';\n  });\n\n  // Replace {{ char }} variants with {{char}}\n  result = result.replace(/\\{\\{\\s*char\\s*\\}\\}/gi, (match) => {\n    const isUpperCase = match.includes('Char') || match.includes('CHAR');\n    return isUpperCase ? '{{Char}}' : '{{char}}';\n  });\n\n  return result;\n}\n\n/**\n * Convert standard macros to Voxta-style format (with spaces)\n */\nexport function standardToVoxta(text: string): string {\n  if (!text) return text;\n\n  let result = text;\n\n  // Replace {{user}} variants with {{ user }}\n  result = result.replace(/\\{\\{user\\}\\}/gi, (match) => {\n    const isUpperCase = match.includes('User') || match.includes('USER');\n    return isUpperCase ? '{{ User }}' : '{{ user }}';\n  });\n\n  // Replace {{char}} variants with {{ char }}\n  result = result.replace(/\\{\\{char\\}\\}/gi, (match) => {\n    const isUpperCase = match.includes('Char') || match.includes('CHAR');\n    return isUpperCase ? '{{ Char }}' : '{{ char }}';\n  });\n\n  return result;\n}\n","/**\n * Voxta <-> CCv3 Mapping\n *\n * Conversion utilities between Voxta format and CCv3 format.\n */\n\nimport type {\n  CCv3Data,\n  CCv3CharacterBook,\n  CCv3LorebookEntry,\n} from '@character-foundry/schemas';\nimport { generateUUID } from '@character-foundry/core';\nimport type {\n  VoxtaCharacter,\n  VoxtaBook,\n  VoxtaExtensionData,\n} from './types.js';\nimport { voxtaToStandard, standardToVoxta } from './macros.js';\n\n/**\n * Convert a Voxta character to CCv3 format\n */\nexport function voxtaToCCv3(character: VoxtaCharacter, books?: VoxtaBook[]): CCv3Data {\n  // Build voxta extension data to preserve Voxta-specific fields\n  const voxtaExt: VoxtaExtensionData = {\n    id: character.Id,\n    packageId: character.PackageId,\n    label: character.Label,\n    appearance: character.Description,\n    context: character.Context,\n    instructions: character.Instructions,\n    userNameOverride: character.UserNameOverride,\n    userDescriptionOverride: character.UserDescriptionOverride,\n    culture: character.Culture,\n    importedFrom: character.ImportedFrom,\n    textToSpeech: character.TextToSpeech,\n    chatSettings: {\n      chatStyle: character.ChatStyle,\n      enableThinkingSpeech: character.EnableThinkingSpeech,\n      notifyUserAwayReturn: character.NotifyUserAwayReturn,\n      timeAware: character.TimeAware,\n      useMemory: character.UseMemory,\n      maxTokens: character.MaxTokens,\n      maxSentences: character.MaxSentences,\n      systemPromptOverrideType: character.SystemPromptOverrideType,\n    },\n    simulationSettings: {\n      climaxSensitivity: character.ClimaxSensitivity,\n      pleasureDecay: character.PleasureDecay,\n    },\n    scripts: character.Scripts,\n    augmentations: character.Augmentations,\n    original: {\n      DateCreated: character.DateCreated,\n      DateModified: character.DateModified,\n    },\n  };\n\n  // Convert lorebook from VoxtaBooks\n  let characterBook: CCv3CharacterBook | undefined;\n\n  if (books && books.length > 0) {\n    const entries: CCv3LorebookEntry[] = [];\n    const linkedBookIds = new Set(character.MemoryBooks || []);\n\n    for (const book of books) {\n      // Only include if linked or if no links defined (legacy/implicit)\n      if (linkedBookIds.size === 0 || linkedBookIds.has(book.Id)) {\n        if (book.Items) {\n          for (let i = 0; i < book.Items.length; i++) {\n            const item = book.Items[i]!;\n            entries.push({\n              keys: item.Keywords || [],\n              content: voxtaToStandard(item.Text || ''),\n              enabled: item.Deleted !== true,\n              insertion_order: i,\n              name: item.Id || '',\n              priority: item.Weight || 10,\n              id: i,\n              comment: '',\n              selective: false,\n              secondary_keys: [],\n              constant: false,\n              position: 'before_char',\n            });\n          }\n        }\n      }\n    }\n\n    if (entries.length > 0) {\n      characterBook = {\n        entries,\n        name: books[0]!.Name || 'Imported Lorebook',\n      };\n    }\n  }\n\n  // Convert timestamps (ISO string -> Unix seconds)\n  const creationDate = character.DateCreated\n    ? Math.floor(new Date(character.DateCreated).getTime() / 1000)\n    : undefined;\n  const modificationDate = character.DateModified\n    ? Math.floor(new Date(character.DateModified).getTime() / 1000)\n    : undefined;\n\n  // Build CCv3 card\n  const card: CCv3Data = {\n    spec: 'chara_card_v3',\n    spec_version: '3.0',\n    data: {\n      name: character.Name || 'Unknown',\n      nickname: character.Label,\n      description: voxtaToStandard(character.Profile || ''),\n      personality: voxtaToStandard(character.Personality || ''),\n      scenario: voxtaToStandard(character.Scenario || ''),\n      first_mes: voxtaToStandard(character.FirstMessage || ''),\n      mes_example: voxtaToStandard(character.MessageExamples || ''),\n      creator_notes: character.CreatorNotes || '',\n      system_prompt: voxtaToStandard(character.SystemPrompt || ''),\n      post_history_instructions: voxtaToStandard(character.PostHistoryInstructions || ''),\n      alternate_greetings: (character.AlternativeFirstMessages || []).map(voxtaToStandard),\n      group_only_greetings: [],\n      tags: character.Tags || [],\n      creator: character.Creator || '',\n      character_version: character.Version || '1.0',\n      creation_date: creationDate,\n      modification_date: modificationDate,\n      character_book: characterBook,\n      extensions: {\n        voxta: voxtaExt,\n        visual_description: character.Description || undefined,\n      },\n    },\n  };\n\n  return card;\n}\n\n/**\n * Convert CCv3 card to Voxta character format\n */\nexport function ccv3ToVoxta(card: CCv3Data): VoxtaCharacter {\n  const cardData = card.data;\n  const extensions = cardData.extensions as Record<string, unknown> | undefined;\n  const voxtaExt = extensions?.voxta as VoxtaExtensionData | undefined;\n  const dateNow = new Date().toISOString();\n\n  const appearance = voxtaExt?.appearance || (extensions?.visual_description as string) || '';\n\n  // Convert timestamps (Unix seconds -> ISO string)\n  const dateCreated = cardData.creation_date\n    ? new Date(cardData.creation_date * 1000).toISOString()\n    : voxtaExt?.original?.DateCreated || dateNow;\n  const dateModified = cardData.modification_date\n    ? new Date(cardData.modification_date * 1000).toISOString()\n    : dateNow;\n\n  const character: VoxtaCharacter = {\n    $type: 'character',\n    Id: voxtaExt?.id || generateUUID(),\n    PackageId: voxtaExt?.packageId || generateUUID(),\n    Name: cardData.name,\n    Label: cardData.nickname || voxtaExt?.label,\n    Version: cardData.character_version,\n\n    // Core content (handle nullable personality/mes_example)\n    Description: appearance,\n    Personality: standardToVoxta(cardData.personality ?? ''),\n    Profile: standardToVoxta(cardData.description),\n    Scenario: standardToVoxta(cardData.scenario),\n    FirstMessage: standardToVoxta(cardData.first_mes),\n    AlternativeFirstMessages: (cardData.alternate_greetings || []).map(standardToVoxta),\n    MessageExamples: standardToVoxta(cardData.mes_example ?? ''),\n\n    // System prompts\n    SystemPrompt: standardToVoxta(cardData.system_prompt || ''),\n    PostHistoryInstructions: standardToVoxta(cardData.post_history_instructions || ''),\n    Context: voxtaExt?.context,\n    Instructions: voxtaExt?.instructions,\n\n    // Persona overrides\n    UserNameOverride: voxtaExt?.userNameOverride,\n    UserDescriptionOverride: voxtaExt?.userDescriptionOverride,\n\n    // Metadata\n    Creator: cardData.creator,\n    CreatorNotes: cardData.creator_notes,\n    Tags: cardData.tags,\n    Culture: voxtaExt?.culture,\n    ImportedFrom: voxtaExt?.importedFrom,\n\n    // TTS & AI settings\n    TextToSpeech: voxtaExt?.textToSpeech,\n    ChatStyle: voxtaExt?.chatSettings?.chatStyle,\n    EnableThinkingSpeech: voxtaExt?.chatSettings?.enableThinkingSpeech,\n    NotifyUserAwayReturn: voxtaExt?.chatSettings?.notifyUserAwayReturn,\n    TimeAware: voxtaExt?.chatSettings?.timeAware,\n    UseMemory: voxtaExt?.chatSettings?.useMemory,\n    MaxTokens: voxtaExt?.chatSettings?.maxTokens,\n    MaxSentences: voxtaExt?.chatSettings?.maxSentences,\n    SystemPromptOverrideType: voxtaExt?.chatSettings?.systemPromptOverrideType,\n\n    // Simulation settings\n    ClimaxSensitivity: voxtaExt?.simulationSettings?.climaxSensitivity,\n    PleasureDecay: voxtaExt?.simulationSettings?.pleasureDecay,\n\n    // Advanced\n    Scripts: voxtaExt?.scripts,\n    Augmentations: voxtaExt?.augmentations,\n\n    DateCreated: dateCreated,\n    DateModified: dateModified,\n  };\n\n  return character;\n}\n\n/**\n * Convert CCv3 lorebook to Voxta book format\n */\nexport function ccv3LorebookToVoxtaBook(card: CCv3Data): VoxtaBook | null {\n  const characterBook = card.data.character_book;\n  if (!characterBook?.entries || characterBook.entries.length === 0) {\n    return null;\n  }\n\n  const book: VoxtaBook = {\n    $type: 'book',\n    Id: generateUUID(),\n    Name: characterBook.name || `${card.data.name}'s Lorebook`,\n    Items: characterBook.entries.map((entry) => ({\n      Id: generateUUID(),\n      Keywords: entry.keys || [],\n      Text: standardToVoxta(entry.content || ''),\n      Weight: entry.priority || 10,\n      Deleted: entry.enabled === false,\n    })),\n  };\n\n  return book;\n}\n","/**\n * Voxta Merge Utilities\n *\n * Functions for merging CCv3 edits into Voxta structures.\n */\n\nimport { unzipSync, zipSync, type Unzipped, type Zippable } from 'fflate';\nimport {\n  type BinaryData,\n  fromString,\n  ParseError,\n  SizeLimitError,\n  generateUUID,\n} from '@character-foundry/core';\nimport {\n  findZipStart,\n  preflightZipSizes,\n  ZipPreflightError,\n} from '@character-foundry/core/zip';\nimport { detectImageFormat, getExtension } from '@character-foundry/media';\nimport type { CCv3Data, CCv3CharacterBook } from '@character-foundry/schemas';\nimport type {\n  VoxtaCharacter,\n  VoxtaBook,\n  VoxtaBookItem,\n  VoxtaPackage,\n  ExtractedVoxtaCharacter,\n  ExtractedVoxtaBook,\n  CompressionLevel,\n} from './types.js';\nimport { standardToVoxta } from './macros.js';\n\n/**\n * Editable CCv3 fields (subset that can be changed in editors)\n */\nexport type CCv3Edits = Partial<CCv3Data['data']>;\n\n/**\n * Merge partial CCv3 edits into an existing Voxta character.\n *\n * This function applies only the fields present in `edits` to the original\n * character, preserving Voxta-specific fields like Scripts, TTS, and\n * Augmentations that CCv3 cannot represent.\n *\n * @param original - The original extracted Voxta character\n * @param edits - Partial CCv3 data fields to apply\n * @returns Updated VoxtaCharacter with edits merged\n */\nexport function mergeCharacterEdits(\n  original: ExtractedVoxtaCharacter | VoxtaCharacter,\n  edits: CCv3Edits\n): VoxtaCharacter {\n  // Get the base character data\n  const char: VoxtaCharacter =\n    'data' in original ? { ...original.data } : { ...original };\n\n  const dateNow = new Date().toISOString();\n\n  // Core text fields - only update if present in edits\n  if (edits.name !== undefined) {\n    char.Name = edits.name;\n  }\n\n  if (edits.nickname !== undefined) {\n    char.Label = edits.nickname || undefined;\n  }\n\n  if (edits.description !== undefined) {\n    char.Profile = standardToVoxta(edits.description);\n  }\n\n  if (edits.personality !== undefined) {\n    char.Personality = standardToVoxta(edits.personality ?? '');\n  }\n\n  if (edits.scenario !== undefined) {\n    char.Scenario = standardToVoxta(edits.scenario);\n  }\n\n  if (edits.first_mes !== undefined) {\n    char.FirstMessage = standardToVoxta(edits.first_mes);\n  }\n\n  if (edits.alternate_greetings !== undefined) {\n    char.AlternativeFirstMessages = edits.alternate_greetings.map(standardToVoxta);\n  }\n\n  if (edits.mes_example !== undefined) {\n    char.MessageExamples = standardToVoxta(edits.mes_example ?? '');\n  }\n\n  // System prompts\n  if (edits.system_prompt !== undefined) {\n    char.SystemPrompt = standardToVoxta(edits.system_prompt);\n  }\n\n  if (edits.post_history_instructions !== undefined) {\n    char.PostHistoryInstructions = standardToVoxta(edits.post_history_instructions);\n  }\n\n  // Metadata\n  if (edits.creator !== undefined) {\n    char.Creator = edits.creator || undefined;\n  }\n\n  if (edits.creator_notes !== undefined) {\n    char.CreatorNotes = edits.creator_notes || undefined;\n  }\n\n  if (edits.tags !== undefined) {\n    char.Tags = edits.tags;\n  }\n\n  if (edits.character_version !== undefined) {\n    char.Version = edits.character_version || undefined;\n  }\n\n  // Handle visual_description from extensions\n  if (edits.extensions !== undefined) {\n    const ext = edits.extensions as Record<string, unknown> | undefined;\n    if (ext?.visual_description !== undefined) {\n      char.Description = (ext.visual_description as string) || undefined;\n    }\n  }\n\n  // Update modification timestamp\n  char.DateModified = dateNow;\n\n  return char;\n}\n\n/**\n * Merge partial CCv3 lorebook edits into an existing Voxta book.\n *\n * @param original - The original extracted Voxta book\n * @param edits - CCv3 character_book to merge\n * @returns Updated VoxtaBook with edits merged\n */\nexport function mergeBookEdits(\n  original: ExtractedVoxtaBook | VoxtaBook,\n  edits: CCv3CharacterBook\n): VoxtaBook {\n  const book: VoxtaBook = 'data' in original ? { ...original.data } : { ...original };\n  const dateNow = new Date().toISOString();\n\n  // Update book name if provided\n  if (edits.name !== undefined) {\n    book.Name = edits.name;\n  }\n\n  // Merge entries - match by name (stored as entry ID) or create new\n  if (edits.entries !== undefined) {\n    const existingById = new Map<string, VoxtaBookItem>();\n    for (const item of book.Items || []) {\n      existingById.set(item.Id, item);\n    }\n\n    const newItems: VoxtaBookItem[] = [];\n\n    for (const entry of edits.entries) {\n      // Try to match existing entry by name (which stores the original ID)\n      const existingId = entry.name || '';\n      const existing = existingById.get(existingId);\n\n      if (existing) {\n        // Update existing entry\n        newItems.push({\n          ...existing,\n          Keywords: entry.keys || [],\n          Text: standardToVoxta(entry.content || ''),\n          Weight: entry.priority ?? existing.Weight ?? 10,\n          Deleted: entry.enabled === false,\n          LastUpdated: dateNow,\n        });\n        existingById.delete(existingId);\n      } else {\n        // Create new entry\n        newItems.push({\n          Id: generateUUID(),\n          Keywords: entry.keys || [],\n          Text: standardToVoxta(entry.content || ''),\n          Weight: entry.priority ?? 10,\n          Deleted: entry.enabled === false,\n          CreatedAt: dateNow,\n          LastUpdated: dateNow,\n        });\n      }\n    }\n\n    // Mark remaining entries as deleted (soft delete)\n    for (const remaining of existingById.values()) {\n      newItems.push({\n        ...remaining,\n        Deleted: true,\n        DeletedAt: dateNow,\n      });\n    }\n\n    book.Items = newItems;\n  }\n\n  book.DateModified = dateNow;\n\n  return book;\n}\n\n/**\n * Delta changes to apply to a Voxta package\n */\nexport interface VoxtaDeltas {\n  /** Updated characters by ID */\n  characters?: Map<string, VoxtaCharacter>;\n  /** Updated books by ID */\n  books?: Map<string, VoxtaBook>;\n  /** Updated package metadata (optional) */\n  package?: Partial<VoxtaPackage>;\n}\n\n/**\n * Options for applying deltas\n */\nexport interface ApplyDeltaOptions {\n  compressionLevel?: CompressionLevel;\n}\n\n/** Max total size for delta operations (500MB) */\nconst DELTA_MAX_TOTAL_SIZE = 500 * 1024 * 1024;\n/** Max file size for delta operations (50MB) */\nconst DELTA_MAX_FILE_SIZE = 50 * 1024 * 1024;\n\n/**\n * Apply delta changes to an existing Voxta package.\n *\n * This performs a minimal update - only files that have changed are rewritten.\n * All other files (assets, scenarios, unchanged characters/books) are preserved\n * exactly as they were in the original package.\n *\n * @param originalBuffer - The original .voxpkg file buffer\n * @param deltas - Changes to apply\n * @param options - Compression options\n * @returns New package buffer with changes applied\n */\nexport function applyVoxtaDeltas(\n  originalBuffer: BinaryData,\n  deltas: VoxtaDeltas,\n  options: ApplyDeltaOptions = {}\n): Uint8Array {\n  const { compressionLevel = 6 } = options;\n\n  // Handle SFX archives\n  const zipData = findZipStart(originalBuffer);\n\n  // SECURITY: Preflight check even for delta operations\n  try {\n    preflightZipSizes(zipData, {\n      maxFileSize: DELTA_MAX_FILE_SIZE,\n      maxTotalSize: DELTA_MAX_TOTAL_SIZE,\n      maxFiles: 10000,\n    });\n  } catch (err) {\n    if (err instanceof ZipPreflightError) {\n      throw new SizeLimitError(\n        err.totalSize || err.entrySize || 0,\n        err.maxSize || err.maxEntrySize || DELTA_MAX_TOTAL_SIZE,\n        err.oversizedEntry || 'Voxta package'\n      );\n    }\n    throw err;\n  }\n\n  // Unzip original (now safe - preflight passed)\n  let unzipped: Unzipped;\n  try {\n    unzipped = unzipSync(zipData);\n  } catch (err) {\n    throw new ParseError(\n      `Failed to unzip Voxta package: ${err instanceof Error ? err.message : String(err)}`,\n      'voxta'\n    );\n  }\n\n  // Build new ZIP entries, starting with all originals\n  const zipEntries: Zippable = {};\n\n  for (const [fileName, fileData] of Object.entries(unzipped)) {\n    // Check if this file should be replaced\n    let replaced = false;\n\n    // Check for character.json updates\n    const charMatch = fileName.match(/^Characters\\/([^/]+)\\/character\\.json$/);\n    if (charMatch && deltas.characters?.has(charMatch[1]!)) {\n      const updatedChar = deltas.characters.get(charMatch[1]!)!;\n      zipEntries[fileName] = [\n        fromString(JSON.stringify(updatedChar, null, 2)),\n        { level: compressionLevel },\n      ];\n      replaced = true;\n    }\n\n    // Check for book.json updates\n    const bookMatch = fileName.match(/^Books\\/([^/]+)\\/book\\.json$/);\n    if (bookMatch && deltas.books?.has(bookMatch[1]!)) {\n      const updatedBook = deltas.books.get(bookMatch[1]!)!;\n      zipEntries[fileName] = [\n        fromString(JSON.stringify(updatedBook, null, 2)),\n        { level: compressionLevel },\n      ];\n      replaced = true;\n    }\n\n    // Check for package.json update\n    if (fileName === 'package.json' && deltas.package) {\n      // Merge with existing package metadata\n      const existing = JSON.parse(new TextDecoder().decode(fileData)) as VoxtaPackage;\n      const updated: VoxtaPackage = {\n        ...existing,\n        ...deltas.package,\n        DateModified: new Date().toISOString(),\n      };\n      zipEntries[fileName] = [\n        fromString(JSON.stringify(updated, null, 2)),\n        { level: compressionLevel },\n      ];\n      replaced = true;\n    }\n\n    // Keep original if not replaced\n    if (!replaced) {\n      zipEntries[fileName] = [fileData, { level: compressionLevel }];\n    }\n  }\n\n  // Create new ZIP\n  return zipSync(zipEntries);\n}\n\n/**\n * Async version of applyVoxtaDeltas\n */\nexport async function applyVoxtaDeltasAsync(\n  originalBuffer: BinaryData,\n  deltas: VoxtaDeltas,\n  options: ApplyDeltaOptions = {}\n): Promise<Uint8Array> {\n  return applyVoxtaDeltas(originalBuffer, deltas, options);\n}\n\n/**\n * Character info in package manifest\n */\nexport interface ManifestCharacter {\n  id: string;\n  name: string;\n}\n\n/**\n * Book info in package manifest\n */\nexport interface ManifestBook {\n  id: string;\n  name: string;\n  /** Character IDs that reference this book */\n  usedBy: string[];\n}\n\n/**\n * Scenario info in package manifest\n */\nexport interface ManifestScenario {\n  id: string;\n  name: string;\n}\n\n/**\n * Package manifest for UI display\n */\nexport interface PackageManifest {\n  packageId?: string;\n  packageName?: string;\n  characters: ManifestCharacter[];\n  books: ManifestBook[];\n  scenarios: ManifestScenario[];\n}\n\n/**\n * Get a manifest summary of a Voxta package for UI display.\n *\n * This provides a quick overview of package contents with relationship\n * information (which characters use which books).\n *\n * @param data - Extracted Voxta data from readVoxta()\n * @returns Package manifest for UI display\n */\nexport function getPackageManifest(data: import('./types.js').VoxtaData): PackageManifest {\n  const characters: ManifestCharacter[] = data.characters.map((c) => ({\n    id: c.id,\n    name: c.data.Name,\n  }));\n\n  // Build a map of book ID -> character IDs that use it\n  const bookUsers = new Map<string, string[]>();\n  for (const char of data.characters) {\n    const memoryBooks = char.data.MemoryBooks || [];\n    for (const bookId of memoryBooks) {\n      if (!bookUsers.has(bookId)) {\n        bookUsers.set(bookId, []);\n      }\n      bookUsers.get(bookId)!.push(char.id);\n    }\n  }\n\n  const books: ManifestBook[] = data.books.map((b) => ({\n    id: b.id,\n    name: b.data.Name,\n    usedBy: bookUsers.get(b.id) || [],\n  }));\n\n  const scenarios: ManifestScenario[] = data.scenarios.map((s) => ({\n    id: s.id,\n    name: s.data.Name,\n  }));\n\n  return {\n    packageId: data.package?.Id,\n    packageName: data.package?.Name,\n    characters,\n    books,\n    scenarios,\n  };\n}\n\n/**\n * Options for extracting a character package\n */\nexport interface ExtractCharacterOptions {\n  compressionLevel?: CompressionLevel;\n  /** Include books referenced by the character */\n  includeBooks?: boolean;\n  /** New package name (defaults to character name) */\n  packageName?: string;\n}\n\n/**\n * Extract a single character from a multi-character package.\n *\n * Creates a new standalone .voxpkg containing just the specified character,\n * their assets, and optionally their referenced books.\n *\n * NOTE: Scenarios are NOT extracted since they may contain scripts that\n * reference other characters in the package.\n *\n * @param originalBuffer - The original .voxpkg file buffer\n * @param characterId - ID of the character to extract\n * @param options - Extraction options\n * @returns New package buffer with just the specified character\n */\nexport function extractCharacterPackage(\n  originalBuffer: BinaryData,\n  characterId: string,\n  options: ExtractCharacterOptions = {}\n): Uint8Array {\n  const { compressionLevel = 6, includeBooks = true, packageName } = options;\n\n  // Handle SFX archives\n  const zipData = findZipStart(originalBuffer);\n\n  // SECURITY: Preflight check\n  try {\n    preflightZipSizes(zipData, {\n      maxFileSize: DELTA_MAX_FILE_SIZE,\n      maxTotalSize: DELTA_MAX_TOTAL_SIZE,\n      maxFiles: 10000,\n    });\n  } catch (err) {\n    if (err instanceof ZipPreflightError) {\n      throw new SizeLimitError(\n        err.totalSize || err.entrySize || 0,\n        err.maxSize || err.maxEntrySize || DELTA_MAX_TOTAL_SIZE,\n        err.oversizedEntry || 'Voxta package'\n      );\n    }\n    throw err;\n  }\n\n  // Unzip original (now safe - preflight passed)\n  let unzipped: Unzipped;\n  try {\n    unzipped = unzipSync(zipData);\n  } catch (err) {\n    throw new ParseError(\n      `Failed to unzip Voxta package: ${err instanceof Error ? err.message : String(err)}`,\n      'voxta'\n    );\n  }\n\n  // Find the character's data to get their name and book refs\n  const charJsonPath = `Characters/${characterId}/character.json`;\n  const charJsonData = unzipped[charJsonPath];\n  if (!charJsonData) {\n    throw new ParseError(`Character ${characterId} not found in package`, 'voxta');\n  }\n\n  const charData = JSON.parse(new TextDecoder().decode(charJsonData)) as VoxtaCharacter;\n  const memoryBooks = new Set(charData.MemoryBooks || []);\n\n  // Generate new package ID\n  const newPackageId = generateUUID();\n  const dateNow = new Date().toISOString();\n\n  // Build new ZIP with only this character's files\n  const zipEntries: Zippable = {};\n\n  for (const [fileName, fileData] of Object.entries(unzipped)) {\n    // Skip empty directories\n    if (fileName.endsWith('/') || fileData.length === 0) continue;\n\n    // Include all files under this character's directory\n    if (fileName.startsWith(`Characters/${characterId}/`)) {\n      // Update character.json with new package ID\n      if (fileName === charJsonPath) {\n        const updatedChar: VoxtaCharacter = {\n          ...charData,\n          PackageId: newPackageId,\n          DateModified: dateNow,\n        };\n        zipEntries[fileName] = [\n          fromString(JSON.stringify(updatedChar, null, 2)),\n          { level: compressionLevel },\n        ];\n      } else {\n        zipEntries[fileName] = [fileData, { level: compressionLevel }];\n      }\n      continue;\n    }\n\n    // Include books if requested and referenced by this character\n    if (includeBooks) {\n      const bookMatch = fileName.match(/^Books\\/([^/]+)\\//);\n      if (bookMatch && memoryBooks.has(bookMatch[1]!)) {\n        // Update book.json with new package ID\n        if (fileName.endsWith('/book.json')) {\n          const bookData = JSON.parse(new TextDecoder().decode(fileData)) as VoxtaBook;\n          const updatedBook: VoxtaBook = {\n            ...bookData,\n            PackageId: newPackageId,\n            DateModified: dateNow,\n          };\n          zipEntries[fileName] = [\n            fromString(JSON.stringify(updatedBook, null, 2)),\n            { level: compressionLevel },\n          ];\n        } else {\n          zipEntries[fileName] = [fileData, { level: compressionLevel }];\n        }\n        continue;\n      }\n    }\n  }\n\n  // Create new package.json\n  const newPackage: VoxtaPackage = {\n    $type: 'package',\n    Id: newPackageId,\n    Name: packageName || charData.Name,\n    Version: charData.Version || '1.0.0',\n    Description: charData.Profile || undefined,\n    Creator: charData.Creator,\n    ExplicitContent: charData.ExplicitContent,\n    EntryResource: { Kind: 1, Id: characterId },\n    ThumbnailResource: { Kind: 1, Id: characterId },\n    DateCreated: charData.DateCreated || dateNow,\n    DateModified: dateNow,\n  };\n\n  zipEntries['package.json'] = [\n    fromString(JSON.stringify(newPackage, null, 2)),\n    { level: compressionLevel },\n  ];\n\n  return zipSync(zipEntries);\n}\n\n/**\n * Options for adding a character to a package\n */\nexport interface AddCharacterOptions {\n  compressionLevel?: CompressionLevel;\n  /** Books to include with the character */\n  books?: VoxtaBook[];\n  /** Assets to include (path relative to character dir -> data) */\n  assets?: Map<string, BinaryData>;\n  /** Thumbnail image */\n  thumbnail?: BinaryData;\n}\n\n/**\n * Add a character to an existing Voxta package.\n *\n * @param originalBuffer - The original .voxpkg file buffer\n * @param character - The character to add\n * @param options - Options including books and assets\n * @returns New package buffer with the character added\n */\nexport function addCharacterToPackage(\n  originalBuffer: BinaryData,\n  character: VoxtaCharacter,\n  options: AddCharacterOptions = {}\n): Uint8Array {\n  const { compressionLevel = 6, books = [], assets, thumbnail } = options;\n\n  // Handle SFX archives\n  const zipData = findZipStart(originalBuffer);\n\n  // SECURITY: Preflight check\n  try {\n    preflightZipSizes(zipData, {\n      maxFileSize: DELTA_MAX_FILE_SIZE,\n      maxTotalSize: DELTA_MAX_TOTAL_SIZE,\n      maxFiles: 10000,\n    });\n  } catch (err) {\n    if (err instanceof ZipPreflightError) {\n      throw new SizeLimitError(\n        err.totalSize || err.entrySize || 0,\n        err.maxSize || err.maxEntrySize || DELTA_MAX_TOTAL_SIZE,\n        err.oversizedEntry || 'Voxta package'\n      );\n    }\n    throw err;\n  }\n\n  // Unzip original (now safe - preflight passed)\n  let unzipped: Unzipped;\n  try {\n    unzipped = unzipSync(zipData);\n  } catch (err) {\n    throw new ParseError(\n      `Failed to unzip Voxta package: ${err instanceof Error ? err.message : String(err)}`,\n      'voxta'\n    );\n  }\n\n  // Get existing package metadata\n  const packageJsonData = unzipped['package.json'];\n  let packageMeta: VoxtaPackage | undefined;\n  if (packageJsonData) {\n    packageMeta = JSON.parse(new TextDecoder().decode(packageJsonData)) as VoxtaPackage;\n  }\n\n  const packageId = packageMeta?.Id || generateUUID();\n  const dateNow = new Date().toISOString();\n\n  // Build new ZIP with all original files plus new character\n  const zipEntries: Zippable = {};\n\n  // Copy all original files\n  for (const [fileName, fileData] of Object.entries(unzipped)) {\n    if (fileName === 'package.json') continue; // Will update separately\n    zipEntries[fileName] = [fileData, { level: compressionLevel }];\n  }\n\n  // Ensure character has the right package ID\n  const charToAdd: VoxtaCharacter = {\n    ...character,\n    PackageId: packageId,\n    DateModified: dateNow,\n  };\n\n  // Add character.json\n  const charId = charToAdd.Id;\n  zipEntries[`Characters/${charId}/character.json`] = [\n    fromString(JSON.stringify(charToAdd, null, 2)),\n    { level: compressionLevel },\n  ];\n\n  // Add thumbnail if provided (detect format)\n  if (thumbnail) {\n    const thumbData = thumbnail instanceof Uint8Array ? thumbnail : new Uint8Array(thumbnail);\n    const thumbFormat = detectImageFormat(thumbData);\n    const thumbExt = thumbFormat ? getExtension(thumbFormat) : 'png';\n    zipEntries[`Characters/${charId}/thumbnail.${thumbExt}`] = [thumbnail, { level: compressionLevel }];\n  }\n\n  // Add assets if provided\n  if (assets) {\n    for (const [assetPath, assetData] of assets) {\n      zipEntries[`Characters/${charId}/${assetPath}`] = [assetData, { level: compressionLevel }];\n    }\n  }\n\n  // Add books\n  for (const book of books) {\n    const bookToAdd: VoxtaBook = {\n      ...book,\n      PackageId: packageId,\n      DateModified: dateNow,\n    };\n    zipEntries[`Books/${book.Id}/book.json`] = [\n      fromString(JSON.stringify(bookToAdd, null, 2)),\n      { level: compressionLevel },\n    ];\n  }\n\n  // Update package.json\n  const updatedPackage: VoxtaPackage = packageMeta\n    ? { ...packageMeta, DateModified: dateNow }\n    : {\n        $type: 'package',\n        Id: packageId,\n        Name: charToAdd.Name,\n        Version: '1.0.0',\n        EntryResource: { Kind: 1, Id: charId },\n        ThumbnailResource: { Kind: 1, Id: charId },\n        DateCreated: dateNow,\n        DateModified: dateNow,\n      };\n\n  zipEntries['package.json'] = [\n    fromString(JSON.stringify(updatedPackage, null, 2)),\n    { level: compressionLevel },\n  ];\n\n  return zipSync(zipEntries);\n}\n","/**\n * Voxta Loss Reporting\n *\n * Documents what data is lost when exporting to Voxta format.\n */\n\nimport type { NormalizedCard } from '@character-foundry/schemas';\nimport { hasRisuExtensions, hasRisuScripts, hasDepthPrompt } from '@character-foundry/schemas';\nimport type { VoxtaLossReport } from './types.js';\n\n/**\n * Fields that cannot be represented in Voxta format\n */\nconst ALWAYS_LOST_FIELDS = [\n  'group_only_greetings',    // Voxta doesn't support groups\n];\n\n/**\n * Extension namespaces that are always lost\n */\nconst LOST_EXTENSION_NAMESPACES = [\n  'risuai',                  // All Risu extensions\n  'chub',                    // Chub metadata\n  'depth_prompt',            // SillyTavern depth prompts\n];\n\n/**\n * Check what would be lost when exporting a card to Voxta format\n */\nexport function checkVoxtaLoss(card: NormalizedCard): VoxtaLossReport {\n  const lostFields: string[] = [];\n  const lostAssets: string[] = [];\n  const warnings: string[] = [];\n\n  // Check always-lost fields that have content\n  // Note: system_prompt, post_history_instructions, and alternate_greetings ARE supported by Voxta\n  if (card.groupOnlyGreetings.length > 0) {\n    lostFields.push(`group_only_greetings (${card.groupOnlyGreetings.length} entries)`);\n  }\n\n  // Check extensions\n  const extensions = card.extensions;\n\n  if (hasRisuExtensions(extensions)) {\n    lostFields.push('extensions.risuai.*');\n\n    if (hasRisuScripts(extensions)) {\n      warnings.push('Risu scripts (triggerscript, customScripts) will be lost');\n    }\n  }\n\n  if (hasDepthPrompt(extensions)) {\n    lostFields.push('extensions.depth_prompt');\n    warnings.push('SillyTavern depth prompt will be lost');\n  }\n\n  if (extensions?.chub) {\n    lostFields.push('extensions.chub.*');\n  }\n\n  // Check for any other unknown extensions\n  for (const key of Object.keys(extensions)) {\n    if (key !== 'voxta' && key !== 'visual_description' && !LOST_EXTENSION_NAMESPACES.includes(key)) {\n      lostFields.push(`extensions.${key}`);\n    }\n  }\n\n  // Check character book extensions\n  if (card.characterBook?.extensions) {\n    lostFields.push('character_book.extensions');\n  }\n\n  // Check lorebook entry extensions\n  if (card.characterBook?.entries) {\n    const entriesWithExtensions = card.characterBook.entries.filter(e => e.extensions && Object.keys(e.extensions).length > 0);\n    if (entriesWithExtensions.length > 0) {\n      lostFields.push(`lorebook entries extensions (${entriesWithExtensions.length} entries)`);\n    }\n  }\n\n  return {\n    lostFields,\n    lostAssets,\n    warnings,\n    reason: 'Voxta format does not support extensions field',\n  };\n}\n\n/**\n * Check if export would be lossless\n */\nexport function isVoxtaExportLossless(card: NormalizedCard): boolean {\n  const report = checkVoxtaLoss(card);\n  return report.lostFields.length === 0 && report.lostAssets.length === 0;\n}\n\n/**\n * Format loss report as human-readable string\n */\nexport function formatVoxtaLossReport(report: VoxtaLossReport): string {\n  const lines: string[] = [];\n\n  if (report.lostFields.length === 0 && report.lostAssets.length === 0 && report.warnings.length === 0) {\n    return 'No data will be lost in this export.';\n  }\n\n  lines.push('Voxta Export Loss Report');\n  lines.push('========================');\n  lines.push('');\n  lines.push(`Reason: ${report.reason}`);\n  lines.push('');\n\n  if (report.lostFields.length > 0) {\n    lines.push('Lost Fields:');\n    for (const field of report.lostFields) {\n      lines.push(`  - ${field}`);\n    }\n    lines.push('');\n  }\n\n  if (report.lostAssets.length > 0) {\n    lines.push('Lost Assets:');\n    for (const asset of report.lostAssets) {\n      lines.push(`  - ${asset}`);\n    }\n    lines.push('');\n  }\n\n  if (report.warnings.length > 0) {\n    lines.push('Warnings:');\n    for (const warning of report.warnings) {\n      lines.push(`  ! ${warning}`);\n    }\n  }\n\n  return lines.join('\\n');\n}\n","/**\n * Voxta Asset Enricher\n *\n * Analyzes Voxta asset paths to extract semantic tags and types.\n * e.g. \"Avatars/Default/happy_idle_01.webp\" -> tags: [emotion:happy, state:idle, variant:01]\n */\n\nimport type { ExtractedVoxtaAsset } from './types.js';\n\nexport interface EnrichedAssetMetadata {\n  type: 'icon' | 'sound' | 'custom';\n  tags: string[];\n}\n\n/**\n * Extract metadata from a Voxta asset path/filename\n */\nexport function enrichVoxtaAsset(asset: ExtractedVoxtaAsset): EnrichedAssetMetadata {\n  const tags: string[] = [];\n  let type: EnrichedAssetMetadata['type'] = 'custom';\n\n  const parts = asset.path.split('/');\n  const filename = parts[parts.length - 1] || '';\n  \n  // 1. Determine Type\n  if (asset.path.includes('/Avatars/')) {\n    type = 'icon';\n    \n    // 2. Extract Semantic Tags from Filename\n    // Format: {Emotion}_{State}_{Variant}.ext\n    const nameNoExt = filename.substring(0, filename.lastIndexOf('.'));\n    const nameParts = nameNoExt.split('_');\n    \n    if (nameParts.length >= 3) {\n      const [emotion, state, variant] = nameParts;\n      if (emotion) tags.push(`emotion:${emotion.toLowerCase()}`);\n      if (state) tags.push(`state:${state.toLowerCase()}`);\n      if (variant) tags.push(`variant:${variant}`);\n    } else if (nameParts.length === 2) {\n      const [emotion, state] = nameParts;\n      if (emotion) tags.push(`emotion:${emotion.toLowerCase()}`);\n      if (state) tags.push(`state:${state.toLowerCase()}`);\n    } else if (nameParts.length === 1) {\n      if (nameParts[0]) tags.push(`emotion:${nameParts[0].toLowerCase()}`);\n    }\n    \n  } else if (asset.path.includes('/VoiceSamples/')) {\n    type = 'sound';\n    tags.push('voice');\n  }\n\n  return { type, tags };\n}\n"],"mappings":"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","names":["VoxtaResourceKind","import_core","import_core","import_fflate","import_core","import_zip","import_media"]}