@ncukondo/reference-manager 0.33.0 → 0.33.2

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 (32) hide show
  1. package/dist/chunks/{SearchableMultiSelect-B8QVnO_p.js → SearchableMultiSelect-CvthFBf3.js} +2 -2
  2. package/dist/chunks/{SearchableMultiSelect-B8QVnO_p.js.map → SearchableMultiSelect-CvthFBf3.js.map} +1 -1
  3. package/dist/chunks/{action-menu-i1v02Qig.js → action-menu-BWSeIIPB.js} +3 -3
  4. package/dist/chunks/{action-menu-i1v02Qig.js.map → action-menu-BWSeIIPB.js.map} +1 -1
  5. package/dist/chunks/{checker-CnWQe7v2.js → checker-Bsxp9sCm.js} +4 -4
  6. package/dist/chunks/{checker-CnWQe7v2.js.map → checker-Bsxp9sCm.js.map} +1 -1
  7. package/dist/chunks/{crossref-client-Dxwv2A5D.js → crossref-client-CYwiZLF9.js} +2 -2
  8. package/dist/chunks/{crossref-client-Dxwv2A5D.js.map → crossref-client-CYwiZLF9.js.map} +1 -1
  9. package/dist/chunks/{fix-interaction-D_zhtL9k.js → fix-interaction-Ebrjh1H0.js} +5 -5
  10. package/dist/chunks/{fix-interaction-D_zhtL9k.js.map → fix-interaction-Ebrjh1H0.js.map} +1 -1
  11. package/dist/chunks/{index-PkCQJBdt.js → index-Bm25py-B.js} +28 -28
  12. package/dist/chunks/index-Bm25py-B.js.map +1 -0
  13. package/dist/chunks/{index-DMShdNwY.js → index-BrfxHfSZ.js} +4 -4
  14. package/dist/chunks/{index-DMShdNwY.js.map → index-BrfxHfSZ.js.map} +1 -1
  15. package/dist/chunks/{index-a52FHX03.js → index-CA7km4m0.js} +14 -5
  16. package/dist/chunks/{index-a52FHX03.js.map → index-CA7km4m0.js.map} +1 -1
  17. package/dist/chunks/{index-DpZ-Ma7M.js → index-QxdPt5c9.js} +3 -3
  18. package/dist/chunks/index-QxdPt5c9.js.map +1 -0
  19. package/dist/chunks/{pubmed-client-CPFYI4kR.js → pubmed-client-Cw87sE2s.js} +2 -2
  20. package/dist/chunks/{pubmed-client-CPFYI4kR.js.map → pubmed-client-Cw87sE2s.js.map} +1 -1
  21. package/dist/chunks/{reference-select-aEB3-5rp.js → reference-select-CsXBOR8g.js} +3 -3
  22. package/dist/chunks/{reference-select-aEB3-5rp.js.map → reference-select-CsXBOR8g.js.map} +1 -1
  23. package/dist/chunks/{style-select-CQ4BBBZJ.js → style-select-Bo9u9rtE.js} +3 -3
  24. package/dist/chunks/{style-select-CQ4BBBZJ.js.map → style-select-Bo9u9rtE.js.map} +1 -1
  25. package/dist/cli.js +2 -2
  26. package/dist/features/import/browser.d.ts +1 -1
  27. package/dist/features/import/browser.d.ts.map +1 -1
  28. package/dist/server/routes/add.d.ts.map +1 -1
  29. package/dist/server.js +1 -1
  30. package/package.json +1 -1
  31. package/dist/chunks/index-DpZ-Ma7M.js.map +0 -1
  32. package/dist/chunks/index-PkCQJBdt.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"checker-CnWQe7v2.js","sources":["../../src/features/check/checker.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { CrossrefUpdateInfo, RemoteMetadata } from \"./crossref-client.js\";\nimport type { CheckFinding, CheckResult } from \"./types.js\";\n\nexport interface CheckConfig {\n email?: string;\n pubmed?: { email?: string; apiKey?: string };\n metadata?: boolean;\n}\n\ninterface CrossrefCheckResult {\n findings: CheckFinding[];\n metadata?: RemoteMetadata;\n}\n\n/**\n * Check a single reference against external sources for status changes.\n *\n * @param item - The CSL-JSON item to check\n * @param config - Optional config for API credentials\n * @returns Check result with findings\n */\nexport async function checkReference(item: CslItem, config?: CheckConfig): Promise<CheckResult> {\n const id = item.id;\n const uuid = (item.custom?.uuid as string) ?? \"\";\n const checkedAt = new Date().toISOString();\n const findings: CheckFinding[] = [];\n const checkedSources: string[] = [];\n\n const hasDoi = !!item.DOI;\n const hasPmid = !!item.PMID;\n\n // Skip references with neither DOI nor PMID\n if (!hasDoi && !hasPmid) {\n return { id, uuid, status: \"skipped\", findings: [], checkedAt, checkedSources: [] };\n }\n\n let crossrefMetadata: RemoteMetadata | undefined;\n\n // Query Crossref if DOI is present\n if (hasDoi) {\n checkedSources.push(\"crossref\");\n const crossrefResult = await checkCrossref(item.DOI as string, config);\n findings.push(...crossrefResult.findings);\n crossrefMetadata = crossrefResult.metadata;\n }\n\n // Query PubMed if PMID is present\n if (hasPmid) {\n checkedSources.push(\"pubmed\");\n const pubmedFindings = await checkPubmed(item.PMID as string, config);\n addUniqueFindings(findings, pubmedFindings);\n }\n\n // Metadata comparison (default: enabled)\n const metadataFinding = await checkMetadata(item, config, crossrefMetadata, hasPmid, hasDoi);\n if (metadataFinding) {\n findings.push(metadataFinding);\n }\n\n const status = findings.length > 0 ? \"warning\" : \"ok\";\n return { id, uuid, status, findings, checkedAt, checkedSources };\n}\n\n/**\n * Add findings that aren't already present (by type) to the target list.\n */\nfunction addUniqueFindings(target: CheckFinding[], source: CheckFinding[]): void {\n for (const finding of source) {\n if (!target.some((f) => f.type === finding.type)) {\n target.push(finding);\n }\n }\n}\n\n/**\n * Perform metadata comparison if enabled.\n */\nasync function checkMetadata(\n item: CslItem,\n config: CheckConfig | undefined,\n crossrefMetadata: RemoteMetadata | undefined,\n hasPmid: boolean,\n hasDoi: boolean\n): Promise<CheckFinding | null> {\n if (config?.metadata === false) return null;\n\n if (crossrefMetadata) {\n // DOI-based: compare against Crossref metadata\n return compareItemMetadata(item, crossrefMetadata);\n }\n\n if (hasPmid && !hasDoi) {\n // PubMed-only: fetch remote CSL-JSON via PubMed and compare\n return comparePubmedMetadata(item, config);\n }\n\n return null;\n}\n\n/**\n * Query Crossref and return findings plus metadata.\n */\nasync function checkCrossref(doi: string, config?: CheckConfig): Promise<CrossrefCheckResult> {\n const { queryCrossref } = await import(\"./crossref-client.js\");\n const crossrefConfig = config?.email ? { email: config.email } : undefined;\n const result = await queryCrossref(doi, crossrefConfig);\n if (!result.success) return { findings: [] };\n\n const findings: CheckFinding[] = [];\n for (const update of result.updates) {\n const finding = mapCrossrefUpdate(update);\n if (finding) {\n findings.push(finding);\n }\n }\n return result.metadata ? { findings, metadata: result.metadata } : { findings };\n}\n\n/**\n * Compare item metadata against Crossref metadata.\n */\nasync function compareItemMetadata(\n item: CslItem,\n remoteMetadata: RemoteMetadata\n): Promise<CheckFinding | null> {\n const { compareMetadata } = await import(\"./metadata-comparator.js\");\n\n const local = extractLocalMetadata(item);\n const comparison = compareMetadata(local, remoteMetadata);\n\n if (comparison.classification === \"no_change\") return null;\n\n const type = comparison.classification;\n const message =\n type === \"metadata_mismatch\"\n ? \"Local metadata significantly differs from the remote record\"\n : \"Remote metadata has been updated since import\";\n\n return {\n type,\n message,\n details: {\n updatedFields: comparison.changedFields,\n fieldDiffs: comparison.fieldDiffs,\n },\n };\n}\n\n/**\n * Fetch PubMed CSL-JSON and compare metadata for PMID-only references.\n */\nasync function comparePubmedMetadata(\n item: CslItem,\n config?: CheckConfig\n): Promise<CheckFinding | null> {\n const { fetchPmids } = await import(\"../import/fetcher.js\");\n const pubmedConfig = config?.pubmed ?? {};\n const results = await fetchPmids([item.PMID as string], pubmedConfig);\n const result = results[0];\n if (!result || !result.success) {\n console.error(\n `PubMed metadata fetch failed for PMID ${item.PMID}: ${result?.error ?? \"unknown error\"}`\n );\n return null;\n }\n\n const remoteMetadata = cslItemToRemoteMetadata(result.item);\n return compareItemMetadata(item, remoteMetadata);\n}\n\n/**\n * Convert a CslItem (from PubMed) to RemoteMetadata format for comparison.\n */\nfunction cslItemToRemoteMetadata(item: CslItem): RemoteMetadata {\n const metadata: RemoteMetadata = {};\n if (item.title !== undefined) metadata.title = item.title;\n if (item.author !== undefined) {\n metadata.author = item.author as Array<{ family?: string; given?: string }>;\n }\n if (item[\"container-title\"] !== undefined) metadata.containerTitle = item[\"container-title\"];\n if (item.type !== undefined) metadata.type = item.type;\n if (item.page !== undefined) metadata.page = item.page;\n if (item.volume !== undefined) metadata.volume = item.volume;\n if (item.issue !== undefined) metadata.issue = item.issue;\n if (item.issued !== undefined) {\n metadata.issued = item.issued as { \"date-parts\"?: number[][] };\n }\n return metadata;\n}\n\n/**\n * Extract local metadata fields from a CslItem for comparison.\n */\nfunction extractLocalMetadata(\n item: CslItem\n): import(\"./metadata-comparator.js\").LocalMetadataFields {\n const local: import(\"./metadata-comparator.js\").LocalMetadataFields = {};\n if (item.title !== undefined) local.title = item.title;\n if (item.author !== undefined)\n local.author = item.author as Array<{ family?: string; given?: string }>;\n if (item[\"container-title\"] !== undefined) local[\"container-title\"] = item[\"container-title\"];\n if (item.type !== undefined) local.type = item.type;\n if (item.page !== undefined) local.page = item.page;\n if (item.volume !== undefined) local.volume = item.volume;\n if (item.issue !== undefined) local.issue = item.issue;\n if (item.issued !== undefined) local.issued = item.issued as { \"date-parts\"?: number[][] };\n return local;\n}\n\n/**\n * Query PubMed and return findings.\n */\nasync function checkPubmed(pmid: string, config?: CheckConfig): Promise<CheckFinding[]> {\n const { queryPubmed } = await import(\"./pubmed-client.js\");\n const result = await queryPubmed(pmid, config?.pubmed);\n if (!result.success) return [];\n\n const findings: CheckFinding[] = [];\n if (result.isRetracted) {\n findings.push({\n type: \"retracted\",\n message: \"This article is marked as retracted in PubMed\",\n });\n }\n if (result.hasConcern) {\n findings.push({\n type: \"concern\",\n message: \"Expression of concern noted in PubMed\",\n });\n }\n return findings;\n}\n\n/**\n * Map a Crossref update-to entry to a CheckFinding.\n */\nfunction mapCrossrefUpdate(update: CrossrefUpdateInfo): CheckFinding | null {\n const doiDetail = update.doi ? { retractionDoi: update.doi } : {};\n const dateDetail = update.date ? { retractionDate: update.date } : {};\n const newDoiDetail = update.doi ? { newDoi: update.doi } : {};\n\n switch (update.type) {\n case \"retraction\":\n return {\n type: \"retracted\",\n message: update.date\n ? `This article was retracted on ${update.date}`\n : \"This article was retracted\",\n details: { ...doiDetail, ...dateDetail },\n };\n case \"expression-of-concern\":\n return {\n type: \"concern\",\n message: update.date\n ? `Expression of concern issued on ${update.date}`\n : \"Expression of concern issued\",\n details: { ...doiDetail, ...dateDetail },\n };\n case \"new_version\":\n return {\n type: \"version_changed\",\n message: update.doi\n ? `Published version available: ${update.doi}`\n : \"Published version available\",\n details: newDoiDetail,\n };\n default:\n return null;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"checker-Bsxp9sCm.js","sources":["../../src/features/check/checker.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { CrossrefUpdateInfo, RemoteMetadata } from \"./crossref-client.js\";\nimport type { CheckFinding, CheckResult } from \"./types.js\";\n\nexport interface CheckConfig {\n email?: string;\n pubmed?: { email?: string; apiKey?: string };\n metadata?: boolean;\n}\n\ninterface CrossrefCheckResult {\n findings: CheckFinding[];\n metadata?: RemoteMetadata;\n}\n\n/**\n * Check a single reference against external sources for status changes.\n *\n * @param item - The CSL-JSON item to check\n * @param config - Optional config for API credentials\n * @returns Check result with findings\n */\nexport async function checkReference(item: CslItem, config?: CheckConfig): Promise<CheckResult> {\n const id = item.id;\n const uuid = (item.custom?.uuid as string) ?? \"\";\n const checkedAt = new Date().toISOString();\n const findings: CheckFinding[] = [];\n const checkedSources: string[] = [];\n\n const hasDoi = !!item.DOI;\n const hasPmid = !!item.PMID;\n\n // Skip references with neither DOI nor PMID\n if (!hasDoi && !hasPmid) {\n return { id, uuid, status: \"skipped\", findings: [], checkedAt, checkedSources: [] };\n }\n\n let crossrefMetadata: RemoteMetadata | undefined;\n\n // Query Crossref if DOI is present\n if (hasDoi) {\n checkedSources.push(\"crossref\");\n const crossrefResult = await checkCrossref(item.DOI as string, config);\n findings.push(...crossrefResult.findings);\n crossrefMetadata = crossrefResult.metadata;\n }\n\n // Query PubMed if PMID is present\n if (hasPmid) {\n checkedSources.push(\"pubmed\");\n const pubmedFindings = await checkPubmed(item.PMID as string, config);\n addUniqueFindings(findings, pubmedFindings);\n }\n\n // Metadata comparison (default: enabled)\n const metadataFinding = await checkMetadata(item, config, crossrefMetadata, hasPmid, hasDoi);\n if (metadataFinding) {\n findings.push(metadataFinding);\n }\n\n const status = findings.length > 0 ? \"warning\" : \"ok\";\n return { id, uuid, status, findings, checkedAt, checkedSources };\n}\n\n/**\n * Add findings that aren't already present (by type) to the target list.\n */\nfunction addUniqueFindings(target: CheckFinding[], source: CheckFinding[]): void {\n for (const finding of source) {\n if (!target.some((f) => f.type === finding.type)) {\n target.push(finding);\n }\n }\n}\n\n/**\n * Perform metadata comparison if enabled.\n */\nasync function checkMetadata(\n item: CslItem,\n config: CheckConfig | undefined,\n crossrefMetadata: RemoteMetadata | undefined,\n hasPmid: boolean,\n hasDoi: boolean\n): Promise<CheckFinding | null> {\n if (config?.metadata === false) return null;\n\n if (crossrefMetadata) {\n // DOI-based: compare against Crossref metadata\n return compareItemMetadata(item, crossrefMetadata);\n }\n\n if (hasPmid && !hasDoi) {\n // PubMed-only: fetch remote CSL-JSON via PubMed and compare\n return comparePubmedMetadata(item, config);\n }\n\n return null;\n}\n\n/**\n * Query Crossref and return findings plus metadata.\n */\nasync function checkCrossref(doi: string, config?: CheckConfig): Promise<CrossrefCheckResult> {\n const { queryCrossref } = await import(\"./crossref-client.js\");\n const crossrefConfig = config?.email ? { email: config.email } : undefined;\n const result = await queryCrossref(doi, crossrefConfig);\n if (!result.success) return { findings: [] };\n\n const findings: CheckFinding[] = [];\n for (const update of result.updates) {\n const finding = mapCrossrefUpdate(update);\n if (finding) {\n findings.push(finding);\n }\n }\n return result.metadata ? { findings, metadata: result.metadata } : { findings };\n}\n\n/**\n * Compare item metadata against Crossref metadata.\n */\nasync function compareItemMetadata(\n item: CslItem,\n remoteMetadata: RemoteMetadata\n): Promise<CheckFinding | null> {\n const { compareMetadata } = await import(\"./metadata-comparator.js\");\n\n const local = extractLocalMetadata(item);\n const comparison = compareMetadata(local, remoteMetadata);\n\n if (comparison.classification === \"no_change\") return null;\n\n const type = comparison.classification;\n const message =\n type === \"metadata_mismatch\"\n ? \"Local metadata significantly differs from the remote record\"\n : \"Remote metadata has been updated since import\";\n\n return {\n type,\n message,\n details: {\n updatedFields: comparison.changedFields,\n fieldDiffs: comparison.fieldDiffs,\n },\n };\n}\n\n/**\n * Fetch PubMed CSL-JSON and compare metadata for PMID-only references.\n */\nasync function comparePubmedMetadata(\n item: CslItem,\n config?: CheckConfig\n): Promise<CheckFinding | null> {\n const { fetchPmids } = await import(\"../import/fetcher.js\");\n const pubmedConfig = config?.pubmed ?? {};\n const results = await fetchPmids([item.PMID as string], pubmedConfig);\n const result = results[0];\n if (!result || !result.success) {\n console.error(\n `PubMed metadata fetch failed for PMID ${item.PMID}: ${result?.error ?? \"unknown error\"}`\n );\n return null;\n }\n\n const remoteMetadata = cslItemToRemoteMetadata(result.item);\n return compareItemMetadata(item, remoteMetadata);\n}\n\n/**\n * Convert a CslItem (from PubMed) to RemoteMetadata format for comparison.\n */\nfunction cslItemToRemoteMetadata(item: CslItem): RemoteMetadata {\n const metadata: RemoteMetadata = {};\n if (item.title !== undefined) metadata.title = item.title;\n if (item.author !== undefined) {\n metadata.author = item.author as Array<{ family?: string; given?: string }>;\n }\n if (item[\"container-title\"] !== undefined) metadata.containerTitle = item[\"container-title\"];\n if (item.type !== undefined) metadata.type = item.type;\n if (item.page !== undefined) metadata.page = item.page;\n if (item.volume !== undefined) metadata.volume = item.volume;\n if (item.issue !== undefined) metadata.issue = item.issue;\n if (item.issued !== undefined) {\n metadata.issued = item.issued as { \"date-parts\"?: number[][] };\n }\n return metadata;\n}\n\n/**\n * Extract local metadata fields from a CslItem for comparison.\n */\nfunction extractLocalMetadata(\n item: CslItem\n): import(\"./metadata-comparator.js\").LocalMetadataFields {\n const local: import(\"./metadata-comparator.js\").LocalMetadataFields = {};\n if (item.title !== undefined) local.title = item.title;\n if (item.author !== undefined)\n local.author = item.author as Array<{ family?: string; given?: string }>;\n if (item[\"container-title\"] !== undefined) local[\"container-title\"] = item[\"container-title\"];\n if (item.type !== undefined) local.type = item.type;\n if (item.page !== undefined) local.page = item.page;\n if (item.volume !== undefined) local.volume = item.volume;\n if (item.issue !== undefined) local.issue = item.issue;\n if (item.issued !== undefined) local.issued = item.issued as { \"date-parts\"?: number[][] };\n return local;\n}\n\n/**\n * Query PubMed and return findings.\n */\nasync function checkPubmed(pmid: string, config?: CheckConfig): Promise<CheckFinding[]> {\n const { queryPubmed } = await import(\"./pubmed-client.js\");\n const result = await queryPubmed(pmid, config?.pubmed);\n if (!result.success) return [];\n\n const findings: CheckFinding[] = [];\n if (result.isRetracted) {\n findings.push({\n type: \"retracted\",\n message: \"This article is marked as retracted in PubMed\",\n });\n }\n if (result.hasConcern) {\n findings.push({\n type: \"concern\",\n message: \"Expression of concern noted in PubMed\",\n });\n }\n return findings;\n}\n\n/**\n * Map a Crossref update-to entry to a CheckFinding.\n */\nfunction mapCrossrefUpdate(update: CrossrefUpdateInfo): CheckFinding | null {\n const doiDetail = update.doi ? { retractionDoi: update.doi } : {};\n const dateDetail = update.date ? { retractionDate: update.date } : {};\n const newDoiDetail = update.doi ? { newDoi: update.doi } : {};\n\n switch (update.type) {\n case \"retraction\":\n return {\n type: \"retracted\",\n message: update.date\n ? `This article was retracted on ${update.date}`\n : \"This article was retracted\",\n details: { ...doiDetail, ...dateDetail },\n };\n case \"expression-of-concern\":\n return {\n type: \"concern\",\n message: update.date\n ? `Expression of concern issued on ${update.date}`\n : \"Expression of concern issued\",\n details: { ...doiDetail, ...dateDetail },\n };\n case \"new_version\":\n return {\n type: \"version_changed\",\n message: update.doi\n ? `Published version available: ${update.doi}`\n : \"Published version available\",\n details: newDoiDetail,\n };\n default:\n return null;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { g as getRateLimiter } from "./index-a52FHX03.js";
1
+ import { g as getRateLimiter } from "./index-CA7km4m0.js";
2
2
  const CROSSREF_API_BASE = "https://api.crossref.org/works";
3
3
  function formatDateParts(updated) {
4
4
  if (!updated || typeof updated !== "object") return {};
@@ -91,4 +91,4 @@ async function queryCrossref(doi, config) {
91
91
  export {
92
92
  queryCrossref
93
93
  };
94
- //# sourceMappingURL=crossref-client-Dxwv2A5D.js.map
94
+ //# sourceMappingURL=crossref-client-CYwiZLF9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crossref-client-Dxwv2A5D.js","sources":["../../src/features/check/crossref-client.ts"],"sourcesContent":["import { getRateLimiter } from \"../import/rate-limiter.js\";\n\nconst CROSSREF_API_BASE = \"https://api.crossref.org/works\";\n\nexport interface CrossrefUpdateInfo {\n type: string;\n doi?: string;\n label?: string;\n date?: string;\n}\n\nexport interface RemoteMetadata {\n title?: string;\n author?: Array<{ family?: string; given?: string }>;\n containerTitle?: string;\n type?: string;\n page?: string;\n volume?: string;\n issue?: string;\n issued?: { \"date-parts\"?: number[][] };\n}\n\nexport type CrossrefResult =\n | { success: true; updates: CrossrefUpdateInfo[]; metadata?: RemoteMetadata }\n | { success: false; error: string };\n\n/**\n * Format date-parts from Crossref API response to ISO date string.\n */\nfunction formatDateParts(updated: unknown): { date?: string } {\n if (!updated || typeof updated !== \"object\") return {};\n const dateParts = (updated as Record<string, unknown>)[\"date-parts\"];\n if (!Array.isArray(dateParts) || dateParts.length === 0) return {};\n const parts = dateParts[0] as number[];\n if (!Array.isArray(parts) || parts.length === 0) return {};\n const [year, month, day] = parts;\n const m = String(month ?? 1).padStart(2, \"0\");\n const d = String(day ?? 1).padStart(2, \"0\");\n return { date: `${year}-${m}-${d}` };\n}\n\n/**\n * Extract comparable metadata fields from a Crossref message object.\n */\nfunction extractMetadata(message: Record<string, unknown> | undefined): RemoteMetadata | undefined {\n if (!message) return undefined;\n\n const metadata: RemoteMetadata = {};\n\n // Title: array in Crossref, take first element\n const titleArr = message.title as string[] | undefined;\n const firstTitle = Array.isArray(titleArr) ? titleArr[0] : undefined;\n if (firstTitle) {\n metadata.title = firstTitle;\n }\n\n // Author\n const authorArr = message.author as Array<{ family?: string; given?: string }> | undefined;\n if (Array.isArray(authorArr) && authorArr.length > 0) {\n metadata.author = authorArr.map((a) => ({\n ...(a.family ? { family: a.family } : {}),\n ...(a.given ? { given: a.given } : {}),\n }));\n }\n\n // Container title: array in Crossref, take first\n const containerArr = message[\"container-title\"] as string[] | undefined;\n const firstContainer = Array.isArray(containerArr) ? containerArr[0] : undefined;\n if (firstContainer) {\n metadata.containerTitle = firstContainer;\n }\n\n // Type\n if (typeof message.type === \"string\") {\n metadata.type = message.type;\n }\n\n // Page, volume, issue\n if (typeof message.page === \"string\") metadata.page = message.page;\n if (typeof message.volume === \"string\") metadata.volume = message.volume;\n if (typeof message.issue === \"string\") metadata.issue = message.issue;\n\n // Issued\n const issued = message.issued as { \"date-parts\"?: number[][] } | undefined;\n if (issued && Array.isArray(issued[\"date-parts\"])) {\n metadata.issued = issued;\n }\n\n // Return undefined if no metadata fields were populated (prevents spurious diffs)\n if (Object.keys(metadata).length === 0) return undefined;\n\n return metadata;\n}\n\n/**\n * Query Crossref REST API for a DOI and extract update-to information.\n *\n * @param doi - The DOI to query\n * @param config - Optional config with email for polite pool\n * @returns Crossref result with update information\n */\nexport async function queryCrossref(\n doi: string,\n config?: { email?: string }\n): Promise<CrossrefResult> {\n const rateLimiter = getRateLimiter(\"crossref\", {});\n await rateLimiter.acquire();\n\n try {\n const url = new URL(`${CROSSREF_API_BASE}/${encodeURIComponent(doi)}`);\n if (config?.email) {\n url.searchParams.set(\"mailto\", config.email);\n }\n const response = await fetch(url.toString());\n\n if (!response.ok) {\n return {\n success: false,\n error: `Crossref API returned ${response.status} ${response.statusText}`,\n };\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const message = data.message as Record<string, unknown> | undefined;\n\n const updateTo = (message?.[\"update-to\"] ?? []) as Record<string, unknown>[];\n const updatedBy = (message?.[\"updated-by\"] ?? []) as Record<string, unknown>[];\n const allEntries: CrossrefUpdateInfo[] = [...updateTo, ...updatedBy].map((e) => {\n const datePart = formatDateParts(e.updated);\n return {\n type: String(e.type ?? \"\"),\n ...(e.DOI ? { doi: String(e.DOI) } : {}),\n ...(e.label ? { label: String(e.label) } : {}),\n ...(datePart.date ? { date: datePart.date } : {}),\n };\n });\n\n const seen = new Set<string>();\n const updates = allEntries.filter((e) => {\n const key = `${e.type}:${e.doi ?? \"\"}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n const metadata = extractMetadata(message);\n\n return metadata ? { success: true, updates, metadata } : { success: true, updates };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crossref-client-CYwiZLF9.js","sources":["../../src/features/check/crossref-client.ts"],"sourcesContent":["import { getRateLimiter } from \"../import/rate-limiter.js\";\n\nconst CROSSREF_API_BASE = \"https://api.crossref.org/works\";\n\nexport interface CrossrefUpdateInfo {\n type: string;\n doi?: string;\n label?: string;\n date?: string;\n}\n\nexport interface RemoteMetadata {\n title?: string;\n author?: Array<{ family?: string; given?: string }>;\n containerTitle?: string;\n type?: string;\n page?: string;\n volume?: string;\n issue?: string;\n issued?: { \"date-parts\"?: number[][] };\n}\n\nexport type CrossrefResult =\n | { success: true; updates: CrossrefUpdateInfo[]; metadata?: RemoteMetadata }\n | { success: false; error: string };\n\n/**\n * Format date-parts from Crossref API response to ISO date string.\n */\nfunction formatDateParts(updated: unknown): { date?: string } {\n if (!updated || typeof updated !== \"object\") return {};\n const dateParts = (updated as Record<string, unknown>)[\"date-parts\"];\n if (!Array.isArray(dateParts) || dateParts.length === 0) return {};\n const parts = dateParts[0] as number[];\n if (!Array.isArray(parts) || parts.length === 0) return {};\n const [year, month, day] = parts;\n const m = String(month ?? 1).padStart(2, \"0\");\n const d = String(day ?? 1).padStart(2, \"0\");\n return { date: `${year}-${m}-${d}` };\n}\n\n/**\n * Extract comparable metadata fields from a Crossref message object.\n */\nfunction extractMetadata(message: Record<string, unknown> | undefined): RemoteMetadata | undefined {\n if (!message) return undefined;\n\n const metadata: RemoteMetadata = {};\n\n // Title: array in Crossref, take first element\n const titleArr = message.title as string[] | undefined;\n const firstTitle = Array.isArray(titleArr) ? titleArr[0] : undefined;\n if (firstTitle) {\n metadata.title = firstTitle;\n }\n\n // Author\n const authorArr = message.author as Array<{ family?: string; given?: string }> | undefined;\n if (Array.isArray(authorArr) && authorArr.length > 0) {\n metadata.author = authorArr.map((a) => ({\n ...(a.family ? { family: a.family } : {}),\n ...(a.given ? { given: a.given } : {}),\n }));\n }\n\n // Container title: array in Crossref, take first\n const containerArr = message[\"container-title\"] as string[] | undefined;\n const firstContainer = Array.isArray(containerArr) ? containerArr[0] : undefined;\n if (firstContainer) {\n metadata.containerTitle = firstContainer;\n }\n\n // Type\n if (typeof message.type === \"string\") {\n metadata.type = message.type;\n }\n\n // Page, volume, issue\n if (typeof message.page === \"string\") metadata.page = message.page;\n if (typeof message.volume === \"string\") metadata.volume = message.volume;\n if (typeof message.issue === \"string\") metadata.issue = message.issue;\n\n // Issued\n const issued = message.issued as { \"date-parts\"?: number[][] } | undefined;\n if (issued && Array.isArray(issued[\"date-parts\"])) {\n metadata.issued = issued;\n }\n\n // Return undefined if no metadata fields were populated (prevents spurious diffs)\n if (Object.keys(metadata).length === 0) return undefined;\n\n return metadata;\n}\n\n/**\n * Query Crossref REST API for a DOI and extract update-to information.\n *\n * @param doi - The DOI to query\n * @param config - Optional config with email for polite pool\n * @returns Crossref result with update information\n */\nexport async function queryCrossref(\n doi: string,\n config?: { email?: string }\n): Promise<CrossrefResult> {\n const rateLimiter = getRateLimiter(\"crossref\", {});\n await rateLimiter.acquire();\n\n try {\n const url = new URL(`${CROSSREF_API_BASE}/${encodeURIComponent(doi)}`);\n if (config?.email) {\n url.searchParams.set(\"mailto\", config.email);\n }\n const response = await fetch(url.toString());\n\n if (!response.ok) {\n return {\n success: false,\n error: `Crossref API returned ${response.status} ${response.statusText}`,\n };\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const message = data.message as Record<string, unknown> | undefined;\n\n const updateTo = (message?.[\"update-to\"] ?? []) as Record<string, unknown>[];\n const updatedBy = (message?.[\"updated-by\"] ?? []) as Record<string, unknown>[];\n const allEntries: CrossrefUpdateInfo[] = [...updateTo, ...updatedBy].map((e) => {\n const datePart = formatDateParts(e.updated);\n return {\n type: String(e.type ?? \"\"),\n ...(e.DOI ? { doi: String(e.DOI) } : {}),\n ...(e.label ? { label: String(e.label) } : {}),\n ...(datePart.date ? { date: datePart.date } : {}),\n };\n });\n\n const seen = new Set<string>();\n const updates = allEntries.filter((e) => {\n const key = `${e.type}:${e.doi ?? \"\"}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n const metadata = extractMetadata(message);\n\n return metadata ? { success: true, updates, metadata } : { success: true, updates };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { render } from "ink";
2
2
  import { createElement } from "react";
3
- import { S as Select, r as restoreStdinAfterInk } from "./index-PkCQJBdt.js";
3
+ import { S as Select, r as restoreStdinAfterInk } from "./index-Bm25py-B.js";
4
4
  function getFixActionsForFinding(finding) {
5
5
  switch (finding.type) {
6
6
  case "retracted":
@@ -77,7 +77,7 @@ async function applyUpdateFromPublished(library, item, finding) {
77
77
  if (!newDoi) {
78
78
  return { applied: false, message: "No published DOI available in finding details" };
79
79
  }
80
- const { fetchDoi } = await import("./index-a52FHX03.js").then((n) => n.C);
80
+ const { fetchDoi } = await import("./index-CA7km4m0.js").then((n) => n.C);
81
81
  const fetchResult = await fetchDoi(newDoi);
82
82
  if (!fetchResult.success) {
83
83
  return {
@@ -93,7 +93,7 @@ async function applyUpdateFromPublished(library, item, finding) {
93
93
  async function applyUpdateAllFields(library, item, finding) {
94
94
  let fetchedItem;
95
95
  if (item.DOI) {
96
- const { fetchDoi } = await import("./index-a52FHX03.js").then((n) => n.C);
96
+ const { fetchDoi } = await import("./index-CA7km4m0.js").then((n) => n.C);
97
97
  const fetchResult = await fetchDoi(item.DOI);
98
98
  if (!fetchResult.success) {
99
99
  return {
@@ -103,7 +103,7 @@ async function applyUpdateAllFields(library, item, finding) {
103
103
  }
104
104
  fetchedItem = fetchResult.item;
105
105
  } else if (item.PMID) {
106
- const { fetchPmids } = await import("./index-a52FHX03.js").then((n) => n.C);
106
+ const { fetchPmids } = await import("./index-CA7km4m0.js").then((n) => n.C);
107
107
  const results = await fetchPmids([item.PMID], {});
108
108
  const result = results[0];
109
109
  if (!result || !result.success) {
@@ -259,4 +259,4 @@ async function runFixInteraction(results, library, findItem) {
259
259
  export {
260
260
  runFixInteraction
261
261
  };
262
- //# sourceMappingURL=fix-interaction-D_zhtL9k.js.map
262
+ //# sourceMappingURL=fix-interaction-Ebrjh1H0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fix-interaction-D_zhtL9k.js","sources":["../../src/features/check/fix-actions.ts","../../src/features/check/fix-interaction.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport type { CheckFinding } from \"./types.js\";\n\nexport type FixActionType =\n | \"add_retracted_tag\"\n | \"add_retraction_note\"\n | \"remove_from_library\"\n | \"update_from_published\"\n | \"add_version_tag\"\n | \"add_concern_tag\"\n | \"add_concern_note\"\n | \"update_all_fields\"\n | \"update_selected_fields\"\n | \"skip\";\n\nexport interface FixAction {\n type: FixActionType;\n label: string;\n}\n\nexport interface FixActionResult {\n applied: boolean;\n message: string;\n removed?: boolean;\n}\n\nexport function getFixActionsForFinding(finding: CheckFinding): FixAction[] {\n switch (finding.type) {\n case \"retracted\":\n return [\n { type: \"add_retracted_tag\", label: 'Add tag \"retracted\"' },\n { type: \"add_retraction_note\", label: \"Add note with retraction details\" },\n { type: \"remove_from_library\", label: \"Remove from library\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"version_changed\":\n return [\n { type: \"update_from_published\", label: \"Update metadata from published version\" },\n { type: \"add_version_tag\", label: 'Add tag \"has-published-version\"' },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"concern\":\n return [\n { type: \"add_concern_tag\", label: 'Add tag \"expression-of-concern\"' },\n { type: \"add_concern_note\", label: \"Add note with concern details\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"metadata_mismatch\":\n case \"metadata_outdated\":\n return [\n { type: \"update_all_fields\", label: \"Update all changed fields from remote\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n default:\n return [];\n }\n}\n\nfunction addTag(item: CslItem, tag: string): string[] {\n const existing = (item.custom?.tags as string[] | undefined) ?? [];\n if (existing.includes(tag)) {\n return existing;\n }\n return [...existing, tag];\n}\n\nfunction buildNoteText(prefix: string, finding: CheckFinding): string {\n const parts = [prefix];\n if (finding.details?.retractionDate) {\n parts.push(`Date: ${finding.details.retractionDate}`);\n }\n if (finding.details?.retractionDoi) {\n parts.push(`DOI: ${finding.details.retractionDoi}`);\n }\n return parts.join(\". \");\n}\n\nfunction appendNote(existingNote: string | undefined, newNote: string): string {\n if (existingNote) {\n return `${existingNote}\\n\\n${newNote}`;\n }\n return newNote;\n}\n\nasync function applyTagAction(\n library: ILibrary,\n item: CslItem,\n tag: string\n): Promise<FixActionResult> {\n const tags = addTag(item, tag);\n await library.update(item.id, { custom: { ...item.custom, tags } } as Partial<CslItem>, {\n idType: \"id\",\n });\n await library.save();\n return { applied: true, message: `Added tag \"${tag}\"` };\n}\n\nasync function applyNoteAction(\n library: ILibrary,\n item: CslItem,\n prefix: string,\n finding: CheckFinding\n): Promise<FixActionResult> {\n const noteText = buildNoteText(prefix, finding);\n const note = appendNote(item.note, noteText);\n await library.update(item.id, { note } as Partial<CslItem>, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Added note: ${noteText}` };\n}\n\nasync function applyUpdateFromPublished(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding\n): Promise<FixActionResult> {\n const newDoi = finding.details?.newDoi;\n if (!newDoi) {\n return { applied: false, message: \"No published DOI available in finding details\" };\n }\n const { fetchDoi } = await import(\"../import/fetcher.js\");\n const fetchResult = await fetchDoi(newDoi);\n if (!fetchResult.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for ${newDoi}: ${fetchResult.error}`,\n };\n }\n const { id: _id, custom: _custom, ...metadata } = fetchResult.item;\n await library.update(item.id, metadata as Partial<CslItem>, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Updated metadata from ${newDoi}` };\n}\n\nasync function applyUpdateAllFields(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding\n): Promise<FixActionResult> {\n let fetchedItem: CslItem;\n\n if (item.DOI) {\n const { fetchDoi } = await import(\"../import/fetcher.js\");\n const fetchResult = await fetchDoi(item.DOI);\n if (!fetchResult.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for DOI ${item.DOI}: ${fetchResult.error}`,\n };\n }\n fetchedItem = fetchResult.item;\n } else if (item.PMID) {\n const { fetchPmids } = await import(\"../import/fetcher.js\");\n const results = await fetchPmids([item.PMID], {});\n const result = results[0];\n if (!result || !result.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for PMID ${item.PMID}: ${result?.error ?? \"unknown error\"}`,\n };\n }\n fetchedItem = result.item;\n } else {\n return { applied: false, message: \"No DOI or PMID available for metadata update\" };\n }\n\n const updatedFields = finding.details?.updatedFields ?? [];\n const updates: Partial<CslItem> = {};\n for (const field of updatedFields) {\n if (field in fetchedItem) {\n (updates as Record<string, unknown>)[field] = (fetchedItem as Record<string, unknown>)[field];\n }\n }\n if (Object.keys(updates).length === 0) {\n return { applied: false, message: \"No fields to update\" };\n }\n await library.update(item.id, updates, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Updated fields: ${updatedFields.join(\", \")}` };\n}\n\nexport async function applyFixAction(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding,\n actionType: FixActionType\n): Promise<FixActionResult> {\n switch (actionType) {\n case \"add_retracted_tag\":\n return applyTagAction(library, item, \"retracted\");\n\n case \"add_retraction_note\":\n return applyNoteAction(library, item, \"RETRACTED\", finding);\n\n case \"add_concern_tag\":\n return applyTagAction(library, item, \"expression-of-concern\");\n\n case \"add_concern_note\":\n return applyNoteAction(library, item, \"EXPRESSION OF CONCERN\", finding);\n\n case \"add_version_tag\":\n return applyTagAction(library, item, \"has-published-version\");\n\n case \"remove_from_library\": {\n const removeResult = await library.remove(item.id, { idType: \"id\" });\n if (!removeResult.removed) {\n return { applied: false, message: `Failed to remove ${item.id}` };\n }\n await library.save();\n return { applied: true, message: `Removed ${item.id}`, removed: true };\n }\n\n case \"update_from_published\":\n return applyUpdateFromPublished(library, item, finding);\n\n case \"update_all_fields\":\n return applyUpdateAllFields(library, item, finding);\n\n // Placeholder for programmatic API (MCP/server) use.\n // Individual field selection is not available in interactive CLI mode,\n // but can be used via the MCP tool or HTTP server API.\n case \"update_selected_fields\":\n return { applied: false, message: \"Field selection not available in CLI mode\" };\n\n case \"skip\":\n return { applied: true, message: \"Skipped\" };\n\n default:\n return { applied: false, message: `Unknown action: ${actionType}` };\n }\n}\n","import { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport { restoreStdinAfterInk } from \"../interactive/alternate-screen.js\";\nimport { Select } from \"../interactive/components/index.js\";\nimport type { SelectOption } from \"../interactive/components/index.js\";\nimport { type FixActionType, applyFixAction, getFixActionsForFinding } from \"./fix-actions.js\";\nimport type { CheckFinding, CheckResult } from \"./types.js\";\n\nexport interface FixInteractionResult {\n totalFindings: number;\n applied: number;\n skipped: number;\n removed: string[];\n}\n\nfunction selectFixAction(\n message: string,\n options: SelectOption<FixActionType>[]\n): Promise<FixActionType | null> {\n return new Promise<FixActionType | null>((resolve) => {\n let selected: FixActionType | null = null;\n\n const { waitUntilExit } = render(\n createElement(Select<FixActionType>, {\n options,\n message,\n onSelect: (value: FixActionType) => {\n selected = value;\n },\n onCancel: () => {\n selected = null;\n },\n })\n );\n\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(selected);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve(null);\n });\n });\n}\n\nfunction getStatusLabel(type: string): string {\n switch (type) {\n case \"retracted\":\n return \"RETRACTED\";\n case \"concern\":\n return \"CONCERN\";\n case \"version_changed\":\n return \"VERSION\";\n case \"metadata_mismatch\":\n return \"MISMATCH\";\n case \"metadata_outdated\":\n return \"OUTDATED\";\n default:\n return \"WARNING\";\n }\n}\n\nfunction buildSelectOptions(finding: CheckFinding): SelectOption<FixActionType>[] {\n return getFixActionsForFinding(finding).map((a) => ({\n label: a.label,\n value: a.type,\n }));\n}\n\nasync function processFinding(\n result: FixInteractionResult,\n library: ILibrary,\n item: CslItem,\n resultId: string,\n finding: CheckFinding\n): Promise<void> {\n result.totalFindings++;\n const options = buildSelectOptions(finding);\n if (options.length === 0) return;\n\n const label = getStatusLabel(finding.type);\n const message = `[${label}] ${resultId}: ${finding.message}`;\n const selectedAction = await selectFixAction(message, options);\n\n if (selectedAction === null) {\n result.skipped++;\n return;\n }\n\n const actionResult = await applyFixAction(library, item, finding, selectedAction);\n\n if (!actionResult.applied) {\n process.stderr.write(` Error: ${actionResult.message}\\n`);\n return;\n }\n\n process.stderr.write(` ${actionResult.message}\\n`);\n if (selectedAction === \"skip\") {\n result.skipped++;\n } else {\n result.applied++;\n if (actionResult.removed) {\n result.removed.push(resultId);\n }\n }\n}\n\nexport async function runFixInteraction(\n results: CheckResult[],\n library: ILibrary,\n findItem: (id: string) => CslItem | undefined\n): Promise<FixInteractionResult> {\n const interactionResult: FixInteractionResult = {\n totalFindings: 0,\n applied: 0,\n skipped: 0,\n removed: [],\n };\n\n const warningResults = results.filter((r) => r.status === \"warning\");\n\n for (const checkResult of warningResults) {\n const item = findItem(checkResult.id);\n if (!item) continue;\n\n for (const finding of checkResult.findings) {\n await processFinding(interactionResult, library, item, checkResult.id, finding);\n }\n }\n\n return interactionResult;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fix-interaction-Ebrjh1H0.js","sources":["../../src/features/check/fix-actions.ts","../../src/features/check/fix-interaction.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport type { CheckFinding } from \"./types.js\";\n\nexport type FixActionType =\n | \"add_retracted_tag\"\n | \"add_retraction_note\"\n | \"remove_from_library\"\n | \"update_from_published\"\n | \"add_version_tag\"\n | \"add_concern_tag\"\n | \"add_concern_note\"\n | \"update_all_fields\"\n | \"update_selected_fields\"\n | \"skip\";\n\nexport interface FixAction {\n type: FixActionType;\n label: string;\n}\n\nexport interface FixActionResult {\n applied: boolean;\n message: string;\n removed?: boolean;\n}\n\nexport function getFixActionsForFinding(finding: CheckFinding): FixAction[] {\n switch (finding.type) {\n case \"retracted\":\n return [\n { type: \"add_retracted_tag\", label: 'Add tag \"retracted\"' },\n { type: \"add_retraction_note\", label: \"Add note with retraction details\" },\n { type: \"remove_from_library\", label: \"Remove from library\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"version_changed\":\n return [\n { type: \"update_from_published\", label: \"Update metadata from published version\" },\n { type: \"add_version_tag\", label: 'Add tag \"has-published-version\"' },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"concern\":\n return [\n { type: \"add_concern_tag\", label: 'Add tag \"expression-of-concern\"' },\n { type: \"add_concern_note\", label: \"Add note with concern details\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"metadata_mismatch\":\n case \"metadata_outdated\":\n return [\n { type: \"update_all_fields\", label: \"Update all changed fields from remote\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n default:\n return [];\n }\n}\n\nfunction addTag(item: CslItem, tag: string): string[] {\n const existing = (item.custom?.tags as string[] | undefined) ?? [];\n if (existing.includes(tag)) {\n return existing;\n }\n return [...existing, tag];\n}\n\nfunction buildNoteText(prefix: string, finding: CheckFinding): string {\n const parts = [prefix];\n if (finding.details?.retractionDate) {\n parts.push(`Date: ${finding.details.retractionDate}`);\n }\n if (finding.details?.retractionDoi) {\n parts.push(`DOI: ${finding.details.retractionDoi}`);\n }\n return parts.join(\". \");\n}\n\nfunction appendNote(existingNote: string | undefined, newNote: string): string {\n if (existingNote) {\n return `${existingNote}\\n\\n${newNote}`;\n }\n return newNote;\n}\n\nasync function applyTagAction(\n library: ILibrary,\n item: CslItem,\n tag: string\n): Promise<FixActionResult> {\n const tags = addTag(item, tag);\n await library.update(item.id, { custom: { ...item.custom, tags } } as Partial<CslItem>, {\n idType: \"id\",\n });\n await library.save();\n return { applied: true, message: `Added tag \"${tag}\"` };\n}\n\nasync function applyNoteAction(\n library: ILibrary,\n item: CslItem,\n prefix: string,\n finding: CheckFinding\n): Promise<FixActionResult> {\n const noteText = buildNoteText(prefix, finding);\n const note = appendNote(item.note, noteText);\n await library.update(item.id, { note } as Partial<CslItem>, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Added note: ${noteText}` };\n}\n\nasync function applyUpdateFromPublished(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding\n): Promise<FixActionResult> {\n const newDoi = finding.details?.newDoi;\n if (!newDoi) {\n return { applied: false, message: \"No published DOI available in finding details\" };\n }\n const { fetchDoi } = await import(\"../import/fetcher.js\");\n const fetchResult = await fetchDoi(newDoi);\n if (!fetchResult.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for ${newDoi}: ${fetchResult.error}`,\n };\n }\n const { id: _id, custom: _custom, ...metadata } = fetchResult.item;\n await library.update(item.id, metadata as Partial<CslItem>, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Updated metadata from ${newDoi}` };\n}\n\nasync function applyUpdateAllFields(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding\n): Promise<FixActionResult> {\n let fetchedItem: CslItem;\n\n if (item.DOI) {\n const { fetchDoi } = await import(\"../import/fetcher.js\");\n const fetchResult = await fetchDoi(item.DOI);\n if (!fetchResult.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for DOI ${item.DOI}: ${fetchResult.error}`,\n };\n }\n fetchedItem = fetchResult.item;\n } else if (item.PMID) {\n const { fetchPmids } = await import(\"../import/fetcher.js\");\n const results = await fetchPmids([item.PMID], {});\n const result = results[0];\n if (!result || !result.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for PMID ${item.PMID}: ${result?.error ?? \"unknown error\"}`,\n };\n }\n fetchedItem = result.item;\n } else {\n return { applied: false, message: \"No DOI or PMID available for metadata update\" };\n }\n\n const updatedFields = finding.details?.updatedFields ?? [];\n const updates: Partial<CslItem> = {};\n for (const field of updatedFields) {\n if (field in fetchedItem) {\n (updates as Record<string, unknown>)[field] = (fetchedItem as Record<string, unknown>)[field];\n }\n }\n if (Object.keys(updates).length === 0) {\n return { applied: false, message: \"No fields to update\" };\n }\n await library.update(item.id, updates, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Updated fields: ${updatedFields.join(\", \")}` };\n}\n\nexport async function applyFixAction(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding,\n actionType: FixActionType\n): Promise<FixActionResult> {\n switch (actionType) {\n case \"add_retracted_tag\":\n return applyTagAction(library, item, \"retracted\");\n\n case \"add_retraction_note\":\n return applyNoteAction(library, item, \"RETRACTED\", finding);\n\n case \"add_concern_tag\":\n return applyTagAction(library, item, \"expression-of-concern\");\n\n case \"add_concern_note\":\n return applyNoteAction(library, item, \"EXPRESSION OF CONCERN\", finding);\n\n case \"add_version_tag\":\n return applyTagAction(library, item, \"has-published-version\");\n\n case \"remove_from_library\": {\n const removeResult = await library.remove(item.id, { idType: \"id\" });\n if (!removeResult.removed) {\n return { applied: false, message: `Failed to remove ${item.id}` };\n }\n await library.save();\n return { applied: true, message: `Removed ${item.id}`, removed: true };\n }\n\n case \"update_from_published\":\n return applyUpdateFromPublished(library, item, finding);\n\n case \"update_all_fields\":\n return applyUpdateAllFields(library, item, finding);\n\n // Placeholder for programmatic API (MCP/server) use.\n // Individual field selection is not available in interactive CLI mode,\n // but can be used via the MCP tool or HTTP server API.\n case \"update_selected_fields\":\n return { applied: false, message: \"Field selection not available in CLI mode\" };\n\n case \"skip\":\n return { applied: true, message: \"Skipped\" };\n\n default:\n return { applied: false, message: `Unknown action: ${actionType}` };\n }\n}\n","import { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport { restoreStdinAfterInk } from \"../interactive/alternate-screen.js\";\nimport { Select } from \"../interactive/components/index.js\";\nimport type { SelectOption } from \"../interactive/components/index.js\";\nimport { type FixActionType, applyFixAction, getFixActionsForFinding } from \"./fix-actions.js\";\nimport type { CheckFinding, CheckResult } from \"./types.js\";\n\nexport interface FixInteractionResult {\n totalFindings: number;\n applied: number;\n skipped: number;\n removed: string[];\n}\n\nfunction selectFixAction(\n message: string,\n options: SelectOption<FixActionType>[]\n): Promise<FixActionType | null> {\n return new Promise<FixActionType | null>((resolve) => {\n let selected: FixActionType | null = null;\n\n const { waitUntilExit } = render(\n createElement(Select<FixActionType>, {\n options,\n message,\n onSelect: (value: FixActionType) => {\n selected = value;\n },\n onCancel: () => {\n selected = null;\n },\n })\n );\n\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(selected);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve(null);\n });\n });\n}\n\nfunction getStatusLabel(type: string): string {\n switch (type) {\n case \"retracted\":\n return \"RETRACTED\";\n case \"concern\":\n return \"CONCERN\";\n case \"version_changed\":\n return \"VERSION\";\n case \"metadata_mismatch\":\n return \"MISMATCH\";\n case \"metadata_outdated\":\n return \"OUTDATED\";\n default:\n return \"WARNING\";\n }\n}\n\nfunction buildSelectOptions(finding: CheckFinding): SelectOption<FixActionType>[] {\n return getFixActionsForFinding(finding).map((a) => ({\n label: a.label,\n value: a.type,\n }));\n}\n\nasync function processFinding(\n result: FixInteractionResult,\n library: ILibrary,\n item: CslItem,\n resultId: string,\n finding: CheckFinding\n): Promise<void> {\n result.totalFindings++;\n const options = buildSelectOptions(finding);\n if (options.length === 0) return;\n\n const label = getStatusLabel(finding.type);\n const message = `[${label}] ${resultId}: ${finding.message}`;\n const selectedAction = await selectFixAction(message, options);\n\n if (selectedAction === null) {\n result.skipped++;\n return;\n }\n\n const actionResult = await applyFixAction(library, item, finding, selectedAction);\n\n if (!actionResult.applied) {\n process.stderr.write(` Error: ${actionResult.message}\\n`);\n return;\n }\n\n process.stderr.write(` ${actionResult.message}\\n`);\n if (selectedAction === \"skip\") {\n result.skipped++;\n } else {\n result.applied++;\n if (actionResult.removed) {\n result.removed.push(resultId);\n }\n }\n}\n\nexport async function runFixInteraction(\n results: CheckResult[],\n library: ILibrary,\n findItem: (id: string) => CslItem | undefined\n): Promise<FixInteractionResult> {\n const interactionResult: FixInteractionResult = {\n totalFindings: 0,\n applied: 0,\n skipped: 0,\n removed: [],\n };\n\n const warningResults = results.filter((r) => r.status === \"warning\");\n\n for (const checkResult of warningResults) {\n const item = findItem(checkResult.id);\n if (!item) continue;\n\n for (const finding of checkResult.findings) {\n await processFinding(interactionResult, library, item, checkResult.id, finding);\n }\n }\n\n return interactionResult;\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Command, Option } from "commander";
2
- import { n as normalizePathForOutput, d as deleteDirectoryIfEmpty, p as parseFilename, i as isReservedRole, e as ensureDirectory, a as addAttachment, R as RESERVED_ROLES, b as generateFilename, c as findFulltextFiles, h as findFulltextFile, j as extensionToFormat, k as fulltextAttach, l as fulltextDiscover, m as fulltextFetch, o as fulltextConvert, q as fulltextGet, r as getExtension, s as getDefaultExportFromCjs, B as BUILTIN_STYLES, t as packageJson, u as getFulltextAttachmentTypes, v as startServerWithFileWatcher, w as BUILTIN_CONVERTER_NAMES, x as BUILTIN_CONVERTER_INFO } from "./index-a52FHX03.js";
2
+ import { n as normalizePathForOutput, d as deleteDirectoryIfEmpty, p as parseFilename, i as isReservedRole, e as ensureDirectory, a as addAttachment, R as RESERVED_ROLES, b as generateFilename, c as findFulltextFiles, h as findFulltextFile, j as extensionToFormat, k as fulltextAttach, l as fulltextDiscover, m as fulltextFetch, o as fulltextConvert, q as fulltextGet, r as getExtension, s as getDefaultExportFromCjs, B as BUILTIN_STYLES, t as packageJson, u as getFulltextAttachmentTypes, v as startServerWithFileWatcher, w as BUILTIN_CONVERTER_NAMES, x as BUILTIN_CONVERTER_INFO } from "./index-CA7km4m0.js";
3
3
  import { i as isEqual, M as MANAGED_CUSTOM_FIELDS, w as writeFileAtomic, L as Library, h as CslItemSchema, p as pickDefined, a as sortOrderSchema, z as paginationOptionsSchema, F as FileWatcher, b as sortFieldSchema, y as searchSortFieldSchema } from "./file-watcher-CWHg1yol.js";
4
4
  import * as fs from "node:fs";
5
5
  import { promises, readFileSync, existsSync, mkdirSync, writeFileSync, lstatSync, unlinkSync, rmSync, symlinkSync } from "node:fs";
@@ -915,15 +915,15 @@ class OperationsLibrary {
915
915
  }
916
916
  // High-level operations
917
917
  async search(options) {
918
- const { searchReferences } = await import("./index-a52FHX03.js").then((n) => n.H);
918
+ const { searchReferences } = await import("./index-CA7km4m0.js").then((n) => n.H);
919
919
  return searchReferences(this.library, options);
920
920
  }
921
921
  async list(options) {
922
- const { listReferences } = await import("./index-a52FHX03.js").then((n) => n.G);
922
+ const { listReferences } = await import("./index-CA7km4m0.js").then((n) => n.G);
923
923
  return listReferences(this.library, options ?? {});
924
924
  }
925
925
  async cite(options) {
926
- const { citeReferences } = await import("./index-a52FHX03.js").then((n) => n.F);
926
+ const { citeReferences } = await import("./index-CA7km4m0.js").then((n) => n.F);
927
927
  const defaultStyle = options.defaultStyle ?? this.citationConfig?.defaultStyle;
928
928
  const cslDirectory = options.cslDirectory ?? this.citationConfig?.cslDirectory;
929
929
  const mergedOptions = {
@@ -934,36 +934,36 @@ class OperationsLibrary {
934
934
  return citeReferences(this.library, mergedOptions);
935
935
  }
936
936
  async import(inputs, options) {
937
- const { addReferences } = await import("./index-a52FHX03.js").then((n) => n.D);
937
+ const { addReferences } = await import("./index-CA7km4m0.js").then((n) => n.D);
938
938
  return addReferences(inputs, this.library, options ?? {});
939
939
  }
940
940
  async check(options) {
941
- const { checkReferences } = await import("./index-a52FHX03.js").then((n) => n.E);
941
+ const { checkReferences } = await import("./index-CA7km4m0.js").then((n) => n.E);
942
942
  return checkReferences(this.library, options);
943
943
  }
944
944
  // Attachment operations
945
945
  async attachAdd(options) {
946
- const { addAttachment: addAttachment2 } = await import("./index-DpZ-Ma7M.js");
946
+ const { addAttachment: addAttachment2 } = await import("./index-QxdPt5c9.js");
947
947
  return addAttachment2(this.library, options);
948
948
  }
949
949
  async attachList(options) {
950
- const { listAttachments: listAttachments2 } = await import("./index-DpZ-Ma7M.js");
950
+ const { listAttachments: listAttachments2 } = await import("./index-QxdPt5c9.js");
951
951
  return listAttachments2(this.library, options);
952
952
  }
953
953
  async attachGet(options) {
954
- const { getAttachment: getAttachment2 } = await import("./index-DpZ-Ma7M.js");
954
+ const { getAttachment: getAttachment2 } = await import("./index-QxdPt5c9.js");
955
955
  return getAttachment2(this.library, options);
956
956
  }
957
957
  async attachDetach(options) {
958
- const { detachAttachment: detachAttachment2 } = await import("./index-DpZ-Ma7M.js");
958
+ const { detachAttachment: detachAttachment2 } = await import("./index-QxdPt5c9.js");
959
959
  return detachAttachment2(this.library, options);
960
960
  }
961
961
  async attachSync(options) {
962
- const { syncAttachments: syncAttachments2 } = await import("./index-DpZ-Ma7M.js");
962
+ const { syncAttachments: syncAttachments2 } = await import("./index-QxdPt5c9.js");
963
963
  return syncAttachments2(this.library, options);
964
964
  }
965
965
  async attachOpen(options) {
966
- const { openAttachment: openAttachment2 } = await import("./index-DpZ-Ma7M.js");
966
+ const { openAttachment: openAttachment2 } = await import("./index-QxdPt5c9.js");
967
967
  return openAttachment2(this.library, options);
968
968
  }
969
969
  }
@@ -1828,7 +1828,7 @@ function getAttachExitCode(result) {
1828
1828
  }
1829
1829
  async function executeInteractiveSelect$3(context, config2) {
1830
1830
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
1831
- const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
1831
+ const { selectReferencesOrExit } = await import("./reference-select-CsXBOR8g.js");
1832
1832
  const allReferences = await context.library.getAll();
1833
1833
  const identifiers = await withAlternateScreen2(
1834
1834
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -2493,7 +2493,7 @@ async function handleCheckAction(identifiers, options, globalOpts) {
2493
2493
  const jsonOptions = buildJsonOptionsFromRefs(options, outputFormat, result, allRefs);
2494
2494
  outputCheckResult(result, outputFormat, jsonOptions);
2495
2495
  if (options.fix && result.summary.warnings > 0 && allRefs) {
2496
- const { runFixInteraction } = await import("./fix-interaction-D_zhtL9k.js");
2496
+ const { runFixInteraction } = await import("./fix-interaction-Ebrjh1H0.js");
2497
2497
  const findItem = (id2) => allRefs.find((item) => item.id === id2);
2498
2498
  const fixResult = await runFixInteraction(result.results, context.library, findItem);
2499
2499
  const removedSuffix = fixResult.removed.length > 0 ? `, ${fixResult.removed.length} removed` : "";
@@ -2561,7 +2561,7 @@ function outputCheckError(error, format2) {
2561
2561
  }
2562
2562
  async function selectReferencesInteractively(context, config2) {
2563
2563
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
2564
- const { selectReferenceItemsOrExit } = await import("./reference-select-aEB3-5rp.js");
2564
+ const { selectReferenceItemsOrExit } = await import("./reference-select-CsXBOR8g.js");
2565
2565
  const allReferences = await context.library.getAll();
2566
2566
  if (allReferences.length === 0) {
2567
2567
  process.stderr.write("No references in library.\n");
@@ -2629,8 +2629,8 @@ function getCiteExitCode(result) {
2629
2629
  }
2630
2630
  async function executeInteractiveCite(options, context, config2) {
2631
2631
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
2632
- const { runCiteFlow } = await import("./index-DMShdNwY.js");
2633
- const { buildStyleChoices, listCustomStyles } = await import("./style-select-CQ4BBBZJ.js");
2632
+ const { runCiteFlow } = await import("./index-BrfxHfSZ.js");
2633
+ const { buildStyleChoices, listCustomStyles } = await import("./style-select-Bo9u9rtE.js");
2634
2634
  const { search } = await import("./file-watcher-CWHg1yol.js").then((n) => n.B);
2635
2635
  const { tokenize } = await import("./file-watcher-CWHg1yol.js").then((n) => n.A);
2636
2636
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
@@ -7322,7 +7322,7 @@ function formatEditOutput(result) {
7322
7322
  }
7323
7323
  async function executeInteractiveEdit(options, context, config2) {
7324
7324
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
7325
- const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
7325
+ const { selectReferencesOrExit } = await import("./reference-select-CsXBOR8g.js");
7326
7326
  const allReferences = await context.library.getAll();
7327
7327
  const identifiers = await withAlternateScreen2(
7328
7328
  () => selectReferencesOrExit(allReferences, { multiSelect: true }, config2.cli.tui)
@@ -10898,7 +10898,7 @@ function getFulltextExitCode(result) {
10898
10898
  }
10899
10899
  async function executeInteractiveSelect$2(context, config2, multiSelect = false) {
10900
10900
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
10901
- const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
10901
+ const { selectReferencesOrExit } = await import("./reference-select-CsXBOR8g.js");
10902
10902
  const allReferences = await context.library.getAll();
10903
10903
  const identifiers = await withAlternateScreen2(
10904
10904
  () => selectReferencesOrExit(allReferences, { multiSelect }, config2.cli.tui)
@@ -32555,7 +32555,7 @@ async function mcpStart(options) {
32555
32555
  async function executeRemove(options, context) {
32556
32556
  const { identifier, idType = "id", fulltextDirectory, deleteFulltext = false } = options;
32557
32557
  if (context.mode === "local" && deleteFulltext && fulltextDirectory) {
32558
- const { removeReference } = await import("./index-a52FHX03.js").then((n) => n.A);
32558
+ const { removeReference } = await import("./index-CA7km4m0.js").then((n) => n.A);
32559
32559
  return removeReference(context.library, {
32560
32560
  identifier,
32561
32561
  idType,
@@ -32610,7 +32610,7 @@ Continue?`;
32610
32610
  }
32611
32611
  async function executeInteractiveRemove(context, config2) {
32612
32612
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
32613
- const { selectReferenceItemsOrExit } = await import("./reference-select-aEB3-5rp.js");
32613
+ const { selectReferenceItemsOrExit } = await import("./reference-select-CsXBOR8g.js");
32614
32614
  const allReferences = await context.library.getAll();
32615
32615
  const selectedItems = await withAlternateScreen2(
32616
32616
  () => selectReferenceItemsOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -32835,7 +32835,7 @@ async function executeInteractiveSearch(options, context, config2) {
32835
32835
  validateInteractiveOptions(options);
32836
32836
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
32837
32837
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
32838
- const { runSearchFlow } = await import("./index-DMShdNwY.js");
32838
+ const { runSearchFlow } = await import("./index-BrfxHfSZ.js");
32839
32839
  const { search } = await import("./file-watcher-CWHg1yol.js").then((n) => n.B);
32840
32840
  const { tokenize } = await import("./file-watcher-CWHg1yol.js").then((n) => n.A);
32841
32841
  checkTTY();
@@ -32854,7 +32854,7 @@ async function executeInteractiveSearch(options, context, config2) {
32854
32854
  })
32855
32855
  );
32856
32856
  if (result.selectedItems && !result.cancelled) {
32857
- const { isSideEffectAction } = await import("./action-menu-i1v02Qig.js");
32857
+ const { isSideEffectAction } = await import("./action-menu-BWSeIIPB.js");
32858
32858
  if (isSideEffectAction(result.action)) {
32859
32859
  await executeSideEffectAction(result.action, result.selectedItems, context, config2);
32860
32860
  return { output: "", cancelled: false, action: result.action };
@@ -33152,7 +33152,7 @@ function formatShowOutput(item, options, attachmentsDirectory) {
33152
33152
  }
33153
33153
  async function executeInteractiveSelect$1(context, config2) {
33154
33154
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
33155
- const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
33155
+ const { selectReferencesOrExit } = await import("./reference-select-CsXBOR8g.js");
33156
33156
  const allReferences = await context.library.getAll();
33157
33157
  const identifiers = await withAlternateScreen2(
33158
33158
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -33401,7 +33401,7 @@ function formatUpdateOutput(result, identifier) {
33401
33401
  }
33402
33402
  async function executeInteractiveUpdate(context, config2) {
33403
33403
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
33404
- const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
33404
+ const { selectReferencesOrExit } = await import("./reference-select-CsXBOR8g.js");
33405
33405
  const allReferences = await context.library.getAll();
33406
33406
  const identifiers = await withAlternateScreen2(
33407
33407
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -33696,7 +33696,7 @@ function getUrlExitCode(result) {
33696
33696
  }
33697
33697
  async function executeInteractiveSelect(context, config2) {
33698
33698
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
33699
- const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
33699
+ const { selectReferencesOrExit } = await import("./reference-select-CsXBOR8g.js");
33700
33700
  const allReferences = await context.library.getAll();
33701
33701
  const identifiers = await withAlternateScreen2(
33702
33702
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -34317,7 +34317,7 @@ function shouldAutoFetch(cliFlag, configEnabled) {
34317
34317
  return configEnabled;
34318
34318
  }
34319
34319
  async function performAutoFetch(addedItems, context, config2) {
34320
- const { fulltextFetch: fulltextFetch2 } = await import("./index-a52FHX03.js").then((n) => n.z);
34320
+ const { fulltextFetch: fulltextFetch2 } = await import("./index-CA7km4m0.js").then((n) => n.z);
34321
34321
  const fetchResults = await autoFetchFulltext(addedItems, context, {
34322
34322
  fulltextConfig: config2.fulltext,
34323
34323
  fulltextDirectory: config2.attachments.directory,
@@ -34636,4 +34636,4 @@ export {
34636
34636
  restoreStdinAfterInk as r,
34637
34637
  syncAttachments as s
34638
34638
  };
34639
- //# sourceMappingURL=index-PkCQJBdt.js.map
34639
+ //# sourceMappingURL=index-Bm25py-B.js.map