@ncukondo/reference-manager 0.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.
Files changed (117) hide show
  1. package/README.md +167 -0
  2. package/bin/reference-manager.js +5 -0
  3. package/dist/chunks/detector-BF8Mcc72.js +1415 -0
  4. package/dist/chunks/detector-BF8Mcc72.js.map +1 -0
  5. package/dist/cli/commands/add.d.ts +22 -0
  6. package/dist/cli/commands/add.d.ts.map +1 -0
  7. package/dist/cli/commands/index.d.ts +16 -0
  8. package/dist/cli/commands/index.d.ts.map +1 -0
  9. package/dist/cli/commands/list.d.ts +15 -0
  10. package/dist/cli/commands/list.d.ts.map +1 -0
  11. package/dist/cli/commands/remove.d.ts +19 -0
  12. package/dist/cli/commands/remove.d.ts.map +1 -0
  13. package/dist/cli/commands/search.d.ts +16 -0
  14. package/dist/cli/commands/search.d.ts.map +1 -0
  15. package/dist/cli/commands/server.d.ts +32 -0
  16. package/dist/cli/commands/server.d.ts.map +1 -0
  17. package/dist/cli/commands/update.d.ts +20 -0
  18. package/dist/cli/commands/update.d.ts.map +1 -0
  19. package/dist/cli/helpers.d.ts +61 -0
  20. package/dist/cli/helpers.d.ts.map +1 -0
  21. package/dist/cli/index.d.ts +13 -0
  22. package/dist/cli/index.d.ts.map +1 -0
  23. package/dist/cli/output/bibtex.d.ts +6 -0
  24. package/dist/cli/output/bibtex.d.ts.map +1 -0
  25. package/dist/cli/output/index.d.ts +7 -0
  26. package/dist/cli/output/index.d.ts.map +1 -0
  27. package/dist/cli/output/json.d.ts +6 -0
  28. package/dist/cli/output/json.d.ts.map +1 -0
  29. package/dist/cli/output/pretty.d.ts +6 -0
  30. package/dist/cli/output/pretty.d.ts.map +1 -0
  31. package/dist/cli/server-client.d.ts +38 -0
  32. package/dist/cli/server-client.d.ts.map +1 -0
  33. package/dist/cli/server-detection.d.ts +27 -0
  34. package/dist/cli/server-detection.d.ts.map +1 -0
  35. package/dist/cli.js +981 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/config/defaults.d.ts +29 -0
  38. package/dist/config/defaults.d.ts.map +1 -0
  39. package/dist/config/index.d.ts +10 -0
  40. package/dist/config/index.d.ts.map +1 -0
  41. package/dist/config/loader.d.ts +27 -0
  42. package/dist/config/loader.d.ts.map +1 -0
  43. package/dist/config/schema.d.ts +129 -0
  44. package/dist/config/schema.d.ts.map +1 -0
  45. package/dist/core/csl-json/parser.d.ts +9 -0
  46. package/dist/core/csl-json/parser.d.ts.map +1 -0
  47. package/dist/core/csl-json/serializer.d.ts +15 -0
  48. package/dist/core/csl-json/serializer.d.ts.map +1 -0
  49. package/dist/core/csl-json/types.d.ts +124 -0
  50. package/dist/core/csl-json/types.d.ts.map +1 -0
  51. package/dist/core/csl-json/validator.d.ts +19 -0
  52. package/dist/core/csl-json/validator.d.ts.map +1 -0
  53. package/dist/core/identifier/generator.d.ts +17 -0
  54. package/dist/core/identifier/generator.d.ts.map +1 -0
  55. package/dist/core/identifier/normalize.d.ts +20 -0
  56. package/dist/core/identifier/normalize.d.ts.map +1 -0
  57. package/dist/core/identifier/uuid.d.ts +24 -0
  58. package/dist/core/identifier/uuid.d.ts.map +1 -0
  59. package/dist/core/index.d.ts +15 -0
  60. package/dist/core/index.d.ts.map +1 -0
  61. package/dist/core/library.d.ts +73 -0
  62. package/dist/core/library.d.ts.map +1 -0
  63. package/dist/core/reference.d.ts +86 -0
  64. package/dist/core/reference.d.ts.map +1 -0
  65. package/dist/features/duplicate/detector.d.ts +19 -0
  66. package/dist/features/duplicate/detector.d.ts.map +1 -0
  67. package/dist/features/duplicate/index.d.ts +6 -0
  68. package/dist/features/duplicate/index.d.ts.map +1 -0
  69. package/dist/features/duplicate/types.d.ts +45 -0
  70. package/dist/features/duplicate/types.d.ts.map +1 -0
  71. package/dist/features/file-watcher/file-watcher.d.ts +83 -0
  72. package/dist/features/file-watcher/file-watcher.d.ts.map +1 -0
  73. package/dist/features/file-watcher/index.d.ts +2 -0
  74. package/dist/features/file-watcher/index.d.ts.map +1 -0
  75. package/dist/features/merge/index.d.ts +8 -0
  76. package/dist/features/merge/index.d.ts.map +1 -0
  77. package/dist/features/merge/three-way.d.ts +16 -0
  78. package/dist/features/merge/three-way.d.ts.map +1 -0
  79. package/dist/features/merge/types.d.ts +74 -0
  80. package/dist/features/merge/types.d.ts.map +1 -0
  81. package/dist/features/search/index.d.ts +9 -0
  82. package/dist/features/search/index.d.ts.map +1 -0
  83. package/dist/features/search/matcher.d.ts +18 -0
  84. package/dist/features/search/matcher.d.ts.map +1 -0
  85. package/dist/features/search/normalizer.d.ts +12 -0
  86. package/dist/features/search/normalizer.d.ts.map +1 -0
  87. package/dist/features/search/sorter.d.ts +11 -0
  88. package/dist/features/search/sorter.d.ts.map +1 -0
  89. package/dist/features/search/tokenizer.d.ts +6 -0
  90. package/dist/features/search/tokenizer.d.ts.map +1 -0
  91. package/dist/features/search/types.d.ts +77 -0
  92. package/dist/features/search/types.d.ts.map +1 -0
  93. package/dist/index.d.ts +13 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +559 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/server/index.d.ts +9 -0
  98. package/dist/server/index.d.ts.map +1 -0
  99. package/dist/server/portfile.d.ts +43 -0
  100. package/dist/server/portfile.d.ts.map +1 -0
  101. package/dist/server/routes/health.d.ts +7 -0
  102. package/dist/server/routes/health.d.ts.map +1 -0
  103. package/dist/server/routes/references.d.ts +9 -0
  104. package/dist/server/routes/references.d.ts.map +1 -0
  105. package/dist/server.js +91 -0
  106. package/dist/server.js.map +1 -0
  107. package/dist/utils/backup.d.ts +21 -0
  108. package/dist/utils/backup.d.ts.map +1 -0
  109. package/dist/utils/file.d.ts +9 -0
  110. package/dist/utils/file.d.ts.map +1 -0
  111. package/dist/utils/hash.d.ts +9 -0
  112. package/dist/utils/hash.d.ts.map +1 -0
  113. package/dist/utils/index.d.ts +5 -0
  114. package/dist/utils/index.d.ts.map +1 -0
  115. package/dist/utils/logger.d.ts +8 -0
  116. package/dist/utils/logger.d.ts.map +1 -0
  117. package/package.json +72 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sources":["../src/server/portfile.ts","../src/cli/commands/add.ts","../src/cli/output/bibtex.ts","../src/cli/output/json.ts","../src/cli/output/pretty.ts","../src/cli/commands/list.ts","../src/cli/commands/search.ts","../src/cli/commands/server.ts","../src/cli/commands/update.ts","../src/cli/helpers.ts","../src/cli/server-client.ts","../src/cli/server-detection.ts","../src/cli/index.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\n/**\n * Get the default portfile path.\n * @returns The path to the portfile in the system's temp directory.\n */\nexport function getPortfilePath(): string {\n const tmpDir = os.tmpdir();\n return path.join(tmpDir, \"reference-manager\", \"server.port\");\n}\n\n/**\n * Write port, PID, library path, and optionally started_at to the portfile.\n * @param portfilePath - Path to the portfile\n * @param port - Server port number\n * @param pid - Server process ID\n * @param library - Path to the library file\n * @param started_at - Optional ISO 8601 timestamp of when the server started\n */\nexport async function writePortfile(\n portfilePath: string,\n port: number,\n pid: number,\n library: string,\n started_at?: string\n): Promise<void> {\n // Create parent directory if it doesn't exist\n const dir = path.dirname(portfilePath);\n await fs.mkdir(dir, { recursive: true });\n\n // Write portfile with port, pid, library, and optionally started_at\n const data: Record<string, unknown> = { port, pid, library };\n if (started_at !== undefined) {\n data.started_at = started_at;\n }\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(portfilePath, content, \"utf-8\");\n}\n\n/**\n * Read port, PID, library, and optionally started_at from the portfile.\n * @param portfilePath - Path to the portfile\n * @returns Object with port, pid, library (if present), and started_at (if present), or null if file doesn't exist or is invalid\n */\nexport async function readPortfile(portfilePath: string): Promise<{\n port: number;\n pid: number;\n library?: string;\n started_at?: string;\n} | null> {\n try {\n const content = await fs.readFile(portfilePath, \"utf-8\");\n const data = JSON.parse(content);\n\n // Validate required fields (port and pid are always required)\n if (typeof data.port !== \"number\" || typeof data.pid !== \"number\") {\n return null;\n }\n\n // Build result with required fields\n const result: {\n port: number;\n pid: number;\n library?: string;\n started_at?: string;\n } = {\n port: data.port,\n pid: data.pid,\n };\n\n // Add optional fields if present\n if (typeof data.library === \"string\") {\n result.library = data.library;\n }\n if (typeof data.started_at === \"string\") {\n result.started_at = data.started_at;\n }\n\n return result;\n } catch {\n // File doesn't exist or invalid JSON\n return null;\n }\n}\n\n/**\n * Check if the portfile exists.\n * @param portfilePath - Path to the portfile\n * @returns True if portfile exists, false otherwise\n */\nexport async function portfileExists(portfilePath: string): Promise<boolean> {\n try {\n await fs.access(portfilePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Remove the portfile.\n * @param portfilePath - Path to the portfile\n */\nexport async function removePortfile(portfilePath: string): Promise<void> {\n try {\n await fs.unlink(portfilePath);\n } catch {\n // Ignore if file doesn't exist\n }\n}\n\n/**\n * Check if a process with the given PID is running.\n * @param pid - Process ID to check\n * @returns True if process is running, false otherwise\n */\nexport function isProcessRunning(pid: number): boolean {\n if (pid <= 0) {\n return false;\n }\n\n try {\n // Sending signal 0 checks if the process exists without killing it\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport { detectDuplicate } from \"../../features/duplicate/detector.js\";\nimport type { DuplicateMatch } from \"../../features/duplicate/types.js\";\n\nexport interface AddOptions {\n force: boolean;\n}\n\nexport interface AddResult {\n added: boolean;\n item: CslItem;\n idChanged: boolean;\n originalId?: string | undefined;\n duplicate?: DuplicateMatch | undefined;\n}\n\n/**\n * Generate suffix for ID collision (a, b, c, ..., z, aa, ab, ...)\n */\nfunction generateSuffix(index: number): string {\n const alphabet = \"abcdefghijklmnopqrstuvwxyz\";\n let suffix = \"\";\n let n = index;\n\n do {\n suffix = alphabet[n % 26] + suffix;\n n = Math.floor(n / 26) - 1;\n } while (n >= 0);\n\n return suffix;\n}\n\n/**\n * Resolve ID collision by appending suffix\n */\nfunction resolveIdCollision(baseId: string, existing: CslItem[]): { id: string; changed: boolean } {\n const existingIds = new Set(existing.map((item) => item.id));\n\n if (!existingIds.has(baseId)) {\n return { id: baseId, changed: false };\n }\n\n // Find next available suffix\n let index = 0;\n let newId: string;\n\n do {\n const suffix = generateSuffix(index);\n newId = `${baseId}${suffix}`;\n index++;\n } while (existingIds.has(newId));\n\n return { id: newId, changed: true };\n}\n\n/**\n * Add a new reference to the library.\n *\n * @param existing - Existing library items\n * @param newItem - New item to add\n * @param options - Add options\n * @returns Add result\n */\nexport async function add(\n existing: CslItem[],\n newItem: CslItem,\n options: AddOptions\n): Promise<AddResult> {\n // 1. Check for content duplicate (unless force=true)\n if (!options.force) {\n const duplicateResult = detectDuplicate(newItem, existing);\n\n if (duplicateResult.matches.length > 0) {\n // Duplicate found, reject\n return {\n added: false,\n item: newItem,\n idChanged: false,\n duplicate: duplicateResult.matches[0],\n };\n }\n }\n\n // 2. Resolve ID collision\n const originalId = newItem.id;\n const { id, changed } = resolveIdCollision(originalId, existing);\n\n const finalItem: CslItem = {\n ...newItem,\n id,\n };\n\n return {\n added: true,\n item: finalItem,\n idChanged: changed,\n originalId: changed ? originalId : undefined,\n };\n}\n","import type { CslItem } from \"../../core/csl-json/types\";\nimport type { Reference } from \"../../core/reference\";\n\n/**\n * Map CSL-JSON type to BibTeX entry type\n */\nfunction mapEntryType(cslType: string): string {\n const typeMap: Record<string, string> = {\n article: \"article\",\n \"article-journal\": \"article\",\n \"article-magazine\": \"article\",\n \"article-newspaper\": \"article\",\n book: \"book\",\n chapter: \"inbook\",\n \"paper-conference\": \"inproceedings\",\n thesis: \"phdthesis\",\n report: \"techreport\",\n webpage: \"misc\",\n };\n\n return typeMap[cslType] || \"misc\";\n}\n\n/**\n * Format a single author as \"Family, Given\"\n */\nfunction formatBibtexAuthor(author: {\n family?: string | undefined;\n given?: string | undefined;\n literal?: string | undefined;\n}): string {\n if (author.literal) {\n return author.literal;\n }\n const family = author.family || \"\";\n const given = author.given || \"\";\n return given ? `${family}, ${given}` : family;\n}\n\n/**\n * Format authors for BibTeX as \"Family1, Given1 and Family2, Given2\"\n */\nfunction formatBibtexAuthors(\n authors: Array<{\n family?: string | undefined;\n given?: string | undefined;\n literal?: string | undefined;\n \"dropping-particle\"?: string | undefined;\n \"non-dropping-particle\"?: string | undefined;\n suffix?: string | undefined;\n }>\n): string {\n return authors.map(formatBibtexAuthor).join(\" and \");\n}\n\n/**\n * Format a BibTeX field\n */\nfunction formatField(name: string, value: string): string {\n return ` ${name} = {${value}},`;\n}\n\n/**\n * Add basic bibliographic fields to BibTeX entry\n */\nfunction addBasicFields(lines: string[], item: CslItem): void {\n // Title\n if (item.title) {\n lines.push(formatField(\"title\", item.title));\n }\n\n // Authors\n if (item.author && item.author.length > 0) {\n lines.push(formatField(\"author\", formatBibtexAuthors(item.author)));\n }\n\n // Year\n const year = item.issued?.[\"date-parts\"]?.[0]?.[0];\n if (year) {\n lines.push(formatField(\"year\", String(year)));\n }\n}\n\n/**\n * Add publication details to BibTeX entry\n */\nfunction addPublicationDetails(lines: string[], item: CslItem, entryType: string): void {\n // Container-title (journal or booktitle depending on type)\n if (item[\"container-title\"]) {\n if (entryType === \"article\") {\n lines.push(formatField(\"journal\", item[\"container-title\"]));\n } else if (entryType === \"inbook\" || entryType === \"inproceedings\") {\n lines.push(formatField(\"booktitle\", item[\"container-title\"]));\n }\n }\n\n // Volume\n if (item.volume) {\n lines.push(formatField(\"volume\", item.volume));\n }\n\n // Issue -> number\n if (item.issue) {\n lines.push(formatField(\"number\", item.issue));\n }\n\n // Pages\n if (item.page) {\n lines.push(formatField(\"pages\", item.page));\n }\n\n // Publisher\n if (item.publisher) {\n lines.push(formatField(\"publisher\", item.publisher));\n }\n}\n\n/**\n * Add identifier fields to BibTeX entry\n */\nfunction addIdentifierFields(lines: string[], item: CslItem): void {\n // DOI\n if (item.DOI) {\n lines.push(formatField(\"doi\", item.DOI));\n }\n\n // URL\n if (item.URL) {\n lines.push(formatField(\"url\", item.URL));\n }\n\n // PMID or PMCID in note field\n if (item.PMID) {\n lines.push(formatField(\"note\", `PMID: ${item.PMID}`));\n } else if (item.PMCID) {\n lines.push(formatField(\"note\", `PMCID: ${item.PMCID}`));\n }\n}\n\n/**\n * Format a single reference as BibTeX entry\n */\nfunction formatSingleBibtexEntry(ref: Reference): string {\n const item: CslItem = ref.getItem();\n const entryType = mapEntryType(item.type);\n const lines: string[] = [];\n\n // Opening line: @type{citation-key,\n lines.push(`@${entryType}{${item.id},`);\n\n // Add fields in sections\n addBasicFields(lines, item);\n addPublicationDetails(lines, item, entryType);\n addIdentifierFields(lines, item);\n\n // Closing brace\n lines.push(\"}\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format references as BibTeX\n */\nexport function formatBibtex(references: Reference[]): string {\n if (references.length === 0) {\n return \"\";\n }\n\n return references.map(formatSingleBibtexEntry).join(\"\\n\\n\");\n}\n","import type { Reference } from \"../../core/reference\";\n\n/**\n * Format references as compact JSON\n */\nexport function formatJson(references: Reference[]): string {\n const items = references.map((ref) => ref.getItem());\n return JSON.stringify(items);\n}\n","import type { Reference } from \"../../core/reference\";\n\n/**\n * Format a single author as \"Family, Given-Initial.\"\n */\nfunction formatAuthor(author: {\n family?: string | undefined;\n given?: string | undefined;\n}): string {\n const family = author.family || \"\";\n const givenInitial = author.given ? `${author.given.charAt(0)}.` : \"\";\n return givenInitial ? `${family}, ${givenInitial}` : family;\n}\n\n/**\n * Format authors array as \"Family1, G.; Family2, G.\"\n */\nfunction formatAuthors(\n authors: Array<{\n family?: string | undefined;\n given?: string | undefined;\n literal?: string | undefined;\n \"dropping-particle\"?: string | undefined;\n \"non-dropping-particle\"?: string | undefined;\n suffix?: string | undefined;\n }>\n): string {\n return authors.map(formatAuthor).join(\"; \");\n}\n\n/**\n * Format a single reference in pretty format\n */\nfunction formatSingleReference(ref: Reference): string {\n const item = ref.getItem();\n const lines: string[] = [];\n\n // Header line: [id] title\n const header = item.title ? `[${item.id}] ${item.title}` : `[${item.id}]`;\n lines.push(header);\n\n // Authors (if present)\n if (item.author && item.author.length > 0) {\n lines.push(` Authors: ${formatAuthors(item.author)}`);\n }\n\n // Year\n const year = item.issued?.[\"date-parts\"]?.[0]?.[0];\n lines.push(` Year: ${year || \"(no year)\"}`);\n\n // Type\n lines.push(` Type: ${item.type}`);\n\n // DOI (if present)\n if (item.DOI) {\n lines.push(` DOI: ${item.DOI}`);\n }\n\n // PMID (if present)\n if (item.PMID) {\n lines.push(` PMID: ${item.PMID}`);\n }\n\n // PMCID (if present)\n if (item.PMCID) {\n lines.push(` PMCID: ${item.PMCID}`);\n }\n\n // URL (if present)\n if (item.URL) {\n lines.push(` URL: ${item.URL}`);\n }\n\n // UUID (always)\n lines.push(` UUID: ${ref.getUuid()}`);\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format references in pretty-printed format\n */\nexport function formatPretty(references: Reference[]): string {\n if (references.length === 0) {\n return \"\";\n }\n\n return references.map(formatSingleReference).join(\"\\n\\n\");\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport { Reference } from \"../../core/reference.js\";\nimport { formatBibtex } from \"../output/bibtex.js\";\nimport { formatJson } from \"../output/json.js\";\nimport { formatPretty } from \"../output/pretty.js\";\n\nexport interface ListOptions {\n json?: boolean;\n idsOnly?: boolean;\n uuid?: boolean;\n bibtex?: boolean;\n}\n\n/**\n * List all references in the library.\n *\n * @param items - Array of CSL items\n * @param options - Output format options\n */\nexport async function list(items: CslItem[], options: ListOptions): Promise<void> {\n // Check for conflicting output options\n const outputOptions = [options.json, options.idsOnly, options.uuid, options.bibtex].filter(\n Boolean\n );\n\n if (outputOptions.length > 1) {\n throw new Error(\n \"Multiple output formats specified. Only one of --json, --ids-only, --uuid, --bibtex can be used.\"\n );\n }\n\n // Convert CslItems to References for output formatters\n const references = items.map((item) => new Reference(item));\n\n // Output based on selected format\n if (options.json) {\n process.stdout.write(formatJson(references));\n } else if (options.idsOnly) {\n for (const item of items) {\n process.stdout.write(`${item.id}\\n`);\n }\n } else if (options.uuid) {\n for (const item of items) {\n if (item.custom) {\n process.stdout.write(`${item.custom.uuid}\\n`);\n }\n }\n } else if (options.bibtex) {\n process.stdout.write(formatBibtex(references));\n } else {\n // Default: pretty format\n process.stdout.write(formatPretty(references));\n }\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport { Reference } from \"../../core/reference.js\";\nimport { search as searchReferences } from \"../../features/search/matcher.js\";\nimport { sortResults } from \"../../features/search/sorter.js\";\nimport { tokenize } from \"../../features/search/tokenizer.js\";\nimport { formatBibtex } from \"../output/bibtex.js\";\nimport { formatJson } from \"../output/json.js\";\nimport { formatPretty } from \"../output/pretty.js\";\n\nexport interface SearchOptions {\n json?: boolean;\n idsOnly?: boolean;\n uuid?: boolean;\n bibtex?: boolean;\n}\n\n/**\n * Search references in the library.\n *\n * @param items - Array of CSL items\n * @param query - Search query string\n * @param options - Output format options\n */\nexport async function search(\n items: CslItem[],\n query: string,\n options: SearchOptions\n): Promise<void> {\n // Check for conflicting output options\n const outputOptions = [options.json, options.idsOnly, options.uuid, options.bibtex].filter(\n Boolean\n );\n\n if (outputOptions.length > 1) {\n throw new Error(\n \"Multiple output formats specified. Only one of --json, --ids-only, --uuid, --bibtex can be used.\"\n );\n }\n\n // Tokenize query\n const searchQuery = tokenize(query);\n\n // Search\n const results = searchReferences(items, searchQuery.tokens);\n\n // Sort results\n const sorted = sortResults(results);\n\n // Extract items from results\n const matchedItems = sorted.map((result) => result.reference);\n\n // Convert to References for output formatters\n const references = matchedItems.map((item) => new Reference(item));\n\n // Output based on selected format\n if (options.json) {\n process.stdout.write(formatJson(references));\n } else if (options.idsOnly) {\n for (const item of matchedItems) {\n process.stdout.write(`${item.id}\\n`);\n }\n } else if (options.uuid) {\n for (const item of matchedItems) {\n if (item.custom) {\n process.stdout.write(`${item.custom.uuid}\\n`);\n }\n }\n } else if (options.bibtex) {\n process.stdout.write(formatBibtex(references));\n } else {\n // Default: pretty format\n process.stdout.write(formatPretty(references));\n }\n}\n","import {\n isProcessRunning,\n readPortfile,\n removePortfile,\n writePortfile,\n} from \"../../server/portfile.js\";\n\nexport interface ServerStartOptions {\n port?: number;\n daemon?: boolean;\n library: string;\n portfilePath: string;\n}\n\nexport interface ServerInfo {\n port: number;\n pid: number;\n library: string;\n started_at?: string;\n}\n\n/**\n * Start HTTP server.\n *\n * @param options - Server start options\n */\nexport async function serverStart(options: ServerStartOptions): Promise<void> {\n // Check if server is already running\n const existingStatus = await serverStatus(options.portfilePath);\n if (existingStatus !== null) {\n throw new Error(\"Server is already running\");\n }\n\n // Determine port (use provided port or default to 3000 for testing)\n const port = options.port ?? 3000;\n\n // For daemon mode, create portfile with current process PID\n // (In real implementation, this would be the spawned server process PID)\n const pid = process.pid;\n const started_at = new Date().toISOString();\n\n await writePortfile(options.portfilePath, port, pid, options.library, started_at);\n\n // In real implementation, this would spawn the server process\n // For now, we just create the portfile for testing purposes\n}\n\n/**\n * Stop running server.\n *\n * @param portfilePath - Path to the portfile\n */\nexport async function serverStop(portfilePath: string): Promise<void> {\n // Check if server is running\n const status = await serverStatus(portfilePath);\n if (status === null) {\n throw new Error(\"Server is not running\");\n }\n\n // In real implementation, send SIGTERM to the server process\n // For testing, we just remove the portfile\n await removePortfile(portfilePath);\n\n process.stdout.write(\"Server stopped successfully\\n\");\n}\n\n/**\n * Get server status.\n *\n * @param portfilePath - Path to the portfile\n * @returns Server info if running, null otherwise\n */\nexport async function serverStatus(portfilePath: string): Promise<ServerInfo | null> {\n // Read portfile\n const portfileData = await readPortfile(portfilePath);\n if (portfileData === null) {\n return null;\n }\n\n // Check if process is still running\n if (!isProcessRunning(portfileData.pid)) {\n // Process not found, cleanup stale portfile\n await removePortfile(portfilePath);\n return null;\n }\n\n // Return server info\n const result: ServerInfo = {\n port: portfileData.port,\n pid: portfileData.pid,\n library: portfileData.library ?? \"\",\n };\n\n if (portfileData.started_at !== undefined) {\n result.started_at = portfileData.started_at;\n }\n\n return result;\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\n\nexport interface UpdateOptions {\n byUuid: boolean;\n}\n\nexport interface UpdateResult {\n updated: boolean;\n item?: CslItem | undefined;\n items: CslItem[];\n}\n\n/**\n * Update a reference in the library.\n *\n * @param items - Library items\n * @param identifier - Reference ID or UUID\n * @param updates - Partial updates to apply\n * @param options - Update options\n * @returns Update result\n */\nexport async function update(\n items: CslItem[],\n identifier: string,\n updates: Partial<CslItem>,\n options: UpdateOptions\n): Promise<UpdateResult> {\n let foundIndex = -1;\n\n if (options.byUuid) {\n // Find by UUID\n foundIndex = items.findIndex((item) => item.custom?.uuid === identifier);\n } else {\n // Find by ID\n foundIndex = items.findIndex((item) => item.id === identifier);\n }\n\n if (foundIndex === -1) {\n // Not found\n return {\n updated: false,\n items,\n };\n }\n\n const existingItem = items[foundIndex];\n if (!existingItem) {\n // Should not happen, but TypeScript needs this\n return {\n updated: false,\n items,\n };\n }\n\n // Merge updates with existing item\n const updatedItem: CslItem = {\n ...existingItem,\n ...updates,\n // Ensure required fields\n id: updates.id ?? existingItem.id,\n type: updates.type ?? existingItem.type,\n // Preserve UUID and created_at\n custom: {\n ...(existingItem.custom || {}),\n ...(updates.custom || {}),\n uuid: existingItem.custom?.uuid || \"\",\n created_at: existingItem.custom?.created_at || new Date().toISOString(),\n // Update timestamp\n timestamp: new Date().toISOString(),\n },\n };\n\n const updatedItems = [...items.slice(0, foundIndex), updatedItem, ...items.slice(foundIndex + 1)];\n\n return {\n updated: true,\n item: updatedItem,\n items: updatedItems,\n };\n}\n","/**\n * CLI Helper Functions\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { stdin, stdout } from \"node:process\";\nimport { loadConfig } from \"../config/loader.js\";\nimport type { Config } from \"../config/schema.js\";\n\n/**\n * Output format type\n */\nexport type OutputFormat = \"pretty\" | \"json\" | \"ids-only\" | \"uuid\" | \"bibtex\";\n\n/**\n * CLI options interface\n */\nexport interface CliOptions {\n library?: string;\n logLevel?: \"silent\" | \"info\" | \"debug\";\n config?: string;\n quiet?: boolean;\n verbose?: boolean;\n backup?: boolean;\n backupDir?: string;\n json?: boolean;\n idsOnly?: boolean;\n uuid?: boolean;\n bibtex?: boolean;\n}\n\n/**\n * Read JSON input from file or stdin\n * @param file - File path (optional, defaults to stdin)\n * @returns JSON string\n */\nexport async function readJsonInput(file?: string): Promise<string> {\n if (file) {\n // Read from file\n try {\n return readFileSync(file, \"utf-8\");\n } catch (error) {\n throw new Error(\n `I/O error: Cannot read file ${file}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n // Read from stdin\n const chunks: Buffer[] = [];\n for await (const chunk of stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\n/**\n * Parse JSON input\n * @param input - JSON string\n * @returns Parsed JSON object or array\n */\nexport function parseJsonInput(input: string): unknown {\n if (!input || input.trim() === \"\") {\n throw new Error(\"Parse error: Empty input\");\n }\n\n try {\n return JSON.parse(input);\n } catch (error) {\n throw new Error(\n `Parse error: Invalid JSON: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * Load config with CLI argument overrides\n * @param options - CLI options\n * @returns Config with overrides applied\n */\nexport async function loadConfigWithOverrides(options: CliOptions): Promise<Config> {\n // Load base config\n // Note: options.config is currently ignored as loadConfig uses cwd and userConfigPath\n const config = await loadConfig();\n\n // Apply CLI overrides\n const overrides: Partial<Config> = {};\n\n // Library path\n if (options.library) {\n overrides.library = options.library;\n }\n\n // Log level\n if (options.quiet) {\n overrides.logLevel = \"silent\";\n } else if (options.verbose) {\n overrides.logLevel = \"debug\";\n } else if (options.logLevel) {\n overrides.logLevel = options.logLevel;\n }\n\n // Backup settings\n if (options.backup !== undefined || options.backupDir) {\n overrides.backup = {\n ...config.backup,\n ...(options.backup !== undefined && { enabled: options.backup }),\n ...(options.backupDir && { directory: options.backupDir }),\n };\n }\n\n return { ...config, ...overrides };\n}\n\n/**\n * Get output format from options\n * @param options - CLI options\n * @returns Output format\n * @throws Error if multiple formats specified\n */\nexport function getOutputFormat(options: CliOptions): OutputFormat {\n const formats: OutputFormat[] = [];\n\n if (options.json) formats.push(\"json\");\n if (options.idsOnly) formats.push(\"ids-only\");\n if (options.uuid) formats.push(\"uuid\");\n if (options.bibtex) formats.push(\"bibtex\");\n\n if (formats.length > 1) {\n throw new Error(\n \"Multiple output formats specified. Only one of --json, --ids-only, --uuid, --bibtex can be used.\"\n );\n }\n\n return formats[0] || \"pretty\";\n}\n\n/**\n * Check if running in TTY\n * @returns True if stdin and stdout are TTY\n */\nexport function isTTY(): boolean {\n return Boolean(stdin.isTTY && stdout.isTTY);\n}\n\n/**\n * Read confirmation from user (y/N)\n * @param prompt - Confirmation prompt message\n * @returns True if user confirmed (y/yes), false otherwise\n */\nexport async function readConfirmation(prompt: string): Promise<boolean> {\n // If not TTY, auto-confirm\n if (!isTTY()) {\n return true;\n }\n\n // Display prompt\n stdout.write(`${prompt} (y/N): `);\n\n // Read input\n const chunks: Buffer[] = [];\n for await (const chunk of stdin) {\n chunks.push(chunk as Buffer);\n // Break after first line\n const input = Buffer.concat(chunks).toString(\"utf-8\");\n if (input.includes(\"\\n\")) {\n break;\n }\n }\n\n const input = Buffer.concat(chunks).toString(\"utf-8\").trim().toLowerCase();\n return input === \"y\" || input === \"yes\";\n}\n","import type { CslItem } from \"../core/csl-json/types.js\";\n\n/**\n * Client for communicating with the reference-manager HTTP server.\n */\nexport class ServerClient {\n constructor(private baseUrl: string) {}\n\n /**\n * Get all references from the server.\n * @returns Array of CSL items\n */\n async getAll(): Promise<CslItem[]> {\n const url = `${this.baseUrl}/api/references`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n\n return (await response.json()) as CslItem[];\n }\n\n /**\n * Find reference by UUID.\n * @param uuid - Reference UUID\n * @returns CSL item or null if not found\n */\n async findByUuid(uuid: string): Promise<CslItem | null> {\n const url = `${this.baseUrl}/api/references/${uuid}`;\n const response = await fetch(url);\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n\n return (await response.json()) as CslItem;\n }\n\n /**\n * Add new reference to the library.\n * @param item - CSL item to add\n * @returns Created CSL item with UUID\n */\n async add(item: CslItem): Promise<CslItem> {\n const url = `${this.baseUrl}/api/references`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(item),\n });\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n\n return (await response.json()) as CslItem;\n }\n\n /**\n * Update existing reference.\n * @param uuid - Reference UUID\n * @param item - Updated CSL item\n * @returns Updated CSL item\n */\n async update(uuid: string, item: CslItem): Promise<CslItem> {\n const url = `${this.baseUrl}/api/references/${uuid}`;\n const response = await fetch(url, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(item),\n });\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n\n return (await response.json()) as CslItem;\n }\n\n /**\n * Remove reference by UUID.\n * @param uuid - Reference UUID\n */\n async remove(uuid: string): Promise<void> {\n const url = `${this.baseUrl}/api/references/${uuid}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n });\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n }\n}\n","import { spawn } from \"node:child_process\";\nimport type { Config } from \"../config/schema.js\";\nimport {\n getPortfilePath,\n isProcessRunning,\n portfileExists,\n readPortfile,\n removePortfile,\n} from \"../server/portfile.js\";\n\n/**\n * Server connection information.\n */\nexport interface ServerConnection {\n baseUrl: string;\n pid: number;\n}\n\n/**\n * Get server connection if available.\n * @param libraryPath - Path to the library file\n * @param config - Configuration\n * @returns Server connection or null if not available\n */\nexport async function getServerConnection(\n libraryPath: string,\n config: Config\n): Promise<ServerConnection | null> {\n const portfilePath = getPortfilePath();\n const portfileData = await readPortfile(portfilePath);\n\n // Check if portfile exists\n if (!portfileData) {\n // No server running\n if (config.server.autoStart) {\n // Auto-start server\n await startServerDaemon(libraryPath, config);\n await waitForPortfile(5000); // 5 second timeout\n // Retry connection\n return await getServerConnection(libraryPath, config);\n }\n return null;\n }\n\n // Check if process is running\n if (!isProcessRunning(portfileData.pid)) {\n // Stale portfile, remove it\n await removePortfile(portfilePath);\n return null;\n }\n\n // Check if library path matches\n if (!portfileData.library || portfileData.library !== libraryPath) {\n // Server is serving a different library\n return null;\n }\n\n // Server is running and serving our library\n return {\n baseUrl: `http://localhost:${portfileData.port}`,\n pid: portfileData.pid,\n };\n}\n\n/**\n * Start server in daemon mode.\n * @param libraryPath - Path to the library file\n * @param _config - Configuration (reserved for future use)\n */\nexport async function startServerDaemon(libraryPath: string, _config: Config): Promise<void> {\n // Get the binary path (argv[1] is the script being executed)\n const binaryPath = process.argv[1] || process.execPath;\n\n // Spawn server in detached daemon mode\n const child = spawn(\n process.execPath,\n [binaryPath, \"server\", \"start\", \"--daemon\", \"--library\", libraryPath],\n {\n detached: true,\n stdio: \"ignore\",\n }\n );\n\n child.unref(); // Allow parent to exit\n}\n\n/**\n * Wait for portfile to appear.\n * @param timeoutMs - Timeout in milliseconds\n */\nexport async function waitForPortfile(timeoutMs: number): Promise<void> {\n const portfilePath = getPortfilePath();\n const startTime = Date.now();\n const checkInterval = 50; // Check every 50ms\n\n while (Date.now() - startTime < timeoutMs) {\n if (await portfileExists(portfilePath)) {\n return;\n }\n // Wait before next check\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n }\n\n throw new Error(`Server failed to start: portfile not created within ${timeoutMs}ms`);\n}\n","/**\n * CLI Entry Point\n */\n\nimport { Command } from \"commander\";\nimport { z } from \"zod\";\nimport type { CslItem } from \"../core/csl-json/types.js\";\nimport { Library } from \"../core/library.js\";\nimport { getPortfilePath } from \"../server/portfile.js\";\nimport { add as addCommand } from \"./commands/add.js\";\nimport { list } from \"./commands/list.js\";\nimport { search as searchCommand } from \"./commands/search.js\";\nimport { serverStart, serverStatus, serverStop } from \"./commands/server.js\";\nimport { update as updateCommand } from \"./commands/update.js\";\nimport type { CliOptions } from \"./helpers.js\";\nimport {\n isTTY,\n loadConfigWithOverrides,\n parseJsonInput,\n readConfirmation,\n readJsonInput,\n} from \"./helpers.js\";\nimport { ServerClient } from \"./server-client.js\";\nimport { getServerConnection } from \"./server-detection.js\";\n\n// Import package.json for version and description\nimport packageJson from \"../../package.json\" with { type: \"json\" };\n\n/**\n * Create Commander program instance\n */\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name(\"reference-manager\")\n .version(packageJson.version)\n .description(packageJson.description);\n\n // Global options\n program\n .option(\"--library <path>\", \"Override library file path\")\n .option(\"--log-level <level>\", \"Override log level (silent|info|debug)\")\n .option(\"--config <path>\", \"Use specific config file\")\n .option(\"--quiet\", \"Suppress all non-error output\")\n .option(\"--verbose\", \"Enable verbose output\")\n .option(\"--no-backup\", \"Disable backup creation\")\n .option(\"--backup-dir <path>\", \"Override backup directory\");\n\n // Register commands\n registerListCommand(program);\n registerSearchCommand(program);\n registerAddCommand(program);\n registerRemoveCommand(program);\n registerUpdateCommand(program);\n registerServerCommand(program);\n\n return program;\n}\n\n/**\n * Register 'list' command\n */\nfunction registerListCommand(program: Command): void {\n program\n .command(\"list\")\n .description(\"List all references in the library\")\n .option(\"--json\", \"Output in JSON format\")\n .option(\"--ids-only\", \"Output only citation keys\")\n .option(\"--uuid\", \"Output only UUIDs\")\n .option(\"--bibtex\", \"Output in BibTeX format\")\n .action(async (options) => {\n try {\n const globalOpts = program.opts();\n const config = await loadConfigWithOverrides({ ...globalOpts, ...options });\n\n // Get items (server or direct)\n const server = await getServerConnection(config.library, config);\n let items: CslItem[];\n\n if (server) {\n // Use server API\n const client = new ServerClient(server.baseUrl);\n items = await client.getAll();\n } else {\n // Direct file access\n const library = await Library.load(config.library);\n items = library.getAll().map((ref) => ref.getItem());\n }\n\n // Execute list command\n await list(items, {\n json: options.json,\n idsOnly: options.idsOnly,\n uuid: options.uuid,\n bibtex: options.bibtex,\n });\n\n process.exit(0);\n } catch (error) {\n process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(4);\n }\n });\n}\n\n/**\n * Register 'search' command\n */\nfunction registerSearchCommand(program: Command): void {\n program\n .command(\"search\")\n .description(\"Search references\")\n .argument(\"<query>\", \"Search query\")\n .option(\"--json\", \"Output in JSON format\")\n .option(\"--ids-only\", \"Output only citation keys\")\n .option(\"--uuid\", \"Output only UUIDs\")\n .option(\"--bibtex\", \"Output in BibTeX format\")\n .action(async (query: string, options) => {\n try {\n const globalOpts = program.opts();\n const config = await loadConfigWithOverrides({ ...globalOpts, ...options });\n\n // Get items (server or direct)\n const server = await getServerConnection(config.library, config);\n let items: CslItem[];\n\n if (server) {\n // Use server API\n const client = new ServerClient(server.baseUrl);\n items = await client.getAll();\n } else {\n // Direct file access\n const library = await Library.load(config.library);\n items = library.getAll().map((ref) => ref.getItem());\n }\n\n // Execute search command (handles search and output)\n await searchCommand(items, query, {\n json: options.json,\n idsOnly: options.idsOnly,\n uuid: options.uuid,\n bibtex: options.bibtex,\n });\n\n process.exit(0);\n } catch (error) {\n process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(4);\n }\n });\n}\n\n/**\n * Register 'add' command\n */\nasync function addViaServer(\n items: CslItem[],\n server: { baseUrl: string },\n force: boolean\n): Promise<void> {\n const client = new ServerClient(server.baseUrl);\n\n for (const item of items) {\n try {\n await client.add(item);\n process.stderr.write(`Added reference: [${item.id}]\\n`);\n } catch (error) {\n if (!force && error instanceof Error && error.message.includes(\"Duplicate\")) {\n process.stderr.write(`Error: ${error.message}\\n`);\n process.exit(1);\n }\n throw error;\n }\n }\n}\n\nasync function addViaLibrary(items: CslItem[], libraryPath: string, force: boolean): Promise<void> {\n const library = await Library.load(libraryPath);\n const existingItems = library.getAll().map((ref) => ref.getItem());\n\n for (const item of items) {\n const result = await addCommand(existingItems, item, { force });\n\n if (result.added) {\n library.add(result.item);\n process.stderr.write(`Added reference: [${result.item.id}]\\n`);\n existingItems.push(result.item);\n } else if (result.duplicate) {\n throw new Error(\n `Duplicate detected: ${result.duplicate.type} match with existing reference [${result.duplicate.existing.id}]`\n );\n }\n }\n\n await library.save();\n}\n\nfunction handleAddError(error: unknown): never {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"Parse error\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(3);\n }\n if (message.includes(\"Duplicate\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(1);\n }\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(4);\n}\n\nasync function handleAddAction(\n file: string | undefined,\n options: CliOptions & { force?: boolean },\n program: Command\n): Promise<void> {\n try {\n const globalOpts = program.opts();\n const config = await loadConfigWithOverrides({ ...globalOpts, ...options });\n\n const inputStr = await readJsonInput(file);\n const input = parseJsonInput(inputStr);\n const items: CslItem[] = Array.isArray(input) ? input : [input as CslItem];\n\n const server = await getServerConnection(config.library, config);\n\n if (server) {\n await addViaServer(items, server, options.force ?? false);\n } else {\n await addViaLibrary(items, config.library, options.force ?? false);\n }\n\n process.exit(0);\n } catch (error) {\n handleAddError(error);\n }\n}\n\nfunction registerAddCommand(program: Command): void {\n program\n .command(\"add\")\n .description(\"Add new reference(s) to the library\")\n .argument(\"[file]\", \"JSON file to add (or use stdin)\")\n .option(\"-f, --force\", \"Skip duplicate detection\")\n .action(async (file: string | undefined, options) => {\n await handleAddAction(file, options, program);\n });\n}\n\n/**\n * Register 'remove' command\n */\nasync function findReferenceToRemove(\n identifier: string,\n byUuid: boolean,\n server: { baseUrl: string } | null,\n libraryPath: string\n): Promise<CslItem | undefined> {\n if (server) {\n const client = new ServerClient(server.baseUrl);\n const items = await client.getAll();\n return byUuid\n ? items.find((item) => item.custom?.uuid === identifier)\n : items.find((item) => item.id === identifier);\n }\n\n const library = await Library.load(libraryPath);\n const ref = byUuid ? library.findByUuid(identifier) : library.findById(identifier);\n return ref?.getItem();\n}\n\nasync function confirmRemoval(refToRemove: CslItem, force: boolean): Promise<boolean> {\n if (force || !isTTY()) {\n return true;\n }\n\n const authors = Array.isArray(refToRemove.author)\n ? refToRemove.author.map((a) => `${a.family || \"\"}, ${a.given?.[0] || \"\"}.`).join(\"; \")\n : \"(no authors)\";\n const confirmMsg = `Remove reference [${refToRemove.id}]?\\nTitle: ${refToRemove.title || \"(no title)\"}\\nAuthors: ${authors}\\nContinue?`;\n\n return await readConfirmation(confirmMsg);\n}\n\nasync function removeReference(\n identifier: string,\n refToRemove: CslItem,\n byUuid: boolean,\n server: { baseUrl: string } | null,\n libraryPath: string\n): Promise<void> {\n if (server) {\n const client = new ServerClient(server.baseUrl);\n if (!refToRemove.custom?.uuid) {\n throw new Error(\"Reference missing UUID\");\n }\n await client.remove(refToRemove.custom.uuid);\n return;\n }\n\n const library = await Library.load(libraryPath);\n const removed = byUuid ? library.removeByUuid(identifier) : library.removeById(identifier);\n\n if (!removed) {\n throw new Error(\"Reference not found\");\n }\n\n await library.save();\n}\n\nfunction handleRemoveError(error: unknown): never {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"not found\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(1);\n }\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(4);\n}\n\nasync function handleRemoveAction(\n identifier: string,\n options: { uuid?: boolean; force?: boolean },\n program: Command\n): Promise<void> {\n try {\n const globalOpts = program.opts();\n const config = await loadConfigWithOverrides({ ...globalOpts, ...options });\n const server = await getServerConnection(config.library, config);\n\n const refToRemove = await findReferenceToRemove(\n identifier,\n options.uuid ?? false,\n server,\n config.library\n );\n\n if (!refToRemove) {\n process.stderr.write(`Error: Reference not found: ${identifier}\\n`);\n process.exit(1);\n }\n\n const confirmed = await confirmRemoval(refToRemove, options.force ?? false);\n if (!confirmed) {\n process.stderr.write(\"Cancelled.\\n\");\n process.exit(2);\n }\n\n await removeReference(identifier, refToRemove, options.uuid ?? false, server, config.library);\n\n process.stderr.write(`Removed reference: [${refToRemove.id}]\\n`);\n process.exit(0);\n } catch (error) {\n handleRemoveError(error);\n }\n}\n\nfunction registerRemoveCommand(program: Command): void {\n program\n .command(\"remove\")\n .description(\"Remove a reference from the library\")\n .argument(\"<identifier>\", \"Citation key or UUID\")\n .option(\"--uuid\", \"Interpret identifier as UUID\")\n .option(\"-f, --force\", \"Skip confirmation prompt\")\n .action(async (identifier: string, options) => {\n await handleRemoveAction(identifier, options, program);\n });\n}\n\n/**\n * Register 'update' command\n */\nasync function updateViaServer(\n identifier: string,\n updates: Record<string, unknown>,\n byUuid: boolean,\n server: { baseUrl: string }\n): Promise<void> {\n const client = new ServerClient(server.baseUrl);\n const items = await client.getAll();\n const refToUpdate = byUuid\n ? items.find((item) => item.custom?.uuid === identifier)\n : items.find((item) => item.id === identifier);\n\n if (!refToUpdate || !refToUpdate.custom?.uuid) {\n process.stderr.write(`Error: Reference not found: ${identifier}\\n`);\n process.exit(1);\n }\n\n const updatedItem = { ...refToUpdate, ...updates } as CslItem;\n await client.update(refToUpdate.custom.uuid, updatedItem);\n}\n\nasync function updateViaLibrary(\n identifier: string,\n updates: Partial<CslItem>,\n byUuid: boolean,\n libraryPath: string\n): Promise<void> {\n const library = await Library.load(libraryPath);\n const items = library.getAll().map((ref) => ref.getItem());\n\n const result = await updateCommand(items, identifier, updates, { byUuid });\n\n if (!result.updated || !result.item) {\n throw new Error(\"Reference not found\");\n }\n\n if (result.item.custom?.uuid) {\n library.removeByUuid(result.item.custom.uuid);\n library.add(result.item);\n }\n\n await library.save();\n}\n\nfunction handleUpdateError(error: unknown): never {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"Parse error\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(3);\n }\n if (message.includes(\"not found\") || message.includes(\"validation\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(1);\n }\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(4);\n}\n\nasync function handleUpdateAction(\n identifier: string,\n file: string | undefined,\n options: { uuid?: boolean },\n program: Command\n): Promise<void> {\n try {\n const globalOpts = program.opts();\n const config = await loadConfigWithOverrides({ ...globalOpts, ...options });\n\n const inputStr = await readJsonInput(file);\n const updates = parseJsonInput(inputStr);\n\n // Validate that updates is a non-null object using zod\n const updatesSchema = z.record(z.string(), z.unknown());\n const validatedUpdates = updatesSchema.parse(updates);\n\n const server = await getServerConnection(config.library, config);\n\n if (server) {\n await updateViaServer(identifier, validatedUpdates, options.uuid ?? false, server);\n } else {\n await updateViaLibrary(\n identifier,\n validatedUpdates as Partial<CslItem>,\n options.uuid ?? false,\n config.library\n );\n }\n\n process.stderr.write(`Updated reference: [${identifier}]\\n`);\n process.exit(0);\n } catch (error) {\n handleUpdateError(error);\n }\n}\n\nfunction registerUpdateCommand(program: Command): void {\n program\n .command(\"update\")\n .description(\"Update fields of an existing reference\")\n .argument(\"<identifier>\", \"Citation key or UUID\")\n .argument(\"[file]\", \"JSON file with updates (or use stdin)\")\n .option(\"--uuid\", \"Interpret identifier as UUID\")\n .action(async (identifier: string, file: string | undefined, options) => {\n await handleUpdateAction(identifier, file, options, program);\n });\n}\n\n/**\n * Register 'server' command\n */\nfunction registerServerCommand(program: Command): void {\n const serverCmd = program.command(\"server\").description(\"Manage HTTP server for library access\");\n\n serverCmd\n .command(\"start\")\n .description(\"Start HTTP server\")\n .option(\"--port <port>\", \"Specify port number\")\n .option(\"-d, --daemon\", \"Run in background\")\n .action(async (options) => {\n try {\n const globalOpts = program.opts();\n const config = await loadConfigWithOverrides({ ...globalOpts, ...options });\n\n const portfilePath = getPortfilePath();\n\n const startOptions = {\n library: config.library,\n portfilePath,\n daemon: options.daemon,\n ...(options.port && { port: Number.parseInt(options.port, 10) }),\n };\n\n await serverStart(startOptions);\n\n process.exit(0);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"already running\") || message.includes(\"conflict\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(1);\n }\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(4);\n }\n });\n\n serverCmd\n .command(\"stop\")\n .description(\"Stop running server\")\n .action(async () => {\n try {\n const portfilePath = getPortfilePath();\n await serverStop(portfilePath);\n\n process.stderr.write(\"Server stopped.\\n\");\n process.exit(0);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"not running\")) {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(1);\n }\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(4);\n }\n });\n\n serverCmd\n .command(\"status\")\n .description(\"Check server status\")\n .action(async () => {\n try {\n const portfilePath = getPortfilePath();\n const status = await serverStatus(portfilePath);\n\n if (status) {\n process.stdout.write(\n `Server is running\\nPort: ${status.port}\\nPID: ${status.pid}\\nLibrary: ${status.library}\\n`\n );\n process.exit(0);\n } else {\n process.stdout.write(\"Server not running\\n\");\n process.exit(1);\n }\n } catch (error) {\n process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(4);\n }\n });\n}\n\n/**\n * Main CLI entry point\n */\nexport async function main(argv: string[]): Promise<void> {\n const program = createProgram();\n\n // Setup signal handlers\n process.on(\"SIGINT\", () => {\n process.exit(130);\n });\n\n process.on(\"SIGTERM\", () => {\n process.exit(0);\n });\n\n await program.parseAsync(argv);\n}\n"],"names":["fs","searchReferences","input","searchCommand","addCommand","updateCommand"],"mappings":";;;;;;;;AAQO,SAAS,kBAA0B;AACxC,QAAM,SAAS,GAAG,OAAA;AAClB,SAAO,KAAK,KAAK,QAAQ,qBAAqB,aAAa;AAC7D;AAUA,eAAsB,cACpB,cACA,MACA,KACA,SACA,YACe;AAEf,QAAM,MAAM,KAAK,QAAQ,YAAY;AACrC,QAAMA,SAAG,MAAM,KAAK,EAAE,WAAW,MAAM;AAGvC,QAAM,OAAgC,EAAE,MAAM,KAAK,QAAA;AACnD,MAAI,eAAe,QAAW;AAC5B,SAAK,aAAa;AAAA,EACpB;AACA,QAAM,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC;AAC5C,QAAMA,SAAG,UAAU,cAAc,SAAS,OAAO;AACnD;AAOA,eAAsB,aAAa,cAKzB;AACR,MAAI;AACF,UAAM,UAAU,MAAMA,SAAG,SAAS,cAAc,OAAO;AACvD,UAAM,OAAO,KAAK,MAAM,OAAO;AAG/B,QAAI,OAAO,KAAK,SAAS,YAAY,OAAO,KAAK,QAAQ,UAAU;AACjE,aAAO;AAAA,IACT;AAGA,UAAM,SAKF;AAAA,MACF,MAAM,KAAK;AAAA,MACX,KAAK,KAAK;AAAA,IAAA;AAIZ,QAAI,OAAO,KAAK,YAAY,UAAU;AACpC,aAAO,UAAU,KAAK;AAAA,IACxB;AACA,QAAI,OAAO,KAAK,eAAe,UAAU;AACvC,aAAO,aAAa,KAAK;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAOA,eAAsB,eAAe,cAAwC;AAC3E,MAAI;AACF,UAAMA,SAAG,OAAO,YAAY;AAC5B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,eAAe,cAAqC;AACxE,MAAI;AACF,UAAMA,SAAG,OAAO,YAAY;AAAA,EAC9B,QAAQ;AAAA,EAER;AACF;AAOO,SAAS,iBAAiB,KAAsB;AACrD,MAAI,OAAO,GAAG;AACZ,WAAO;AAAA,EACT;AAEA,MAAI;AAEF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AC/GA,SAAS,eAAe,OAAuB;AAC7C,QAAM,WAAW;AACjB,MAAI,SAAS;AACb,MAAI,IAAI;AAER,KAAG;AACD,aAAS,SAAS,IAAI,EAAE,IAAI;AAC5B,QAAI,KAAK,MAAM,IAAI,EAAE,IAAI;AAAA,EAC3B,SAAS,KAAK;AAEd,SAAO;AACT;AAKA,SAAS,mBAAmB,QAAgB,UAAuD;AACjG,QAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;AAE3D,MAAI,CAAC,YAAY,IAAI,MAAM,GAAG;AAC5B,WAAO,EAAE,IAAI,QAAQ,SAAS,MAAA;AAAA,EAChC;AAGA,MAAI,QAAQ;AACZ,MAAI;AAEJ,KAAG;AACD,UAAM,SAAS,eAAe,KAAK;AACnC,YAAQ,GAAG,MAAM,GAAG,MAAM;AAC1B;AAAA,EACF,SAAS,YAAY,IAAI,KAAK;AAE9B,SAAO,EAAE,IAAI,OAAO,SAAS,KAAA;AAC/B;AAUA,eAAsB,IACpB,UACA,SACA,SACoB;AAEpB,MAAI,CAAC,QAAQ,OAAO;AAClB,UAAM,kBAAkB,gBAAgB,SAAS,QAAQ;AAEzD,QAAI,gBAAgB,QAAQ,SAAS,GAAG;AAEtC,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW,gBAAgB,QAAQ,CAAC;AAAA,MAAA;AAAA,IAExC;AAAA,EACF;AAGA,QAAM,aAAa,QAAQ;AAC3B,QAAM,EAAE,IAAI,QAAA,IAAY,mBAAmB,YAAY,QAAQ;AAE/D,QAAM,YAAqB;AAAA,IACzB,GAAG;AAAA,IACH;AAAA,EAAA;AAGF,SAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY,UAAU,aAAa;AAAA,EAAA;AAEvC;AC5FA,SAAS,aAAa,SAAyB;AAC7C,QAAM,UAAkC;AAAA,IACtC,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,MAAM;AAAA,IACN,SAAS;AAAA,IACT,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,EAAA;AAGX,SAAO,QAAQ,OAAO,KAAK;AAC7B;AAKA,SAAS,mBAAmB,QAIjB;AACT,MAAI,OAAO,SAAS;AAClB,WAAO,OAAO;AAAA,EAChB;AACA,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,QAAQ,OAAO,SAAS;AAC9B,SAAO,QAAQ,GAAG,MAAM,KAAK,KAAK,KAAK;AACzC;AAKA,SAAS,oBACP,SAQQ;AACR,SAAO,QAAQ,IAAI,kBAAkB,EAAE,KAAK,OAAO;AACrD;AAKA,SAAS,YAAY,MAAc,OAAuB;AACxD,SAAO,KAAK,IAAI,OAAO,KAAK;AAC9B;AAKA,SAAS,eAAe,OAAiB,MAAqB;AAE5D,MAAI,KAAK,OAAO;AACd,UAAM,KAAK,YAAY,SAAS,KAAK,KAAK,CAAC;AAAA,EAC7C;AAGA,MAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GAAG;AACzC,UAAM,KAAK,YAAY,UAAU,oBAAoB,KAAK,MAAM,CAAC,CAAC;AAAA,EACpE;AAGA,QAAM,OAAO,KAAK,SAAS,YAAY,IAAI,CAAC,IAAI,CAAC;AACjD,MAAI,MAAM;AACR,UAAM,KAAK,YAAY,QAAQ,OAAO,IAAI,CAAC,CAAC;AAAA,EAC9C;AACF;AAKA,SAAS,sBAAsB,OAAiB,MAAe,WAAyB;AAEtF,MAAI,KAAK,iBAAiB,GAAG;AAC3B,QAAI,cAAc,WAAW;AAC3B,YAAM,KAAK,YAAY,WAAW,KAAK,iBAAiB,CAAC,CAAC;AAAA,IAC5D,WAAW,cAAc,YAAY,cAAc,iBAAiB;AAClE,YAAM,KAAK,YAAY,aAAa,KAAK,iBAAiB,CAAC,CAAC;AAAA,IAC9D;AAAA,EACF;AAGA,MAAI,KAAK,QAAQ;AACf,UAAM,KAAK,YAAY,UAAU,KAAK,MAAM,CAAC;AAAA,EAC/C;AAGA,MAAI,KAAK,OAAO;AACd,UAAM,KAAK,YAAY,UAAU,KAAK,KAAK,CAAC;AAAA,EAC9C;AAGA,MAAI,KAAK,MAAM;AACb,UAAM,KAAK,YAAY,SAAS,KAAK,IAAI,CAAC;AAAA,EAC5C;AAGA,MAAI,KAAK,WAAW;AAClB,UAAM,KAAK,YAAY,aAAa,KAAK,SAAS,CAAC;AAAA,EACrD;AACF;AAKA,SAAS,oBAAoB,OAAiB,MAAqB;AAEjE,MAAI,KAAK,KAAK;AACZ,UAAM,KAAK,YAAY,OAAO,KAAK,GAAG,CAAC;AAAA,EACzC;AAGA,MAAI,KAAK,KAAK;AACZ,UAAM,KAAK,YAAY,OAAO,KAAK,GAAG,CAAC;AAAA,EACzC;AAGA,MAAI,KAAK,MAAM;AACb,UAAM,KAAK,YAAY,QAAQ,SAAS,KAAK,IAAI,EAAE,CAAC;AAAA,EACtD,WAAW,KAAK,OAAO;AACrB,UAAM,KAAK,YAAY,QAAQ,UAAU,KAAK,KAAK,EAAE,CAAC;AAAA,EACxD;AACF;AAKA,SAAS,wBAAwB,KAAwB;AACvD,QAAM,OAAgB,IAAI,QAAA;AAC1B,QAAM,YAAY,aAAa,KAAK,IAAI;AACxC,QAAM,QAAkB,CAAA;AAGxB,QAAM,KAAK,IAAI,SAAS,IAAI,KAAK,EAAE,GAAG;AAGtC,iBAAe,OAAO,IAAI;AAC1B,wBAAsB,OAAO,MAAM,SAAS;AAC5C,sBAAoB,OAAO,IAAI;AAG/B,QAAM,KAAK,GAAG;AAEd,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,aAAa,YAAiC;AAC5D,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,IAAI,uBAAuB,EAAE,KAAK,MAAM;AAC5D;ACrKO,SAAS,WAAW,YAAiC;AAC1D,QAAM,QAAQ,WAAW,IAAI,CAAC,QAAQ,IAAI,SAAS;AACnD,SAAO,KAAK,UAAU,KAAK;AAC7B;ACHA,SAAS,aAAa,QAGX;AACT,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,eAAe,OAAO,QAAQ,GAAG,OAAO,MAAM,OAAO,CAAC,CAAC,MAAM;AACnE,SAAO,eAAe,GAAG,MAAM,KAAK,YAAY,KAAK;AACvD;AAKA,SAAS,cACP,SAQQ;AACR,SAAO,QAAQ,IAAI,YAAY,EAAE,KAAK,IAAI;AAC5C;AAKA,SAAS,sBAAsB,KAAwB;AACrD,QAAM,OAAO,IAAI,QAAA;AACjB,QAAM,QAAkB,CAAA;AAGxB,QAAM,SAAS,KAAK,QAAQ,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,EAAE;AACtE,QAAM,KAAK,MAAM;AAGjB,MAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GAAG;AACzC,UAAM,KAAK,cAAc,cAAc,KAAK,MAAM,CAAC,EAAE;AAAA,EACvD;AAGA,QAAM,OAAO,KAAK,SAAS,YAAY,IAAI,CAAC,IAAI,CAAC;AACjD,QAAM,KAAK,WAAW,QAAQ,WAAW,EAAE;AAG3C,QAAM,KAAK,WAAW,KAAK,IAAI,EAAE;AAGjC,MAAI,KAAK,KAAK;AACZ,UAAM,KAAK,UAAU,KAAK,GAAG,EAAE;AAAA,EACjC;AAGA,MAAI,KAAK,MAAM;AACb,UAAM,KAAK,WAAW,KAAK,IAAI,EAAE;AAAA,EACnC;AAGA,MAAI,KAAK,OAAO;AACd,UAAM,KAAK,YAAY,KAAK,KAAK,EAAE;AAAA,EACrC;AAGA,MAAI,KAAK,KAAK;AACZ,UAAM,KAAK,UAAU,KAAK,GAAG,EAAE;AAAA,EACjC;AAGA,QAAM,KAAK,WAAW,IAAI,QAAA,CAAS,EAAE;AAErC,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,aAAa,YAAiC;AAC5D,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,IAAI,qBAAqB,EAAE,KAAK,MAAM;AAC1D;ACrEA,eAAsB,KAAK,OAAkB,SAAqC;AAEhF,QAAM,gBAAgB,CAAC,QAAQ,MAAM,QAAQ,SAAS,QAAQ,MAAM,QAAQ,MAAM,EAAE;AAAA,IAClF;AAAA,EAAA;AAGF,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAGA,QAAM,aAAa,MAAM,IAAI,CAAC,SAAS,IAAI,UAAU,IAAI,CAAC;AAG1D,MAAI,QAAQ,MAAM;AAChB,YAAQ,OAAO,MAAM,WAAW,UAAU,CAAC;AAAA,EAC7C,WAAW,QAAQ,SAAS;AAC1B,eAAW,QAAQ,OAAO;AACxB,cAAQ,OAAO,MAAM,GAAG,KAAK,EAAE;AAAA,CAAI;AAAA,IACrC;AAAA,EACF,WAAW,QAAQ,MAAM;AACvB,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,QAAQ;AACf,gBAAQ,OAAO,MAAM,GAAG,KAAK,OAAO,IAAI;AAAA,CAAI;AAAA,MAC9C;AAAA,IACF;AAAA,EACF,WAAW,QAAQ,QAAQ;AACzB,YAAQ,OAAO,MAAM,aAAa,UAAU,CAAC;AAAA,EAC/C,OAAO;AAEL,YAAQ,OAAO,MAAM,aAAa,UAAU,CAAC;AAAA,EAC/C;AACF;AC9BA,eAAsB,OACpB,OACA,OACA,SACe;AAEf,QAAM,gBAAgB,CAAC,QAAQ,MAAM,QAAQ,SAAS,QAAQ,MAAM,QAAQ,MAAM,EAAE;AAAA,IAClF;AAAA,EAAA;AAGF,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAGA,QAAM,cAAc,SAAS,KAAK;AAGlC,QAAM,UAAUC,SAAiB,OAAO,YAAY,MAAM;AAG1D,QAAM,SAAS,YAAY,OAAO;AAGlC,QAAM,eAAe,OAAO,IAAI,CAAC,WAAW,OAAO,SAAS;AAG5D,QAAM,aAAa,aAAa,IAAI,CAAC,SAAS,IAAI,UAAU,IAAI,CAAC;AAGjE,MAAI,QAAQ,MAAM;AAChB,YAAQ,OAAO,MAAM,WAAW,UAAU,CAAC;AAAA,EAC7C,WAAW,QAAQ,SAAS;AAC1B,eAAW,QAAQ,cAAc;AAC/B,cAAQ,OAAO,MAAM,GAAG,KAAK,EAAE;AAAA,CAAI;AAAA,IACrC;AAAA,EACF,WAAW,QAAQ,MAAM;AACvB,eAAW,QAAQ,cAAc;AAC/B,UAAI,KAAK,QAAQ;AACf,gBAAQ,OAAO,MAAM,GAAG,KAAK,OAAO,IAAI;AAAA,CAAI;AAAA,MAC9C;AAAA,IACF;AAAA,EACF,WAAW,QAAQ,QAAQ;AACzB,YAAQ,OAAO,MAAM,aAAa,UAAU,CAAC;AAAA,EAC/C,OAAO;AAEL,YAAQ,OAAO,MAAM,aAAa,UAAU,CAAC;AAAA,EAC/C;AACF;AC/CA,eAAsB,YAAY,SAA4C;AAE5E,QAAM,iBAAiB,MAAM,aAAa,QAAQ,YAAY;AAC9D,MAAI,mBAAmB,MAAM;AAC3B,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AAGA,QAAM,OAAO,QAAQ,QAAQ;AAI7B,QAAM,MAAM,QAAQ;AACpB,QAAM,cAAa,oBAAI,KAAA,GAAO,YAAA;AAE9B,QAAM,cAAc,QAAQ,cAAc,MAAM,KAAK,QAAQ,SAAS,UAAU;AAIlF;AAOA,eAAsB,WAAW,cAAqC;AAEpE,QAAM,SAAS,MAAM,aAAa,YAAY;AAC9C,MAAI,WAAW,MAAM;AACnB,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAIA,QAAM,eAAe,YAAY;AAEjC,UAAQ,OAAO,MAAM,+BAA+B;AACtD;AAQA,eAAsB,aAAa,cAAkD;AAEnF,QAAM,eAAe,MAAM,aAAa,YAAY;AACpD,MAAI,iBAAiB,MAAM;AACzB,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,iBAAiB,aAAa,GAAG,GAAG;AAEvC,UAAM,eAAe,YAAY;AACjC,WAAO;AAAA,EACT;AAGA,QAAM,SAAqB;AAAA,IACzB,MAAM,aAAa;AAAA,IACnB,KAAK,aAAa;AAAA,IAClB,SAAS,aAAa,WAAW;AAAA,EAAA;AAGnC,MAAI,aAAa,eAAe,QAAW;AACzC,WAAO,aAAa,aAAa;AAAA,EACnC;AAEA,SAAO;AACT;AC7EA,eAAsB,OACpB,OACA,YACA,SACA,SACuB;AACvB,MAAI,aAAa;AAEjB,MAAI,QAAQ,QAAQ;AAElB,iBAAa,MAAM,UAAU,CAAC,SAAS,KAAK,QAAQ,SAAS,UAAU;AAAA,EACzE,OAAO;AAEL,iBAAa,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,UAAU;AAAA,EAC/D;AAEA,MAAI,eAAe,IAAI;AAErB,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IAAA;AAAA,EAEJ;AAEA,QAAM,eAAe,MAAM,UAAU;AACrC,MAAI,CAAC,cAAc;AAEjB,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IAAA;AAAA,EAEJ;AAGA,QAAM,cAAuB;AAAA,IAC3B,GAAG;AAAA,IACH,GAAG;AAAA;AAAA,IAEH,IAAI,QAAQ,MAAM,aAAa;AAAA,IAC/B,MAAM,QAAQ,QAAQ,aAAa;AAAA;AAAA,IAEnC,QAAQ;AAAA,MACN,GAAI,aAAa,UAAU,CAAA;AAAA,MAC3B,GAAI,QAAQ,UAAU,CAAA;AAAA,MACtB,MAAM,aAAa,QAAQ,QAAQ;AAAA,MACnC,YAAY,aAAa,QAAQ,eAAc,oBAAI,KAAA,GAAO,YAAA;AAAA;AAAA,MAE1D,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,IAAY;AAAA,EACpC;AAGF,QAAM,eAAe,CAAC,GAAG,MAAM,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,MAAM,MAAM,aAAa,CAAC,CAAC;AAEhG,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAEX;AC3CA,eAAsB,cAAc,MAAgC;AAClE,MAAI,MAAM;AAER,QAAI;AACF,aAAO,aAAa,MAAM,OAAO;AAAA,IACnC,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,+BAA+B,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAAA;AAAA,IAElG;AAAA,EACF;AAGA,QAAM,SAAmB,CAAA;AACzB,mBAAiB,SAAS,OAAO;AAC/B,WAAO,KAAK,KAAe;AAAA,EAC7B;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO;AAC/C;AAOO,SAAS,eAAe,OAAwB;AACrD,MAAI,CAAC,SAAS,MAAM,KAAA,MAAW,IAAI;AACjC,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AAEA,MAAI;AACF,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,8BAA8B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAAA;AAAA,EAExF;AACF;AAOA,eAAsB,wBAAwB,SAAsC;AAGlF,QAAM,SAAS,MAAM,WAAA;AAGrB,QAAM,YAA6B,CAAA;AAGnC,MAAI,QAAQ,SAAS;AACnB,cAAU,UAAU,QAAQ;AAAA,EAC9B;AAGA,MAAI,QAAQ,OAAO;AACjB,cAAU,WAAW;AAAA,EACvB,WAAW,QAAQ,SAAS;AAC1B,cAAU,WAAW;AAAA,EACvB,WAAW,QAAQ,UAAU;AAC3B,cAAU,WAAW,QAAQ;AAAA,EAC/B;AAGA,MAAI,QAAQ,WAAW,UAAa,QAAQ,WAAW;AACrD,cAAU,SAAS;AAAA,MACjB,GAAG,OAAO;AAAA,MACV,GAAI,QAAQ,WAAW,UAAa,EAAE,SAAS,QAAQ,OAAA;AAAA,MACvD,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,UAAA;AAAA,IAAU;AAAA,EAE5D;AAEA,SAAO,EAAE,GAAG,QAAQ,GAAG,UAAA;AACzB;AA6BO,SAAS,QAAiB;AAC/B,SAAO,QAAQ,MAAM,SAAS,OAAO,KAAK;AAC5C;AAOA,eAAsB,iBAAiB,QAAkC;AAEvE,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAGA,SAAO,MAAM,GAAG,MAAM,UAAU;AAGhC,QAAM,SAAmB,CAAA;AACzB,mBAAiB,SAAS,OAAO;AAC/B,WAAO,KAAK,KAAe;AAE3B,UAAMC,SAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO;AACpD,QAAIA,OAAM,SAAS,IAAI,GAAG;AACxB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO,EAAE,KAAA,EAAO,YAAA;AAC7D,SAAO,UAAU,OAAO,UAAU;AACpC;ACvKO,MAAM,aAAa;AAAA,EACxB,YAAoB,SAAiB;AAAjB,SAAA,UAAA;AAAA,EAAkB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMtC,MAAM,SAA6B;AACjC,UAAM,MAAM,GAAG,KAAK,OAAO;AAC3B,UAAM,WAAW,MAAM,MAAM,GAAG;AAEhC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,MAAM,SAAS,MAAM;AAAA,IACvC;AAEA,WAAQ,MAAM,SAAS,KAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAW,MAAuC;AACtD,UAAM,MAAM,GAAG,KAAK,OAAO,mBAAmB,IAAI;AAClD,UAAM,WAAW,MAAM,MAAM,GAAG;AAEhC,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,MAAM,SAAS,MAAM;AAAA,IACvC;AAEA,WAAQ,MAAM,SAAS,KAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,MAAiC;AACzC,UAAM,MAAM,GAAG,KAAK,OAAO;AAC3B,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAA;AAAA,MAC3B,MAAM,KAAK,UAAU,IAAI;AAAA,IAAA,CAC1B;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,MAAM,SAAS,MAAM;AAAA,IACvC;AAEA,WAAQ,MAAM,SAAS,KAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,MAAc,MAAiC;AAC1D,UAAM,MAAM,GAAG,KAAK,OAAO,mBAAmB,IAAI;AAClD,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAA;AAAA,MAC3B,MAAM,KAAK,UAAU,IAAI;AAAA,IAAA,CAC1B;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,MAAM,SAAS,MAAM;AAAA,IACvC;AAEA,WAAQ,MAAM,SAAS,KAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,MAA6B;AACxC,UAAM,MAAM,GAAG,KAAK,OAAO,mBAAmB,IAAI;AAClD,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,IAAA,CACT;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,MAAM,SAAS,MAAM;AAAA,IACvC;AAAA,EACF;AACF;AC1EA,eAAsB,oBACpB,aACA,QACkC;AAClC,QAAM,eAAe,gBAAA;AACrB,QAAM,eAAe,MAAM,aAAa,YAAY;AAGpD,MAAI,CAAC,cAAc;AAEjB,QAAI,OAAO,OAAO,WAAW;AAE3B,YAAM,kBAAkB,WAAmB;AAC3C,YAAM,gBAAgB,GAAI;AAE1B,aAAO,MAAM,oBAAoB,aAAa,MAAM;AAAA,IACtD;AACA,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,iBAAiB,aAAa,GAAG,GAAG;AAEvC,UAAM,eAAe,YAAY;AACjC,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,aAAa,WAAW,aAAa,YAAY,aAAa;AAEjE,WAAO;AAAA,EACT;AAGA,SAAO;AAAA,IACL,SAAS,oBAAoB,aAAa,IAAI;AAAA,IAC9C,KAAK,aAAa;AAAA,EAAA;AAEtB;AAOA,eAAsB,kBAAkB,aAAqB,SAAgC;AAE3F,QAAM,aAAa,QAAQ,KAAK,CAAC,KAAK,QAAQ;AAG9C,QAAM,QAAQ;AAAA,IACZ,QAAQ;AAAA,IACR,CAAC,YAAY,UAAU,SAAS,YAAY,aAAa,WAAW;AAAA,IACpE;AAAA,MACE,UAAU;AAAA,MACV,OAAO;AAAA,IAAA;AAAA,EACT;AAGF,QAAM,MAAA;AACR;AAMA,eAAsB,gBAAgB,WAAkC;AACtE,QAAM,eAAe,gBAAA;AACrB,QAAM,YAAY,KAAK,IAAA;AACvB,QAAM,gBAAgB;AAEtB,SAAO,KAAK,QAAQ,YAAY,WAAW;AACzC,QAAI,MAAM,eAAe,YAAY,GAAG;AACtC;AAAA,IACF;AAEA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,aAAa,CAAC;AAAA,EACnE;AAEA,QAAM,IAAI,MAAM,uDAAuD,SAAS,IAAI;AACtF;;;;;;;ACzEO,SAAS,gBAAyB;AACvC,QAAM,UAAU,IAAI,QAAA;AAEpB,UACG,KAAK,mBAAmB,EACxB,QAAQ,YAAY,OAAO,EAC3B,YAAY,YAAY,WAAW;AAGtC,UACG,OAAO,oBAAoB,4BAA4B,EACvD,OAAO,uBAAuB,wCAAwC,EACtE,OAAO,mBAAmB,0BAA0B,EACpD,OAAO,WAAW,+BAA+B,EACjD,OAAO,aAAa,uBAAuB,EAC3C,OAAO,eAAe,yBAAyB,EAC/C,OAAO,uBAAuB,2BAA2B;AAG5D,sBAAoB,OAAO;AAC3B,wBAAsB,OAAO;AAC7B,qBAAmB,OAAO;AAC1B,wBAAsB,OAAO;AAC7B,wBAAsB,OAAO;AAC7B,wBAAsB,OAAO;AAE7B,SAAO;AACT;AAKA,SAAS,oBAAoB,SAAwB;AACnD,UACG,QAAQ,MAAM,EACd,YAAY,oCAAoC,EAChD,OAAO,UAAU,uBAAuB,EACxC,OAAO,cAAc,2BAA2B,EAChD,OAAO,UAAU,mBAAmB,EACpC,OAAO,YAAY,yBAAyB,EAC5C,OAAO,OAAO,YAAY;AACzB,QAAI;AACF,YAAM,aAAa,QAAQ,KAAA;AAC3B,YAAM,SAAS,MAAM,wBAAwB,EAAE,GAAG,YAAY,GAAG,SAAS;AAG1E,YAAM,SAAS,MAAM,oBAAoB,OAAO,SAAS,MAAM;AAC/D,UAAI;AAEJ,UAAI,QAAQ;AAEV,cAAM,SAAS,IAAI,aAAa,OAAO,OAAO;AAC9C,gBAAQ,MAAM,OAAO,OAAA;AAAA,MACvB,OAAO;AAEL,cAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,OAAO;AACjD,gBAAQ,QAAQ,SAAS,IAAI,CAAC,QAAQ,IAAI,SAAS;AAAA,MACrD;AAGA,YAAM,KAAK,OAAO;AAAA,QAChB,MAAM,QAAQ;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,MAAM,QAAQ;AAAA,QACd,QAAQ,QAAQ;AAAA,MAAA,CACjB;AAED,cAAQ,KAAK,CAAC;AAAA,IAChB,SAAS,OAAO;AACd,cAAQ,OAAO,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACzF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;AAKA,SAAS,sBAAsB,SAAwB;AACrD,UACG,QAAQ,QAAQ,EAChB,YAAY,mBAAmB,EAC/B,SAAS,WAAW,cAAc,EAClC,OAAO,UAAU,uBAAuB,EACxC,OAAO,cAAc,2BAA2B,EAChD,OAAO,UAAU,mBAAmB,EACpC,OAAO,YAAY,yBAAyB,EAC5C,OAAO,OAAO,OAAe,YAAY;AACxC,QAAI;AACF,YAAM,aAAa,QAAQ,KAAA;AAC3B,YAAM,SAAS,MAAM,wBAAwB,EAAE,GAAG,YAAY,GAAG,SAAS;AAG1E,YAAM,SAAS,MAAM,oBAAoB,OAAO,SAAS,MAAM;AAC/D,UAAI;AAEJ,UAAI,QAAQ;AAEV,cAAM,SAAS,IAAI,aAAa,OAAO,OAAO;AAC9C,gBAAQ,MAAM,OAAO,OAAA;AAAA,MACvB,OAAO;AAEL,cAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,OAAO;AACjD,gBAAQ,QAAQ,SAAS,IAAI,CAAC,QAAQ,IAAI,SAAS;AAAA,MACrD;AAGA,YAAMC,OAAc,OAAO,OAAO;AAAA,QAChC,MAAM,QAAQ;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,MAAM,QAAQ;AAAA,QACd,QAAQ,QAAQ;AAAA,MAAA,CACjB;AAED,cAAQ,KAAK,CAAC;AAAA,IAChB,SAAS,OAAO;AACd,cAAQ,OAAO,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACzF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;AAKA,eAAe,aACb,OACA,QACA,OACe;AACf,QAAM,SAAS,IAAI,aAAa,OAAO,OAAO;AAE9C,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,OAAO,IAAI,IAAI;AACrB,cAAQ,OAAO,MAAM,qBAAqB,KAAK,EAAE;AAAA,CAAK;AAAA,IACxD,SAAS,OAAO;AACd,UAAI,CAAC,SAAS,iBAAiB,SAAS,MAAM,QAAQ,SAAS,WAAW,GAAG;AAC3E,gBAAQ,OAAO,MAAM,UAAU,MAAM,OAAO;AAAA,CAAI;AAChD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAe,cAAc,OAAkB,aAAqB,OAA+B;AACjG,QAAM,UAAU,MAAM,QAAQ,KAAK,WAAW;AAC9C,QAAM,gBAAgB,QAAQ,OAAA,EAAS,IAAI,CAAC,QAAQ,IAAI,SAAS;AAEjE,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,MAAMC,IAAW,eAAe,MAAM,EAAE,OAAO;AAE9D,QAAI,OAAO,OAAO;AAChB,cAAQ,IAAI,OAAO,IAAI;AACvB,cAAQ,OAAO,MAAM,qBAAqB,OAAO,KAAK,EAAE;AAAA,CAAK;AAC7D,oBAAc,KAAK,OAAO,IAAI;AAAA,IAChC,WAAW,OAAO,WAAW;AAC3B,YAAM,IAAI;AAAA,QACR,uBAAuB,OAAO,UAAU,IAAI,mCAAmC,OAAO,UAAU,SAAS,EAAE;AAAA,MAAA;AAAA,IAE/G;AAAA,EACF;AAEA,QAAM,QAAQ,KAAA;AAChB;AAEA,SAAS,eAAe,OAAuB;AAC7C,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,MAAI,QAAQ,SAAS,aAAa,GAAG;AACnC,YAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,QAAQ,SAAS,WAAW,GAAG;AACjC,YAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,UAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,gBACb,MACA,SACA,SACe;AACf,MAAI;AACF,UAAM,aAAa,QAAQ,KAAA;AAC3B,UAAM,SAAS,MAAM,wBAAwB,EAAE,GAAG,YAAY,GAAG,SAAS;AAE1E,UAAM,WAAW,MAAM,cAAc,IAAI;AACzC,UAAM,QAAQ,eAAe,QAAQ;AACrC,UAAM,QAAmB,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAgB;AAEzE,UAAM,SAAS,MAAM,oBAAoB,OAAO,SAAS,MAAM;AAE/D,QAAI,QAAQ;AACV,YAAM,aAAa,OAAO,QAAQ,QAAQ,SAAS,KAAK;AAAA,IAC1D,OAAO;AACL,YAAM,cAAc,OAAO,OAAO,SAAS,QAAQ,SAAS,KAAK;AAAA,IACnE;AAEA,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,OAAO;AACd,mBAAe,KAAK;AAAA,EACtB;AACF;AAEA,SAAS,mBAAmB,SAAwB;AAClD,UACG,QAAQ,KAAK,EACb,YAAY,qCAAqC,EACjD,SAAS,UAAU,iCAAiC,EACpD,OAAO,eAAe,0BAA0B,EAChD,OAAO,OAAO,MAA0B,YAAY;AACnD,UAAM,gBAAgB,MAAM,SAAS,OAAO;AAAA,EAC9C,CAAC;AACL;AAKA,eAAe,sBACb,YACA,QACA,QACA,aAC8B;AAC9B,MAAI,QAAQ;AACV,UAAM,SAAS,IAAI,aAAa,OAAO,OAAO;AAC9C,UAAM,QAAQ,MAAM,OAAO,OAAA;AAC3B,WAAO,SACH,MAAM,KAAK,CAAC,SAAS,KAAK,QAAQ,SAAS,UAAU,IACrD,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,UAAU;AAAA,EACjD;AAEA,QAAM,UAAU,MAAM,QAAQ,KAAK,WAAW;AAC9C,QAAM,MAAM,SAAS,QAAQ,WAAW,UAAU,IAAI,QAAQ,SAAS,UAAU;AACjF,SAAO,KAAK,QAAA;AACd;AAEA,eAAe,eAAe,aAAsB,OAAkC;AACpF,MAAI,SAAS,CAAC,SAAS;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,QAAQ,YAAY,MAAM,IAC5C,YAAY,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,IACpF;AACJ,QAAM,aAAa,qBAAqB,YAAY,EAAE;AAAA,SAAc,YAAY,SAAS,YAAY;AAAA,WAAc,OAAO;AAAA;AAE1H,SAAO,MAAM,iBAAiB,UAAU;AAC1C;AAEA,eAAe,gBACb,YACA,aACA,QACA,QACA,aACe;AACf,MAAI,QAAQ;AACV,UAAM,SAAS,IAAI,aAAa,OAAO,OAAO;AAC9C,QAAI,CAAC,YAAY,QAAQ,MAAM;AAC7B,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AACA,UAAM,OAAO,OAAO,YAAY,OAAO,IAAI;AAC3C;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,QAAQ,KAAK,WAAW;AAC9C,QAAM,UAAU,SAAS,QAAQ,aAAa,UAAU,IAAI,QAAQ,WAAW,UAAU;AAEzF,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qBAAqB;AAAA,EACvC;AAEA,QAAM,QAAQ,KAAA;AAChB;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,MAAI,QAAQ,SAAS,WAAW,GAAG;AACjC,YAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,UAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,mBACb,YACA,SACA,SACe;AACf,MAAI;AACF,UAAM,aAAa,QAAQ,KAAA;AAC3B,UAAM,SAAS,MAAM,wBAAwB,EAAE,GAAG,YAAY,GAAG,SAAS;AAC1E,UAAM,SAAS,MAAM,oBAAoB,OAAO,SAAS,MAAM;AAE/D,UAAM,cAAc,MAAM;AAAA,MACxB;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA,OAAO;AAAA,IAAA;AAGT,QAAI,CAAC,aAAa;AAChB,cAAQ,OAAO,MAAM,+BAA+B,UAAU;AAAA,CAAI;AAClE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,YAAY,MAAM,eAAe,aAAa,QAAQ,SAAS,KAAK;AAC1E,QAAI,CAAC,WAAW;AACd,cAAQ,OAAO,MAAM,cAAc;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,gBAAgB,YAAY,aAAa,QAAQ,QAAQ,OAAO,QAAQ,OAAO,OAAO;AAE5F,YAAQ,OAAO,MAAM,uBAAuB,YAAY,EAAE;AAAA,CAAK;AAC/D,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,OAAO;AACd,sBAAkB,KAAK;AAAA,EACzB;AACF;AAEA,SAAS,sBAAsB,SAAwB;AACrD,UACG,QAAQ,QAAQ,EAChB,YAAY,qCAAqC,EACjD,SAAS,gBAAgB,sBAAsB,EAC/C,OAAO,UAAU,8BAA8B,EAC/C,OAAO,eAAe,0BAA0B,EAChD,OAAO,OAAO,YAAoB,YAAY;AAC7C,UAAM,mBAAmB,YAAY,SAAS,OAAO;AAAA,EACvD,CAAC;AACL;AAKA,eAAe,gBACb,YACA,SACA,QACA,QACe;AACf,QAAM,SAAS,IAAI,aAAa,OAAO,OAAO;AAC9C,QAAM,QAAQ,MAAM,OAAO,OAAA;AAC3B,QAAM,cAAc,SAChB,MAAM,KAAK,CAAC,SAAS,KAAK,QAAQ,SAAS,UAAU,IACrD,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,UAAU;AAE/C,MAAI,CAAC,eAAe,CAAC,YAAY,QAAQ,MAAM;AAC7C,YAAQ,OAAO,MAAM,+BAA+B,UAAU;AAAA,CAAI;AAClE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,EAAE,GAAG,aAAa,GAAG,QAAA;AACzC,QAAM,OAAO,OAAO,YAAY,OAAO,MAAM,WAAW;AAC1D;AAEA,eAAe,iBACb,YACA,SACA,QACA,aACe;AACf,QAAM,UAAU,MAAM,QAAQ,KAAK,WAAW;AAC9C,QAAM,QAAQ,QAAQ,OAAA,EAAS,IAAI,CAAC,QAAQ,IAAI,SAAS;AAEzD,QAAM,SAAS,MAAMC,OAAc,OAAO,YAAY,SAAS,EAAE,QAAQ;AAEzE,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,MAAM;AACnC,UAAM,IAAI,MAAM,qBAAqB;AAAA,EACvC;AAEA,MAAI,OAAO,KAAK,QAAQ,MAAM;AAC5B,YAAQ,aAAa,OAAO,KAAK,OAAO,IAAI;AAC5C,YAAQ,IAAI,OAAO,IAAI;AAAA,EACzB;AAEA,QAAM,QAAQ,KAAA;AAChB;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,MAAI,QAAQ,SAAS,aAAa,GAAG;AACnC,YAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,QAAQ,SAAS,WAAW,KAAK,QAAQ,SAAS,YAAY,GAAG;AACnE,YAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,UAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,mBACb,YACA,MACA,SACA,SACe;AACf,MAAI;AACF,UAAM,aAAa,QAAQ,KAAA;AAC3B,UAAM,SAAS,MAAM,wBAAwB,EAAE,GAAG,YAAY,GAAG,SAAS;AAE1E,UAAM,WAAW,MAAM,cAAc,IAAI;AACzC,UAAM,UAAU,eAAe,QAAQ;AAGvC,UAAM,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS;AACtD,UAAM,mBAAmB,cAAc,MAAM,OAAO;AAEpD,UAAM,SAAS,MAAM,oBAAoB,OAAO,SAAS,MAAM;AAE/D,QAAI,QAAQ;AACV,YAAM,gBAAgB,YAAY,kBAAkB,QAAQ,QAAQ,OAAO,MAAM;AAAA,IACnF,OAAO;AACL,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,OAAO;AAAA,MAAA;AAAA,IAEX;AAEA,YAAQ,OAAO,MAAM,uBAAuB,UAAU;AAAA,CAAK;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,OAAO;AACd,sBAAkB,KAAK;AAAA,EACzB;AACF;AAEA,SAAS,sBAAsB,SAAwB;AACrD,UACG,QAAQ,QAAQ,EAChB,YAAY,wCAAwC,EACpD,SAAS,gBAAgB,sBAAsB,EAC/C,SAAS,UAAU,uCAAuC,EAC1D,OAAO,UAAU,8BAA8B,EAC/C,OAAO,OAAO,YAAoB,MAA0B,YAAY;AACvE,UAAM,mBAAmB,YAAY,MAAM,SAAS,OAAO;AAAA,EAC7D,CAAC;AACL;AAKA,SAAS,sBAAsB,SAAwB;AACrD,QAAM,YAAY,QAAQ,QAAQ,QAAQ,EAAE,YAAY,uCAAuC;AAE/F,YACG,QAAQ,OAAO,EACf,YAAY,mBAAmB,EAC/B,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,gBAAgB,mBAAmB,EAC1C,OAAO,OAAO,YAAY;AACzB,QAAI;AACF,YAAM,aAAa,QAAQ,KAAA;AAC3B,YAAM,SAAS,MAAM,wBAAwB,EAAE,GAAG,YAAY,GAAG,SAAS;AAE1E,YAAM,eAAe,gBAAA;AAErB,YAAM,eAAe;AAAA,QACnB,SAAS,OAAO;AAAA,QAChB;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,GAAI,QAAQ,QAAQ,EAAE,MAAM,OAAO,SAAS,QAAQ,MAAM,EAAE,EAAA;AAAA,MAAE;AAGhE,YAAM,YAAY,YAAY;AAE9B,cAAQ,KAAK,CAAC;AAAA,IAChB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,QAAQ,SAAS,iBAAiB,KAAK,QAAQ,SAAS,UAAU,GAAG;AACvE,gBAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,MAAM,EACd,YAAY,qBAAqB,EACjC,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,eAAe,gBAAA;AACrB,YAAM,WAAW,YAAY;AAE7B,cAAQ,OAAO,MAAM,mBAAmB;AACxC,cAAQ,KAAK,CAAC;AAAA,IAChB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,QAAQ,SAAS,aAAa,GAAG;AACnC,gBAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AAC1C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,QAAQ,EAChB,YAAY,qBAAqB,EACjC,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,eAAe,gBAAA;AACrB,YAAM,SAAS,MAAM,aAAa,YAAY;AAE9C,UAAI,QAAQ;AACV,gBAAQ,OAAO;AAAA,UACb;AAAA,QAA4B,OAAO,IAAI;AAAA,OAAU,OAAO,GAAG;AAAA,WAAc,OAAO,OAAO;AAAA;AAAA,QAAA;AAEzF,gBAAQ,KAAK,CAAC;AAAA,MAChB,OAAO;AACL,gBAAQ,OAAO,MAAM,sBAAsB;AAC3C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,OAAO,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACzF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;AAKA,eAAsB,KAAK,MAA+B;AACxD,QAAM,UAAU,cAAA;AAGhB,UAAQ,GAAG,UAAU,MAAM;AACzB,YAAQ,KAAK,GAAG;AAAA,EAClB,CAAC;AAED,UAAQ,GAAG,WAAW,MAAM;AAC1B,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,QAAM,QAAQ,WAAW,IAAI;AAC/B;"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Default configuration values
3
+ */
4
+ import type { Config } from "./schema.js";
5
+ /**
6
+ * Get the default backup directory
7
+ * Uses $TMPDIR/reference-manager/backups/
8
+ */
9
+ export declare function getDefaultBackupDirectory(): string;
10
+ /**
11
+ * Get the default library path
12
+ * Uses ~/.reference-manager/csl.library.json
13
+ */
14
+ export declare function getDefaultLibraryPath(): string;
15
+ /**
16
+ * Get the default user config path
17
+ * Uses ~/.reference-manager/config.toml
18
+ */
19
+ export declare function getDefaultUserConfigPath(): string;
20
+ /**
21
+ * Get the default current directory config filename
22
+ * Uses .reference-manager.config.toml
23
+ */
24
+ export declare function getDefaultCurrentDirConfigFilename(): string;
25
+ /**
26
+ * Default configuration
27
+ */
28
+ export declare const defaultConfig: Config;
29
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,IAAI,MAAM,CAE3D;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAmB3B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Configuration module
3
+ *
4
+ * Provides configuration loading and management for reference-manager.
5
+ */
6
+ export type { Config, LogLevel, BackupConfig, WatchConfig, PartialConfig, DeepPartialConfig, } from "./schema.js";
7
+ export { configSchema, logLevelSchema, backupConfigSchema, watchConfigSchema, partialConfigSchema, normalizePartialConfig, } from "./schema.js";
8
+ export { defaultConfig, getDefaultBackupDirectory, getDefaultLibraryPath, getDefaultUserConfigPath, getDefaultCurrentDirConfigFilename, } from "./defaults.js";
9
+ export { loadConfig, type LoadConfigOptions } from "./loader.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,qBAAqB,EACrB,wBAAwB,EACxB,kCAAkC,GACnC,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Configuration loader
3
+ */
4
+ import { type Config } from "./schema.js";
5
+ /**
6
+ * Options for loading configuration
7
+ */
8
+ export interface LoadConfigOptions {
9
+ /** Current working directory (default: process.cwd()) */
10
+ cwd?: string;
11
+ /** User config path (default: ~/.reference-manager/config.toml) */
12
+ userConfigPath?: string;
13
+ /** CLI argument overrides */
14
+ overrides?: Partial<Config>;
15
+ }
16
+ /**
17
+ * Load configuration from multiple sources
18
+ *
19
+ * Priority (highest to lowest):
20
+ * 1. CLI argument overrides
21
+ * 2. Current directory config (.reference-manager.config.toml)
22
+ * 3. Environment variable (REFERENCE_MANAGER_CONFIG)
23
+ * 4. User config (~/.reference-manager/config.toml)
24
+ * 5. Default values
25
+ */
26
+ export declare function loadConfig(options?: LoadConfigOptions): Config;
27
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,EACL,KAAK,MAAM,EAMZ,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7B;AAmGD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAwClE"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Configuration schema using Zod
3
+ */
4
+ import { z } from "zod";
5
+ /**
6
+ * Log level schema
7
+ */
8
+ export declare const logLevelSchema: z.ZodEnum<{
9
+ silent: "silent";
10
+ info: "info";
11
+ debug: "debug";
12
+ }>;
13
+ /**
14
+ * Backup configuration schema
15
+ */
16
+ export declare const backupConfigSchema: z.ZodObject<{
17
+ maxGenerations: z.ZodNumber;
18
+ maxAgeDays: z.ZodNumber;
19
+ directory: z.ZodString;
20
+ }, z.core.$strip>;
21
+ /**
22
+ * File watching configuration schema
23
+ */
24
+ export declare const watchConfigSchema: z.ZodObject<{
25
+ enabled: z.ZodBoolean;
26
+ debounceMs: z.ZodNumber;
27
+ pollIntervalMs: z.ZodNumber;
28
+ retryIntervalMs: z.ZodNumber;
29
+ maxRetries: z.ZodNumber;
30
+ }, z.core.$strip>;
31
+ /**
32
+ * Server configuration schema
33
+ */
34
+ export declare const serverConfigSchema: z.ZodObject<{
35
+ autoStart: z.ZodBoolean;
36
+ autoStopMinutes: z.ZodNumber;
37
+ }, z.core.$strip>;
38
+ /**
39
+ * Complete configuration schema
40
+ */
41
+ export declare const configSchema: z.ZodObject<{
42
+ library: z.ZodString;
43
+ logLevel: z.ZodEnum<{
44
+ silent: "silent";
45
+ info: "info";
46
+ debug: "debug";
47
+ }>;
48
+ backup: z.ZodObject<{
49
+ maxGenerations: z.ZodNumber;
50
+ maxAgeDays: z.ZodNumber;
51
+ directory: z.ZodString;
52
+ }, z.core.$strip>;
53
+ watch: z.ZodObject<{
54
+ enabled: z.ZodBoolean;
55
+ debounceMs: z.ZodNumber;
56
+ pollIntervalMs: z.ZodNumber;
57
+ retryIntervalMs: z.ZodNumber;
58
+ maxRetries: z.ZodNumber;
59
+ }, z.core.$strip>;
60
+ server: z.ZodObject<{
61
+ autoStart: z.ZodBoolean;
62
+ autoStopMinutes: z.ZodNumber;
63
+ }, z.core.$strip>;
64
+ }, z.core.$strip>;
65
+ /**
66
+ * Partial configuration schema (for TOML files)
67
+ * Supports both camelCase and snake_case field names
68
+ */
69
+ export declare const partialConfigSchema: z.ZodObject<{
70
+ library: z.ZodOptional<z.ZodString>;
71
+ logLevel: z.ZodOptional<z.ZodEnum<{
72
+ silent: "silent";
73
+ info: "info";
74
+ debug: "debug";
75
+ }>>;
76
+ log_level: z.ZodOptional<z.ZodEnum<{
77
+ silent: "silent";
78
+ info: "info";
79
+ debug: "debug";
80
+ }>>;
81
+ backup: z.ZodOptional<z.ZodObject<{
82
+ maxGenerations: z.ZodOptional<z.ZodNumber>;
83
+ max_generations: z.ZodOptional<z.ZodNumber>;
84
+ maxAgeDays: z.ZodOptional<z.ZodNumber>;
85
+ max_age_days: z.ZodOptional<z.ZodNumber>;
86
+ directory: z.ZodOptional<z.ZodString>;
87
+ }, z.core.$strip>>;
88
+ watch: z.ZodOptional<z.ZodObject<{
89
+ enabled: z.ZodOptional<z.ZodBoolean>;
90
+ debounceMs: z.ZodOptional<z.ZodNumber>;
91
+ debounce_ms: z.ZodOptional<z.ZodNumber>;
92
+ pollIntervalMs: z.ZodOptional<z.ZodNumber>;
93
+ poll_interval_ms: z.ZodOptional<z.ZodNumber>;
94
+ retryIntervalMs: z.ZodOptional<z.ZodNumber>;
95
+ retry_interval_ms: z.ZodOptional<z.ZodNumber>;
96
+ maxRetries: z.ZodOptional<z.ZodNumber>;
97
+ max_retries: z.ZodOptional<z.ZodNumber>;
98
+ }, z.core.$strip>>;
99
+ server: z.ZodOptional<z.ZodObject<{
100
+ autoStart: z.ZodOptional<z.ZodBoolean>;
101
+ auto_start: z.ZodOptional<z.ZodBoolean>;
102
+ autoStopMinutes: z.ZodOptional<z.ZodNumber>;
103
+ auto_stop_minutes: z.ZodOptional<z.ZodNumber>;
104
+ }, z.core.$strip>>;
105
+ }, z.core.$loose>;
106
+ /**
107
+ * Inferred types from schemas
108
+ */
109
+ export type LogLevel = z.infer<typeof logLevelSchema>;
110
+ export type BackupConfig = z.infer<typeof backupConfigSchema>;
111
+ export type WatchConfig = z.infer<typeof watchConfigSchema>;
112
+ export type ServerConfig = z.infer<typeof serverConfigSchema>;
113
+ export type Config = z.infer<typeof configSchema>;
114
+ export type PartialConfig = z.infer<typeof partialConfigSchema>;
115
+ /**
116
+ * Deep partial type for Config
117
+ */
118
+ export type DeepPartialConfig = {
119
+ library?: string;
120
+ logLevel?: LogLevel;
121
+ backup?: Partial<BackupConfig>;
122
+ watch?: Partial<WatchConfig>;
123
+ server?: Partial<ServerConfig>;
124
+ };
125
+ /**
126
+ * Normalize snake_case fields to camelCase
127
+ */
128
+ export declare function normalizePartialConfig(partial: PartialConfig): DeepPartialConfig;
129
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,cAAc;;;;EAAsC,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;iBAI7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;iBAM5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;iBAMvB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoChB,CAAC;AAEjB;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAClD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CAChC,CAAC;AAwGF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,GAAG,iBAAiB,CA2ChF"}
@@ -0,0 +1,9 @@
1
+ import { type CslLibrary } from "./types";
2
+ /**
3
+ * Parse a CSL-JSON file and ensure all entries have valid UUIDs and timestamps
4
+ * @param filePath - Path to the CSL-JSON file
5
+ * @returns Array of CSL-JSON items with guaranteed UUIDs and timestamps
6
+ * @throws Error if file cannot be read or JSON is invalid
7
+ */
8
+ export declare function parseCslJson(filePath: string): Promise<CslLibrary>;
9
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/core/csl-json/parser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,SAAS,CAAC;AAwB5D;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAgDxE"}
@@ -0,0 +1,15 @@
1
+ import type { CslLibrary } from "./types";
2
+ /**
3
+ * Serialize a CSL-JSON library to a formatted JSON string
4
+ * @param library - CSL-JSON library (array of items)
5
+ * @returns Formatted JSON string with 2-space indentation
6
+ */
7
+ export declare function serializeCslJson(library: CslLibrary): string;
8
+ /**
9
+ * Write a CSL-JSON library to a file
10
+ * @param filePath - Path to write the CSL-JSON file
11
+ * @param library - CSL-JSON library to write
12
+ * @throws Error if file cannot be written
13
+ */
14
+ export declare function writeCslJson(filePath: string, library: CslLibrary): Promise<void>;
15
+ //# sourceMappingURL=serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../../src/core/csl-json/serializer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAe1C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAiB5D;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvF"}
@@ -0,0 +1,124 @@
1
+ import { z } from "zod";
2
+ declare const CslCustomSchema: z.ZodObject<{
3
+ uuid: z.ZodString;
4
+ created_at: z.ZodString;
5
+ timestamp: z.ZodString;
6
+ additional_urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
7
+ }, z.core.$strip>;
8
+ export declare const CslItemSchema: z.ZodObject<{
9
+ id: z.ZodString;
10
+ type: z.ZodString;
11
+ title: z.ZodOptional<z.ZodString>;
12
+ author: z.ZodOptional<z.ZodArray<z.ZodObject<{
13
+ family: z.ZodOptional<z.ZodString>;
14
+ given: z.ZodOptional<z.ZodString>;
15
+ literal: z.ZodOptional<z.ZodString>;
16
+ "dropping-particle": z.ZodOptional<z.ZodString>;
17
+ "non-dropping-particle": z.ZodOptional<z.ZodString>;
18
+ suffix: z.ZodOptional<z.ZodString>;
19
+ }, z.core.$strip>>>;
20
+ editor: z.ZodOptional<z.ZodArray<z.ZodObject<{
21
+ family: z.ZodOptional<z.ZodString>;
22
+ given: z.ZodOptional<z.ZodString>;
23
+ literal: z.ZodOptional<z.ZodString>;
24
+ "dropping-particle": z.ZodOptional<z.ZodString>;
25
+ "non-dropping-particle": z.ZodOptional<z.ZodString>;
26
+ suffix: z.ZodOptional<z.ZodString>;
27
+ }, z.core.$strip>>>;
28
+ issued: z.ZodOptional<z.ZodObject<{
29
+ "date-parts": z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodNumber>>>;
30
+ raw: z.ZodOptional<z.ZodString>;
31
+ season: z.ZodOptional<z.ZodString>;
32
+ circa: z.ZodOptional<z.ZodBoolean>;
33
+ literal: z.ZodOptional<z.ZodString>;
34
+ }, z.core.$strip>>;
35
+ accessed: z.ZodOptional<z.ZodObject<{
36
+ "date-parts": z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodNumber>>>;
37
+ raw: z.ZodOptional<z.ZodString>;
38
+ season: z.ZodOptional<z.ZodString>;
39
+ circa: z.ZodOptional<z.ZodBoolean>;
40
+ literal: z.ZodOptional<z.ZodString>;
41
+ }, z.core.$strip>>;
42
+ "container-title": z.ZodOptional<z.ZodString>;
43
+ volume: z.ZodOptional<z.ZodString>;
44
+ issue: z.ZodOptional<z.ZodString>;
45
+ page: z.ZodOptional<z.ZodString>;
46
+ DOI: z.ZodOptional<z.ZodString>;
47
+ PMID: z.ZodOptional<z.ZodString>;
48
+ PMCID: z.ZodOptional<z.ZodString>;
49
+ ISBN: z.ZodOptional<z.ZodString>;
50
+ ISSN: z.ZodOptional<z.ZodString>;
51
+ URL: z.ZodOptional<z.ZodString>;
52
+ abstract: z.ZodOptional<z.ZodString>;
53
+ publisher: z.ZodOptional<z.ZodString>;
54
+ "publisher-place": z.ZodOptional<z.ZodString>;
55
+ note: z.ZodOptional<z.ZodString>;
56
+ keyword: z.ZodOptional<z.ZodArray<z.ZodString>>;
57
+ custom: z.ZodOptional<z.ZodObject<{
58
+ uuid: z.ZodString;
59
+ created_at: z.ZodString;
60
+ timestamp: z.ZodString;
61
+ additional_urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
62
+ }, z.core.$strip>>;
63
+ }, z.core.$loose>;
64
+ export declare const CslLibrarySchema: z.ZodArray<z.ZodObject<{
65
+ id: z.ZodString;
66
+ type: z.ZodString;
67
+ title: z.ZodOptional<z.ZodString>;
68
+ author: z.ZodOptional<z.ZodArray<z.ZodObject<{
69
+ family: z.ZodOptional<z.ZodString>;
70
+ given: z.ZodOptional<z.ZodString>;
71
+ literal: z.ZodOptional<z.ZodString>;
72
+ "dropping-particle": z.ZodOptional<z.ZodString>;
73
+ "non-dropping-particle": z.ZodOptional<z.ZodString>;
74
+ suffix: z.ZodOptional<z.ZodString>;
75
+ }, z.core.$strip>>>;
76
+ editor: z.ZodOptional<z.ZodArray<z.ZodObject<{
77
+ family: z.ZodOptional<z.ZodString>;
78
+ given: z.ZodOptional<z.ZodString>;
79
+ literal: z.ZodOptional<z.ZodString>;
80
+ "dropping-particle": z.ZodOptional<z.ZodString>;
81
+ "non-dropping-particle": z.ZodOptional<z.ZodString>;
82
+ suffix: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>>>;
84
+ issued: z.ZodOptional<z.ZodObject<{
85
+ "date-parts": z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodNumber>>>;
86
+ raw: z.ZodOptional<z.ZodString>;
87
+ season: z.ZodOptional<z.ZodString>;
88
+ circa: z.ZodOptional<z.ZodBoolean>;
89
+ literal: z.ZodOptional<z.ZodString>;
90
+ }, z.core.$strip>>;
91
+ accessed: z.ZodOptional<z.ZodObject<{
92
+ "date-parts": z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodNumber>>>;
93
+ raw: z.ZodOptional<z.ZodString>;
94
+ season: z.ZodOptional<z.ZodString>;
95
+ circa: z.ZodOptional<z.ZodBoolean>;
96
+ literal: z.ZodOptional<z.ZodString>;
97
+ }, z.core.$strip>>;
98
+ "container-title": z.ZodOptional<z.ZodString>;
99
+ volume: z.ZodOptional<z.ZodString>;
100
+ issue: z.ZodOptional<z.ZodString>;
101
+ page: z.ZodOptional<z.ZodString>;
102
+ DOI: z.ZodOptional<z.ZodString>;
103
+ PMID: z.ZodOptional<z.ZodString>;
104
+ PMCID: z.ZodOptional<z.ZodString>;
105
+ ISBN: z.ZodOptional<z.ZodString>;
106
+ ISSN: z.ZodOptional<z.ZodString>;
107
+ URL: z.ZodOptional<z.ZodString>;
108
+ abstract: z.ZodOptional<z.ZodString>;
109
+ publisher: z.ZodOptional<z.ZodString>;
110
+ "publisher-place": z.ZodOptional<z.ZodString>;
111
+ note: z.ZodOptional<z.ZodString>;
112
+ keyword: z.ZodOptional<z.ZodArray<z.ZodString>>;
113
+ custom: z.ZodOptional<z.ZodObject<{
114
+ uuid: z.ZodString;
115
+ created_at: z.ZodString;
116
+ timestamp: z.ZodString;
117
+ additional_urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
118
+ }, z.core.$strip>>;
119
+ }, z.core.$loose>>;
120
+ export type CslCustom = z.infer<typeof CslCustomSchema>;
121
+ export type CslItem = z.infer<typeof CslItemSchema>;
122
+ export type CslLibrary = z.infer<typeof CslLibrarySchema>;
123
+ export {};
124
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/csl-json/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsBxB,QAAA,MAAM,eAAe;;;;;iBAKnB,CAAC;AAGH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2BV,CAAC;AAGjB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyB,CAAC;AAEvD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AACpD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { CslItem, CslLibrary } from "./types";
2
+ /**
3
+ * Validate CSL-JSON library structure
4
+ * @param data - Data to validate (can be any type)
5
+ * @returns Validated CSL-JSON library
6
+ * @throws Error if validation fails
7
+ */
8
+ export declare function validateCslJson(data: unknown): CslLibrary;
9
+ /**
10
+ * Validate a single CSL-JSON item
11
+ * @param data - Data to validate (can be any type)
12
+ * @returns Validation result with valid flag and errors
13
+ */
14
+ export declare function validateCslItem(data: unknown): {
15
+ valid: boolean;
16
+ data?: CslItem;
17
+ errors?: string[];
18
+ };
19
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/csl-json/validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAQzD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAcA"}
@@ -0,0 +1,17 @@
1
+ import type { CslItem } from "../csl-json/types";
2
+ /**
3
+ * Generate a BibTeX-style ID for a CSL-JSON item
4
+ * Format: <FirstAuthorFamily>-<Year>[<TitleSlug>][a-z suffix]
5
+ * @param item - CSL-JSON item
6
+ * @returns Generated ID
7
+ */
8
+ export declare function generateId(item: CslItem): string;
9
+ /**
10
+ * Generate ID with collision check
11
+ * Appends a, b, c, ... suffix if the base ID already exists
12
+ * @param item - CSL-JSON item
13
+ * @param existingIds - Array of existing IDs
14
+ * @returns Generated ID with collision handling
15
+ */
16
+ export declare function generateIdWithCollisionCheck(item: CslItem, existingIds: string[]): string;
17
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../src/core/identifier/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AA0EjD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAWhD;AAyBD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAiBzF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Normalize text for identifier generation
3
+ * Converts to lowercase, converts spaces to underscores, keeps only alphanumeric and underscores
4
+ * @param text - Text to normalize
5
+ * @returns Normalized text (ASCII alphanumeric and underscores only)
6
+ */
7
+ export declare function normalizeText(text: string): string;
8
+ /**
9
+ * Normalize author name for identifier
10
+ * @param name - Author name to normalize
11
+ * @returns Normalized name (max 32 chars)
12
+ */
13
+ export declare function normalizeAuthorName(name: string): string;
14
+ /**
15
+ * Create a title slug for identifier
16
+ * @param title - Title to create slug from
17
+ * @returns Title slug (max 32 chars)
18
+ */
19
+ export declare function normalizeTitleSlug(title: string): string;
20
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../src/core/identifier/normalize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGxD"}