@ncukondo/reference-manager 0.22.3 → 0.23.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.
- package/dist/chunks/{action-menu-CKMhb5fv.js → action-menu-C0-X1ndf.js} +3 -3
- package/dist/chunks/{action-menu-CKMhb5fv.js.map → action-menu-C0-X1ndf.js.map} +1 -1
- package/dist/chunks/{format-B2MDhuHt.js → format-CBbnqK3-.js} +2 -2
- package/dist/chunks/{format-B2MDhuHt.js.map → format-CBbnqK3-.js.map} +1 -1
- package/dist/chunks/{index-DjQiOVp_.js → index-BSWbcT3c.js} +4 -4
- package/dist/chunks/{index-DjQiOVp_.js.map → index-BSWbcT3c.js.map} +1 -1
- package/dist/chunks/{index-4607sQqe.js → index-BVDVqLTl.js} +3 -3
- package/dist/chunks/index-BVDVqLTl.js.map +1 -0
- package/dist/chunks/{index-CYp8N4gu.js → index-BrETQT0g.js} +43 -32
- package/dist/chunks/index-BrETQT0g.js.map +1 -0
- package/dist/chunks/index-eZatWPDi.js +12525 -0
- package/dist/chunks/index-eZatWPDi.js.map +1 -0
- package/dist/chunks/{loader-CJB3-kI5.js → loader-CzviN_sy.js} +25 -5
- package/dist/chunks/loader-CzviN_sy.js.map +1 -0
- package/dist/chunks/{reference-select-dvLqdttM.js → reference-select-CogjIATu.js} +3 -3
- package/dist/chunks/{reference-select-dvLqdttM.js.map → reference-select-CogjIATu.js.map} +1 -1
- package/dist/chunks/{style-select-BpKQvCBz.js → style-select-CJzZczSq.js} +3 -3
- package/dist/chunks/{style-select-BpKQvCBz.js.map → style-select-CJzZczSq.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/env-override.d.ts.map +1 -1
- package/dist/config/key-parser.d.ts.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/schema.d.ts +8 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/features/operations/fulltext/discover.d.ts +5 -0
- package/dist/features/operations/fulltext/discover.d.ts.map +1 -1
- package/dist/features/operations/fulltext/fetch.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunks/index-4607sQqe.js.map +0 -1
- package/dist/chunks/index-CNr_FIip.js +0 -5945
- package/dist/chunks/index-CNr_FIip.js.map +0 -1
- package/dist/chunks/index-CYp8N4gu.js.map +0 -1
- package/dist/chunks/loader-CJB3-kI5.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DjQiOVp_.js","sources":["../../src/features/interactive/apps/SearchFlowApp.tsx","../../src/features/interactive/apps/runSearchFlow.ts","../../src/features/interactive/apps/CiteFlowApp.tsx","../../src/features/interactive/apps/runCiteFlow.ts"],"sourcesContent":["/**\n * SearchFlowApp - Single App for search -t flow\n *\n * Manages state transitions: search → action → (style/output-format if needed)\n * Following React Ink Single App Pattern (ADR-015)\n */\n\nimport { Box, useApp } from \"ink\";\nimport type React from \"react\";\nimport { createElement, useEffect, useState } from \"react\";\nimport type { CitationKeyFormat } from \"../../../config/schema.js\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport {\n type ActionMenuResult,\n type ActionType,\n OUTPUT_FORMAT_CHOICES,\n type OutputFormatType,\n STYLE_CHOICES,\n generateOutput,\n getActionChoices,\n isSideEffectAction,\n} from \"../action-menu.js\";\nimport {\n type Choice,\n SearchableMultiSelect,\n Select,\n type SortOption,\n} from \"../components/index.js\";\n\n/**\n * Flow states for the search flow\n */\ntype FlowState = \"search\" | \"action\" | \"style\" | \"output-format\" | \"exiting\";\n\n/**\n * Props for SearchFlowApp\n */\nexport interface SearchFlowAppProps {\n /** Choices for the search prompt */\n choices: Choice<CslItem>[];\n /** Filter function for search */\n filterFn: (query: string, choices: Choice<CslItem>[]) => Choice<CslItem>[];\n /** Number of visible items */\n visibleCount: number;\n /** Default sort option */\n defaultSort: SortOption;\n /** Default citation key format */\n defaultKeyFormat: CitationKeyFormat;\n /** Default citation style */\n defaultStyle: string;\n /** Debounce delay in milliseconds for search filtering */\n debounceMs?: number;\n /** Callback when flow completes */\n onComplete: (result: ActionMenuResult) => void;\n /** Callback when flow is cancelled */\n onCancel: () => void;\n}\n\n/**\n * SearchFlowApp component\n *\n * Single App that manages search → action → style/output-format flow\n */\nexport function SearchFlowApp({\n choices,\n filterFn,\n visibleCount,\n defaultSort,\n defaultKeyFormat,\n defaultStyle,\n debounceMs,\n onComplete,\n onCancel,\n}: SearchFlowAppProps): React.ReactElement {\n const { exit } = useApp();\n const [state, setState] = useState<FlowState>(\"search\");\n const [selectedItems, setSelectedItems] = useState<CslItem[]>([]);\n const [pendingResult, setPendingResult] = useState<ActionMenuResult | null>(null);\n\n // Exit when entering \"exiting\" state (after rendering empty component)\n useEffect(() => {\n if (state === \"exiting\" && pendingResult) {\n exit();\n if (pendingResult.cancelled) {\n onCancel();\n } else {\n onComplete(pendingResult);\n }\n }\n }, [state, pendingResult, exit, onCancel, onComplete]);\n\n // Transition to exiting state with result\n const exitWith = (result: ActionMenuResult) => {\n setPendingResult(result);\n setState(\"exiting\");\n };\n\n // Handle search submission\n const handleSearchSubmit = (selected: Choice<CslItem>[]) => {\n if (selected.length === 0) {\n exitWith({ action: \"cancel\", output: \"\", cancelled: true });\n return;\n }\n setSelectedItems(selected.map((c) => c.value));\n setState(\"action\");\n };\n\n // Handle search cancel\n const handleSearchCancel = () => {\n exitWith({ action: \"cancel\", output: \"\", cancelled: true });\n };\n\n // Handle action selection\n const handleActionSelect = (action: ActionType) => {\n if (action === \"cancel\") {\n exitWith({ action: \"cancel\", output: \"\", cancelled: true });\n return;\n }\n\n // If cite-choose, go to style selection\n if (action === \"cite-choose\") {\n setState(\"style\");\n return;\n }\n\n // If output-format, go to output format submenu\n if (action === \"output-format\") {\n setState(\"output-format\");\n return;\n }\n\n // Handle side-effect actions\n if (isSideEffectAction(action)) {\n exitWith({ action, output: \"\", cancelled: false, selectedItems });\n return;\n }\n\n // Generate output and complete\n const output = generateOutput(action, selectedItems, {\n defaultKeyFormat,\n defaultStyle,\n });\n exitWith({ action, output, cancelled: false });\n };\n\n // Handle action cancel (go back to search)\n const handleActionCancel = () => {\n setState(\"search\");\n };\n\n // Handle style selection\n const handleStyleSelect = (style: string) => {\n const output = generateOutput(\"cite-choose\", selectedItems, {\n defaultKeyFormat,\n defaultStyle: style,\n });\n exitWith({ action: \"cite-choose\", output, cancelled: false });\n };\n\n // Handle style cancel (go back to action)\n const handleStyleCancel = () => {\n setState(\"action\");\n };\n\n // Handle output format selection\n const handleOutputFormatSelect = (format: OutputFormatType) => {\n if (format === \"cancel\") {\n setState(\"action\");\n return;\n }\n\n const output = generateOutput(format, selectedItems, {\n defaultKeyFormat,\n defaultStyle,\n });\n exitWith({ action: \"output-format\", output, cancelled: false });\n };\n\n // Handle output format cancel (go back to action)\n const handleOutputFormatCancel = () => {\n setState(\"action\");\n };\n\n // Render based on current state\n if (state === \"exiting\") {\n // Empty component - Ink will clear the previous content\n return createElement(Box);\n }\n\n if (state === \"search\") {\n return createElement(SearchableMultiSelect<CslItem>, {\n choices,\n filterFn,\n visibleCount,\n onSubmit: handleSearchSubmit,\n onCancel: handleSearchCancel,\n header: \"Search references\",\n placeholder: \"Type to search...\",\n defaultSort,\n ...(debounceMs !== undefined && { debounceMs }),\n });\n }\n\n if (state === \"action\") {\n const count = selectedItems.length;\n const refWord = count === 1 ? \"reference\" : \"references\";\n return createElement(Select<ActionType>, {\n key: \"action\",\n options: getActionChoices(count, { defaultKeyFormat }),\n message: `Action for ${count} selected ${refWord}:`,\n onSelect: handleActionSelect,\n onCancel: handleActionCancel,\n });\n }\n\n if (state === \"output-format\") {\n return createElement(Select<OutputFormatType>, {\n key: \"output-format\",\n options: OUTPUT_FORMAT_CHOICES,\n message: \"Select output format:\",\n onSelect: handleOutputFormatSelect,\n onCancel: handleOutputFormatCancel,\n });\n }\n\n // state === \"style\"\n return createElement(Select<string>, {\n key: \"style\",\n options: STYLE_CHOICES,\n message: \"Select citation style:\",\n onSelect: handleStyleSelect,\n onCancel: handleStyleCancel,\n });\n}\n","/**\n * Runner for SearchFlowApp\n *\n * Provides the public API for running the search flow.\n */\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CitationKeyFormat } from \"../../../config/schema.js\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport { buildResourceIndicators } from \"../../format/resource-indicators.js\";\nimport type { SearchResult } from \"../../search/types.js\";\nimport type { ActionMenuResult } from \"../action-menu.js\";\nimport { restoreStdinAfterInk } from \"../alternate-screen.js\";\nimport { type Choice, type SortOption, calculateEffectiveLimit } from \"../components/index.js\";\nimport { formatAuthors } from \"../format.js\";\nimport { SearchFlowApp } from \"./SearchFlowApp.js\";\n\n/**\n * Configuration for the search flow\n */\nexport interface SearchFlowConfig {\n /** Maximum number of results to display */\n limit: number;\n /** Debounce delay in milliseconds for search filtering */\n debounceMs: number;\n /** Default citation key format */\n defaultKeyFormat?: CitationKeyFormat;\n /** Default citation style */\n defaultStyle?: string;\n}\n\n/**\n * Search function type for filtering references\n */\nexport type SearchFunction = (query: string) => SearchResult[];\n\n/**\n * Extract year from CSL item\n */\nfunction extractYear(item: CslItem): number | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n return firstDatePart[0];\n}\n\n/**\n * Extract published date from CSL item\n */\nfunction extractPublishedDate(item: CslItem): Date | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n const [year, month = 1, day = 1] = firstDatePart;\n if (year === undefined) return undefined;\n return new Date(year, month - 1, day);\n}\n\n/**\n * Extract updated date from CSL item (from custom.timestamp)\n */\nfunction extractUpdatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.timestamp;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Extract created date from CSL item (from custom.created_at)\n */\nfunction extractCreatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.created_at;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Format identifiers for meta line\n */\nfunction formatIdentifiers(item: CslItem): string {\n const parts: string[] = [];\n if (item.DOI) parts.push(`DOI: ${item.DOI}`);\n if (item.PMID) parts.push(`PMID: ${item.PMID}`);\n if (item.PMCID) parts.push(`PMCID: ${item.PMCID}`);\n if (item.ISBN) parts.push(`ISBN: ${item.ISBN}`);\n return parts.join(\" · \");\n}\n\n/**\n * Format item type for display\n */\nfunction formatType(type: string): string {\n const typeMap: Record<string, string> = {\n \"article-journal\": \"Journal article\",\n \"article-magazine\": \"Magazine article\",\n \"article-newspaper\": \"Newspaper article\",\n book: \"Book\",\n chapter: \"Book chapter\",\n \"paper-conference\": \"Conference paper\",\n thesis: \"Thesis\",\n report: \"Report\",\n webpage: \"Web page\",\n };\n return typeMap[type] ?? type;\n}\n\n/**\n * Convert CslItem to Choice for SearchableMultiSelect\n */\nexport function toChoice(item: CslItem): Choice<CslItem> {\n const authors = formatAuthors(item.author);\n const year = extractYear(item);\n const identifiers = formatIdentifiers(item);\n const itemType = formatType(item.type);\n\n // Build meta line: Year · Type · Identifiers\n const metaParts: string[] = [];\n if (year) metaParts.push(String(year));\n metaParts.push(itemType);\n if (identifiers) metaParts.push(identifiers);\n\n const updatedDate = extractUpdatedDate(item);\n const createdDate = extractCreatedDate(item);\n const publishedDate = extractPublishedDate(item);\n\n // Prepend resource indicators to meta if present\n const indicators = buildResourceIndicators(item);\n const metaStr = metaParts.join(\" · \");\n const meta = indicators ? `${indicators} ${metaStr}` : metaStr;\n\n return {\n id: item.id,\n title: item.title ?? \"(No title)\",\n subtitle: authors || \"(No authors)\",\n meta,\n value: item,\n ...(updatedDate && { updatedDate }),\n ...(createdDate && { createdDate }),\n ...(publishedDate && { publishedDate }),\n };\n}\n\n/**\n * Run the search flow (search → action → style if needed)\n *\n * This is the main entry point for the `search -t` command.\n */\nexport async function runSearchFlow(\n allReferences: CslItem[],\n searchFn: SearchFunction,\n config: SearchFlowConfig\n): Promise<ActionMenuResult> {\n // Convert references to choices and build lookup map\n const choices = allReferences.map(toChoice);\n const choiceMap = new Map(choices.map((c) => [c.id, c]));\n\n // Calculate effective visible count\n const effectiveLimit = calculateEffectiveLimit(config.limit);\n\n // Create filter function using the provided search function\n const filterFn = (query: string, choices: Choice<CslItem>[]): Choice<CslItem>[] => {\n if (!query.trim()) return choices;\n\n const results = searchFn(query);\n return results.flatMap((r) => {\n const choice = choiceMap.get(r.reference.id);\n return choice ? [choice] : [];\n });\n };\n\n // Default sort option\n const defaultSort: SortOption = \"updated-desc\";\n\n // Create a promise to capture the result\n return new Promise<ActionMenuResult>((resolve) => {\n let flowResult: ActionMenuResult = {\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n };\n\n const handleComplete = (result: ActionMenuResult): void => {\n flowResult = result;\n };\n\n const handleCancel = (): void => {\n flowResult = {\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n };\n };\n\n // Render the Ink app (single render for entire flow)\n const { waitUntilExit } = render(\n createElement(SearchFlowApp, {\n choices,\n filterFn,\n visibleCount: effectiveLimit,\n defaultSort,\n defaultKeyFormat: config.defaultKeyFormat ?? \"pandoc\",\n defaultStyle: config.defaultStyle ?? \"apa\",\n debounceMs: config.debounceMs,\n onComplete: handleComplete,\n onCancel: handleCancel,\n })\n );\n\n // Wait for the app to exit, then resolve\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(flowResult);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve({\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n });\n });\n });\n}\n","/**\n * CiteFlowApp - Single App for cite command flow\n *\n * Implements the Single App Pattern (ADR-015) for the cite command.\n * Manages state transitions: reference selection → style selection → exiting\n */\n\nimport { Box, useApp } from \"ink\";\nimport type React from \"react\";\nimport { createElement, useEffect, useState } from \"react\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport { SearchableMultiSelect } from \"../components/SearchableMultiSelect.js\";\nimport { Select, type SelectOption } from \"../components/Select.js\";\nimport type { Choice, SortOption } from \"../components/index.js\";\n\n// Flow states\ntype FlowState = \"search\" | \"style\" | \"exiting\";\n\n/**\n * Result from the cite flow\n */\nexport interface CiteFlowResult {\n /** Selected reference IDs */\n identifiers: string[];\n /** Selected style (if style selection was shown) */\n style?: string;\n /** Whether the flow was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Props for CiteFlowApp\n */\nexport interface CiteFlowAppProps {\n /** All reference choices */\n choices: Choice<CslItem>[];\n /** Filter function for search */\n filterFn: (query: string, choices: Choice<CslItem>[]) => Choice<CslItem>[];\n /** Number of visible items */\n visibleCount: number;\n /** Default sort option */\n defaultSort: SortOption;\n /** Style options for style selection */\n styleOptions: SelectOption<string>[];\n /** Whether to show style selection (false if style already specified) */\n showStyleSelect: boolean;\n /** Callback when flow completes */\n onComplete: (result: CiteFlowResult) => void;\n /** Callback when flow is cancelled */\n onCancel: () => void;\n}\n\n/**\n * CiteFlowApp component\n *\n * Single Ink app that handles the entire cite flow:\n * 1. Reference selection (SearchableMultiSelect)\n * 2. Style selection (Select) - optional\n * 3. Exit\n */\nexport function CiteFlowApp({\n choices,\n filterFn,\n visibleCount,\n defaultSort,\n styleOptions,\n showStyleSelect,\n onComplete,\n onCancel,\n}: CiteFlowAppProps): React.ReactElement {\n const { exit } = useApp();\n const [state, setState] = useState<FlowState>(\"search\");\n const [selectedItems, setSelectedItems] = useState<CslItem[]>([]);\n const [pendingResult, setPendingResult] = useState<CiteFlowResult | null>(null);\n\n // Exit when entering \"exiting\" state\n useEffect(() => {\n if (state === \"exiting\" && pendingResult) {\n exit();\n if (pendingResult.cancelled) {\n onCancel();\n } else {\n onComplete(pendingResult);\n }\n }\n }, [state, pendingResult, exit, onCancel, onComplete]);\n\n // Transition to exiting state with result\n const exitWith = (result: CiteFlowResult) => {\n setPendingResult(result);\n setState(\"exiting\");\n };\n\n // Handle search submission\n const handleSearchSubmit = (selected: Choice<CslItem>[]) => {\n if (selected.length === 0) {\n exitWith({ identifiers: [], cancelled: true });\n return;\n }\n const items = selected.map((c) => c.value);\n setSelectedItems(items);\n\n if (showStyleSelect) {\n setState(\"style\");\n } else {\n // No style selection needed, complete immediately\n exitWith({\n identifiers: items.map((item) => item.id),\n cancelled: false,\n });\n }\n };\n\n // Handle search cancel\n const handleSearchCancel = () => {\n exitWith({ identifiers: [], cancelled: true });\n };\n\n // Handle style selection\n const handleStyleSelect = (style: string) => {\n exitWith({\n identifiers: selectedItems.map((item) => item.id),\n style,\n cancelled: false,\n });\n };\n\n // Handle style cancel (go back to search)\n const handleStyleCancel = () => {\n setState(\"search\");\n };\n\n // Render based on current state\n if (state === \"exiting\") {\n return createElement(Box);\n }\n\n if (state === \"search\") {\n return createElement(SearchableMultiSelect<CslItem>, {\n choices,\n filterFn,\n visibleCount,\n onSubmit: handleSearchSubmit,\n onCancel: handleSearchCancel,\n header: \"Select references to cite\",\n placeholder: \"Type to search...\",\n defaultSort,\n });\n }\n\n // state === \"style\"\n const count = selectedItems.length;\n const refWord = count === 1 ? \"reference\" : \"references\";\n return createElement(Select<string>, {\n options: styleOptions,\n message: `Select citation style for ${count} ${refWord}:`,\n onSelect: handleStyleSelect,\n onCancel: handleStyleCancel,\n });\n}\n","/**\n * Runner for CiteFlowApp\n *\n * Provides the public API for running the cite flow.\n */\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport type { SearchResult } from \"../../search/types.js\";\nimport { restoreStdinAfterInk } from \"../alternate-screen.js\";\nimport {\n type Choice,\n type SelectOption,\n type SortOption,\n calculateEffectiveLimit,\n} from \"../components/index.js\";\nimport { formatAuthors } from \"../format.js\";\nimport { CiteFlowApp, type CiteFlowResult } from \"./CiteFlowApp.js\";\n\n/**\n * Configuration for the cite flow\n */\nexport interface CiteFlowConfig {\n /** Maximum number of results to display */\n limit: number;\n}\n\n/**\n * Search function type for filtering references\n */\nexport type SearchFunction = (query: string) => SearchResult[];\n\n/**\n * Extract year from CSL item\n */\nfunction extractYear(item: CslItem): number | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n return firstDatePart[0];\n}\n\n/**\n * Extract published date from CSL item\n */\nfunction extractPublishedDate(item: CslItem): Date | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n const [year, month = 1, day = 1] = firstDatePart;\n if (year === undefined) return undefined;\n return new Date(year, month - 1, day);\n}\n\n/**\n * Extract updated date from CSL item (from custom.timestamp)\n */\nfunction extractUpdatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.timestamp;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Extract created date from CSL item (from custom.created_at)\n */\nfunction extractCreatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.created_at;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Format identifiers for meta line\n */\nfunction formatIdentifiers(item: CslItem): string {\n const parts: string[] = [];\n if (item.DOI) parts.push(`DOI: ${item.DOI}`);\n if (item.PMID) parts.push(`PMID: ${item.PMID}`);\n if (item.PMCID) parts.push(`PMCID: ${item.PMCID}`);\n if (item.ISBN) parts.push(`ISBN: ${item.ISBN}`);\n return parts.join(\" · \");\n}\n\n/**\n * Format item type for display\n */\nfunction formatType(type: string): string {\n const typeMap: Record<string, string> = {\n \"article-journal\": \"Journal article\",\n \"article-magazine\": \"Magazine article\",\n \"article-newspaper\": \"Newspaper article\",\n book: \"Book\",\n chapter: \"Book chapter\",\n \"paper-conference\": \"Conference paper\",\n thesis: \"Thesis\",\n report: \"Report\",\n webpage: \"Web page\",\n };\n return typeMap[type] ?? type;\n}\n\n/**\n * Convert CslItem to Choice for SearchableMultiSelect\n */\nfunction toChoice(item: CslItem): Choice<CslItem> {\n const authors = formatAuthors(item.author);\n const year = extractYear(item);\n const identifiers = formatIdentifiers(item);\n const itemType = formatType(item.type);\n\n // Build meta line: Year · Type · Identifiers\n const metaParts: string[] = [];\n if (year) metaParts.push(String(year));\n metaParts.push(itemType);\n if (identifiers) metaParts.push(identifiers);\n\n const updatedDate = extractUpdatedDate(item);\n const createdDate = extractCreatedDate(item);\n const publishedDate = extractPublishedDate(item);\n\n return {\n id: item.id,\n title: item.title ?? \"(No title)\",\n subtitle: authors || \"(No authors)\",\n meta: metaParts.join(\" · \"),\n value: item,\n ...(updatedDate && { updatedDate }),\n ...(createdDate && { createdDate }),\n ...(publishedDate && { publishedDate }),\n };\n}\n\n/**\n * Options for running the cite flow\n */\nexport interface RunCiteFlowOptions {\n /** All references available for selection */\n allReferences: CslItem[];\n /** Search function for filtering */\n searchFn: SearchFunction;\n /** Flow configuration */\n config: CiteFlowConfig;\n /** Style options for style selection */\n styleOptions: SelectOption<string>[];\n /** Whether to show style selection */\n showStyleSelect: boolean;\n}\n\n/**\n * Run the cite flow (reference selection → style selection if needed)\n *\n * This is the main entry point for interactive cite command.\n */\nexport async function runCiteFlow(options: RunCiteFlowOptions): Promise<CiteFlowResult> {\n const { allReferences, searchFn, config, styleOptions, showStyleSelect } = options;\n\n // Convert references to choices\n const choices = allReferences.map(toChoice);\n\n // Calculate effective visible count\n const effectiveLimit = calculateEffectiveLimit(config.limit);\n\n // Create filter function using the provided search function\n const filterFn = (query: string, choices: Choice<CslItem>[]): Choice<CslItem>[] => {\n if (!query.trim()) return choices;\n\n const results = searchFn(query);\n return results.map((r) => toChoice(r.reference));\n };\n\n // Default sort option\n const defaultSort: SortOption = \"updated-desc\";\n\n // Create a promise to capture the result\n return new Promise<CiteFlowResult>((resolve) => {\n let flowResult: CiteFlowResult = {\n identifiers: [],\n cancelled: true,\n };\n\n const handleComplete = (result: CiteFlowResult): void => {\n flowResult = result;\n };\n\n const handleCancel = (): void => {\n flowResult = {\n identifiers: [],\n cancelled: true,\n };\n };\n\n // Render the Ink app (single render for entire flow)\n const { waitUntilExit } = render(\n createElement(CiteFlowApp, {\n choices,\n filterFn,\n visibleCount: effectiveLimit,\n defaultSort,\n styleOptions,\n showStyleSelect,\n onComplete: handleComplete,\n onCancel: handleCancel,\n })\n );\n\n // Wait for the app to exit, then resolve\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(flowResult);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve({\n identifiers: [],\n cancelled: true,\n });\n });\n });\n}\n"],"names":["extractYear","extractPublishedDate","extractUpdatedDate","extractCreatedDate","formatIdentifiers","formatType","toChoice","choices"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-BSWbcT3c.js","sources":["../../src/features/interactive/apps/SearchFlowApp.tsx","../../src/features/interactive/apps/runSearchFlow.ts","../../src/features/interactive/apps/CiteFlowApp.tsx","../../src/features/interactive/apps/runCiteFlow.ts"],"sourcesContent":["/**\n * SearchFlowApp - Single App for search -t flow\n *\n * Manages state transitions: search → action → (style/output-format if needed)\n * Following React Ink Single App Pattern (ADR-015)\n */\n\nimport { Box, useApp } from \"ink\";\nimport type React from \"react\";\nimport { createElement, useEffect, useState } from \"react\";\nimport type { CitationKeyFormat } from \"../../../config/schema.js\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport {\n type ActionMenuResult,\n type ActionType,\n OUTPUT_FORMAT_CHOICES,\n type OutputFormatType,\n STYLE_CHOICES,\n generateOutput,\n getActionChoices,\n isSideEffectAction,\n} from \"../action-menu.js\";\nimport {\n type Choice,\n SearchableMultiSelect,\n Select,\n type SortOption,\n} from \"../components/index.js\";\n\n/**\n * Flow states for the search flow\n */\ntype FlowState = \"search\" | \"action\" | \"style\" | \"output-format\" | \"exiting\";\n\n/**\n * Props for SearchFlowApp\n */\nexport interface SearchFlowAppProps {\n /** Choices for the search prompt */\n choices: Choice<CslItem>[];\n /** Filter function for search */\n filterFn: (query: string, choices: Choice<CslItem>[]) => Choice<CslItem>[];\n /** Number of visible items */\n visibleCount: number;\n /** Default sort option */\n defaultSort: SortOption;\n /** Default citation key format */\n defaultKeyFormat: CitationKeyFormat;\n /** Default citation style */\n defaultStyle: string;\n /** Debounce delay in milliseconds for search filtering */\n debounceMs?: number;\n /** Callback when flow completes */\n onComplete: (result: ActionMenuResult) => void;\n /** Callback when flow is cancelled */\n onCancel: () => void;\n}\n\n/**\n * SearchFlowApp component\n *\n * Single App that manages search → action → style/output-format flow\n */\nexport function SearchFlowApp({\n choices,\n filterFn,\n visibleCount,\n defaultSort,\n defaultKeyFormat,\n defaultStyle,\n debounceMs,\n onComplete,\n onCancel,\n}: SearchFlowAppProps): React.ReactElement {\n const { exit } = useApp();\n const [state, setState] = useState<FlowState>(\"search\");\n const [selectedItems, setSelectedItems] = useState<CslItem[]>([]);\n const [pendingResult, setPendingResult] = useState<ActionMenuResult | null>(null);\n\n // Exit when entering \"exiting\" state (after rendering empty component)\n useEffect(() => {\n if (state === \"exiting\" && pendingResult) {\n exit();\n if (pendingResult.cancelled) {\n onCancel();\n } else {\n onComplete(pendingResult);\n }\n }\n }, [state, pendingResult, exit, onCancel, onComplete]);\n\n // Transition to exiting state with result\n const exitWith = (result: ActionMenuResult) => {\n setPendingResult(result);\n setState(\"exiting\");\n };\n\n // Handle search submission\n const handleSearchSubmit = (selected: Choice<CslItem>[]) => {\n if (selected.length === 0) {\n exitWith({ action: \"cancel\", output: \"\", cancelled: true });\n return;\n }\n setSelectedItems(selected.map((c) => c.value));\n setState(\"action\");\n };\n\n // Handle search cancel\n const handleSearchCancel = () => {\n exitWith({ action: \"cancel\", output: \"\", cancelled: true });\n };\n\n // Handle action selection\n const handleActionSelect = (action: ActionType) => {\n if (action === \"cancel\") {\n exitWith({ action: \"cancel\", output: \"\", cancelled: true });\n return;\n }\n\n // If cite-choose, go to style selection\n if (action === \"cite-choose\") {\n setState(\"style\");\n return;\n }\n\n // If output-format, go to output format submenu\n if (action === \"output-format\") {\n setState(\"output-format\");\n return;\n }\n\n // Handle side-effect actions\n if (isSideEffectAction(action)) {\n exitWith({ action, output: \"\", cancelled: false, selectedItems });\n return;\n }\n\n // Generate output and complete\n const output = generateOutput(action, selectedItems, {\n defaultKeyFormat,\n defaultStyle,\n });\n exitWith({ action, output, cancelled: false });\n };\n\n // Handle action cancel (go back to search)\n const handleActionCancel = () => {\n setState(\"search\");\n };\n\n // Handle style selection\n const handleStyleSelect = (style: string) => {\n const output = generateOutput(\"cite-choose\", selectedItems, {\n defaultKeyFormat,\n defaultStyle: style,\n });\n exitWith({ action: \"cite-choose\", output, cancelled: false });\n };\n\n // Handle style cancel (go back to action)\n const handleStyleCancel = () => {\n setState(\"action\");\n };\n\n // Handle output format selection\n const handleOutputFormatSelect = (format: OutputFormatType) => {\n if (format === \"cancel\") {\n setState(\"action\");\n return;\n }\n\n const output = generateOutput(format, selectedItems, {\n defaultKeyFormat,\n defaultStyle,\n });\n exitWith({ action: \"output-format\", output, cancelled: false });\n };\n\n // Handle output format cancel (go back to action)\n const handleOutputFormatCancel = () => {\n setState(\"action\");\n };\n\n // Render based on current state\n if (state === \"exiting\") {\n // Empty component - Ink will clear the previous content\n return createElement(Box);\n }\n\n if (state === \"search\") {\n return createElement(SearchableMultiSelect<CslItem>, {\n choices,\n filterFn,\n visibleCount,\n onSubmit: handleSearchSubmit,\n onCancel: handleSearchCancel,\n header: \"Search references\",\n placeholder: \"Type to search...\",\n defaultSort,\n ...(debounceMs !== undefined && { debounceMs }),\n });\n }\n\n if (state === \"action\") {\n const count = selectedItems.length;\n const refWord = count === 1 ? \"reference\" : \"references\";\n return createElement(Select<ActionType>, {\n key: \"action\",\n options: getActionChoices(count, { defaultKeyFormat }),\n message: `Action for ${count} selected ${refWord}:`,\n onSelect: handleActionSelect,\n onCancel: handleActionCancel,\n });\n }\n\n if (state === \"output-format\") {\n return createElement(Select<OutputFormatType>, {\n key: \"output-format\",\n options: OUTPUT_FORMAT_CHOICES,\n message: \"Select output format:\",\n onSelect: handleOutputFormatSelect,\n onCancel: handleOutputFormatCancel,\n });\n }\n\n // state === \"style\"\n return createElement(Select<string>, {\n key: \"style\",\n options: STYLE_CHOICES,\n message: \"Select citation style:\",\n onSelect: handleStyleSelect,\n onCancel: handleStyleCancel,\n });\n}\n","/**\n * Runner for SearchFlowApp\n *\n * Provides the public API for running the search flow.\n */\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CitationKeyFormat } from \"../../../config/schema.js\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport { buildResourceIndicators } from \"../../format/resource-indicators.js\";\nimport type { SearchResult } from \"../../search/types.js\";\nimport type { ActionMenuResult } from \"../action-menu.js\";\nimport { restoreStdinAfterInk } from \"../alternate-screen.js\";\nimport { type Choice, type SortOption, calculateEffectiveLimit } from \"../components/index.js\";\nimport { formatAuthors } from \"../format.js\";\nimport { SearchFlowApp } from \"./SearchFlowApp.js\";\n\n/**\n * Configuration for the search flow\n */\nexport interface SearchFlowConfig {\n /** Maximum number of results to display */\n limit: number;\n /** Debounce delay in milliseconds for search filtering */\n debounceMs: number;\n /** Default citation key format */\n defaultKeyFormat?: CitationKeyFormat;\n /** Default citation style */\n defaultStyle?: string;\n}\n\n/**\n * Search function type for filtering references\n */\nexport type SearchFunction = (query: string) => SearchResult[];\n\n/**\n * Extract year from CSL item\n */\nfunction extractYear(item: CslItem): number | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n return firstDatePart[0];\n}\n\n/**\n * Extract published date from CSL item\n */\nfunction extractPublishedDate(item: CslItem): Date | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n const [year, month = 1, day = 1] = firstDatePart;\n if (year === undefined) return undefined;\n return new Date(year, month - 1, day);\n}\n\n/**\n * Extract updated date from CSL item (from custom.timestamp)\n */\nfunction extractUpdatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.timestamp;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Extract created date from CSL item (from custom.created_at)\n */\nfunction extractCreatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.created_at;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Format identifiers for meta line\n */\nfunction formatIdentifiers(item: CslItem): string {\n const parts: string[] = [];\n if (item.DOI) parts.push(`DOI: ${item.DOI}`);\n if (item.PMID) parts.push(`PMID: ${item.PMID}`);\n if (item.PMCID) parts.push(`PMCID: ${item.PMCID}`);\n if (item.ISBN) parts.push(`ISBN: ${item.ISBN}`);\n return parts.join(\" · \");\n}\n\n/**\n * Format item type for display\n */\nfunction formatType(type: string): string {\n const typeMap: Record<string, string> = {\n \"article-journal\": \"Journal article\",\n \"article-magazine\": \"Magazine article\",\n \"article-newspaper\": \"Newspaper article\",\n book: \"Book\",\n chapter: \"Book chapter\",\n \"paper-conference\": \"Conference paper\",\n thesis: \"Thesis\",\n report: \"Report\",\n webpage: \"Web page\",\n };\n return typeMap[type] ?? type;\n}\n\n/**\n * Convert CslItem to Choice for SearchableMultiSelect\n */\nexport function toChoice(item: CslItem): Choice<CslItem> {\n const authors = formatAuthors(item.author);\n const year = extractYear(item);\n const identifiers = formatIdentifiers(item);\n const itemType = formatType(item.type);\n\n // Build meta line: Year · Type · Identifiers\n const metaParts: string[] = [];\n if (year) metaParts.push(String(year));\n metaParts.push(itemType);\n if (identifiers) metaParts.push(identifiers);\n\n const updatedDate = extractUpdatedDate(item);\n const createdDate = extractCreatedDate(item);\n const publishedDate = extractPublishedDate(item);\n\n // Prepend resource indicators to meta if present\n const indicators = buildResourceIndicators(item);\n const metaStr = metaParts.join(\" · \");\n const meta = indicators ? `${indicators} ${metaStr}` : metaStr;\n\n return {\n id: item.id,\n title: item.title ?? \"(No title)\",\n subtitle: authors || \"(No authors)\",\n meta,\n value: item,\n ...(updatedDate && { updatedDate }),\n ...(createdDate && { createdDate }),\n ...(publishedDate && { publishedDate }),\n };\n}\n\n/**\n * Run the search flow (search → action → style if needed)\n *\n * This is the main entry point for the `search -t` command.\n */\nexport async function runSearchFlow(\n allReferences: CslItem[],\n searchFn: SearchFunction,\n config: SearchFlowConfig\n): Promise<ActionMenuResult> {\n // Convert references to choices and build lookup map\n const choices = allReferences.map(toChoice);\n const choiceMap = new Map(choices.map((c) => [c.id, c]));\n\n // Calculate effective visible count\n const effectiveLimit = calculateEffectiveLimit(config.limit);\n\n // Create filter function using the provided search function\n const filterFn = (query: string, choices: Choice<CslItem>[]): Choice<CslItem>[] => {\n if (!query.trim()) return choices;\n\n const results = searchFn(query);\n return results.flatMap((r) => {\n const choice = choiceMap.get(r.reference.id);\n return choice ? [choice] : [];\n });\n };\n\n // Default sort option\n const defaultSort: SortOption = \"updated-desc\";\n\n // Create a promise to capture the result\n return new Promise<ActionMenuResult>((resolve) => {\n let flowResult: ActionMenuResult = {\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n };\n\n const handleComplete = (result: ActionMenuResult): void => {\n flowResult = result;\n };\n\n const handleCancel = (): void => {\n flowResult = {\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n };\n };\n\n // Render the Ink app (single render for entire flow)\n const { waitUntilExit } = render(\n createElement(SearchFlowApp, {\n choices,\n filterFn,\n visibleCount: effectiveLimit,\n defaultSort,\n defaultKeyFormat: config.defaultKeyFormat ?? \"pandoc\",\n defaultStyle: config.defaultStyle ?? \"apa\",\n debounceMs: config.debounceMs,\n onComplete: handleComplete,\n onCancel: handleCancel,\n })\n );\n\n // Wait for the app to exit, then resolve\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(flowResult);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve({\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n });\n });\n });\n}\n","/**\n * CiteFlowApp - Single App for cite command flow\n *\n * Implements the Single App Pattern (ADR-015) for the cite command.\n * Manages state transitions: reference selection → style selection → exiting\n */\n\nimport { Box, useApp } from \"ink\";\nimport type React from \"react\";\nimport { createElement, useEffect, useState } from \"react\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport { SearchableMultiSelect } from \"../components/SearchableMultiSelect.js\";\nimport { Select, type SelectOption } from \"../components/Select.js\";\nimport type { Choice, SortOption } from \"../components/index.js\";\n\n// Flow states\ntype FlowState = \"search\" | \"style\" | \"exiting\";\n\n/**\n * Result from the cite flow\n */\nexport interface CiteFlowResult {\n /** Selected reference IDs */\n identifiers: string[];\n /** Selected style (if style selection was shown) */\n style?: string;\n /** Whether the flow was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Props for CiteFlowApp\n */\nexport interface CiteFlowAppProps {\n /** All reference choices */\n choices: Choice<CslItem>[];\n /** Filter function for search */\n filterFn: (query: string, choices: Choice<CslItem>[]) => Choice<CslItem>[];\n /** Number of visible items */\n visibleCount: number;\n /** Default sort option */\n defaultSort: SortOption;\n /** Style options for style selection */\n styleOptions: SelectOption<string>[];\n /** Whether to show style selection (false if style already specified) */\n showStyleSelect: boolean;\n /** Callback when flow completes */\n onComplete: (result: CiteFlowResult) => void;\n /** Callback when flow is cancelled */\n onCancel: () => void;\n}\n\n/**\n * CiteFlowApp component\n *\n * Single Ink app that handles the entire cite flow:\n * 1. Reference selection (SearchableMultiSelect)\n * 2. Style selection (Select) - optional\n * 3. Exit\n */\nexport function CiteFlowApp({\n choices,\n filterFn,\n visibleCount,\n defaultSort,\n styleOptions,\n showStyleSelect,\n onComplete,\n onCancel,\n}: CiteFlowAppProps): React.ReactElement {\n const { exit } = useApp();\n const [state, setState] = useState<FlowState>(\"search\");\n const [selectedItems, setSelectedItems] = useState<CslItem[]>([]);\n const [pendingResult, setPendingResult] = useState<CiteFlowResult | null>(null);\n\n // Exit when entering \"exiting\" state\n useEffect(() => {\n if (state === \"exiting\" && pendingResult) {\n exit();\n if (pendingResult.cancelled) {\n onCancel();\n } else {\n onComplete(pendingResult);\n }\n }\n }, [state, pendingResult, exit, onCancel, onComplete]);\n\n // Transition to exiting state with result\n const exitWith = (result: CiteFlowResult) => {\n setPendingResult(result);\n setState(\"exiting\");\n };\n\n // Handle search submission\n const handleSearchSubmit = (selected: Choice<CslItem>[]) => {\n if (selected.length === 0) {\n exitWith({ identifiers: [], cancelled: true });\n return;\n }\n const items = selected.map((c) => c.value);\n setSelectedItems(items);\n\n if (showStyleSelect) {\n setState(\"style\");\n } else {\n // No style selection needed, complete immediately\n exitWith({\n identifiers: items.map((item) => item.id),\n cancelled: false,\n });\n }\n };\n\n // Handle search cancel\n const handleSearchCancel = () => {\n exitWith({ identifiers: [], cancelled: true });\n };\n\n // Handle style selection\n const handleStyleSelect = (style: string) => {\n exitWith({\n identifiers: selectedItems.map((item) => item.id),\n style,\n cancelled: false,\n });\n };\n\n // Handle style cancel (go back to search)\n const handleStyleCancel = () => {\n setState(\"search\");\n };\n\n // Render based on current state\n if (state === \"exiting\") {\n return createElement(Box);\n }\n\n if (state === \"search\") {\n return createElement(SearchableMultiSelect<CslItem>, {\n choices,\n filterFn,\n visibleCount,\n onSubmit: handleSearchSubmit,\n onCancel: handleSearchCancel,\n header: \"Select references to cite\",\n placeholder: \"Type to search...\",\n defaultSort,\n });\n }\n\n // state === \"style\"\n const count = selectedItems.length;\n const refWord = count === 1 ? \"reference\" : \"references\";\n return createElement(Select<string>, {\n options: styleOptions,\n message: `Select citation style for ${count} ${refWord}:`,\n onSelect: handleStyleSelect,\n onCancel: handleStyleCancel,\n });\n}\n","/**\n * Runner for CiteFlowApp\n *\n * Provides the public API for running the cite flow.\n */\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CslItem } from \"../../../core/csl-json/types.js\";\nimport type { SearchResult } from \"../../search/types.js\";\nimport { restoreStdinAfterInk } from \"../alternate-screen.js\";\nimport {\n type Choice,\n type SelectOption,\n type SortOption,\n calculateEffectiveLimit,\n} from \"../components/index.js\";\nimport { formatAuthors } from \"../format.js\";\nimport { CiteFlowApp, type CiteFlowResult } from \"./CiteFlowApp.js\";\n\n/**\n * Configuration for the cite flow\n */\nexport interface CiteFlowConfig {\n /** Maximum number of results to display */\n limit: number;\n}\n\n/**\n * Search function type for filtering references\n */\nexport type SearchFunction = (query: string) => SearchResult[];\n\n/**\n * Extract year from CSL item\n */\nfunction extractYear(item: CslItem): number | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n return firstDatePart[0];\n}\n\n/**\n * Extract published date from CSL item\n */\nfunction extractPublishedDate(item: CslItem): Date | undefined {\n const dateParts = item.issued?.[\"date-parts\"];\n if (!dateParts || dateParts.length === 0) return undefined;\n const firstDatePart = dateParts[0];\n if (!firstDatePart || firstDatePart.length === 0) return undefined;\n const [year, month = 1, day = 1] = firstDatePart;\n if (year === undefined) return undefined;\n return new Date(year, month - 1, day);\n}\n\n/**\n * Extract updated date from CSL item (from custom.timestamp)\n */\nfunction extractUpdatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.timestamp;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Extract created date from CSL item (from custom.created_at)\n */\nfunction extractCreatedDate(item: CslItem): Date | undefined {\n const dateStr = item.custom?.created_at;\n if (!dateStr || typeof dateStr !== \"string\") return undefined;\n const date = new Date(dateStr);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * Format identifiers for meta line\n */\nfunction formatIdentifiers(item: CslItem): string {\n const parts: string[] = [];\n if (item.DOI) parts.push(`DOI: ${item.DOI}`);\n if (item.PMID) parts.push(`PMID: ${item.PMID}`);\n if (item.PMCID) parts.push(`PMCID: ${item.PMCID}`);\n if (item.ISBN) parts.push(`ISBN: ${item.ISBN}`);\n return parts.join(\" · \");\n}\n\n/**\n * Format item type for display\n */\nfunction formatType(type: string): string {\n const typeMap: Record<string, string> = {\n \"article-journal\": \"Journal article\",\n \"article-magazine\": \"Magazine article\",\n \"article-newspaper\": \"Newspaper article\",\n book: \"Book\",\n chapter: \"Book chapter\",\n \"paper-conference\": \"Conference paper\",\n thesis: \"Thesis\",\n report: \"Report\",\n webpage: \"Web page\",\n };\n return typeMap[type] ?? type;\n}\n\n/**\n * Convert CslItem to Choice for SearchableMultiSelect\n */\nfunction toChoice(item: CslItem): Choice<CslItem> {\n const authors = formatAuthors(item.author);\n const year = extractYear(item);\n const identifiers = formatIdentifiers(item);\n const itemType = formatType(item.type);\n\n // Build meta line: Year · Type · Identifiers\n const metaParts: string[] = [];\n if (year) metaParts.push(String(year));\n metaParts.push(itemType);\n if (identifiers) metaParts.push(identifiers);\n\n const updatedDate = extractUpdatedDate(item);\n const createdDate = extractCreatedDate(item);\n const publishedDate = extractPublishedDate(item);\n\n return {\n id: item.id,\n title: item.title ?? \"(No title)\",\n subtitle: authors || \"(No authors)\",\n meta: metaParts.join(\" · \"),\n value: item,\n ...(updatedDate && { updatedDate }),\n ...(createdDate && { createdDate }),\n ...(publishedDate && { publishedDate }),\n };\n}\n\n/**\n * Options for running the cite flow\n */\nexport interface RunCiteFlowOptions {\n /** All references available for selection */\n allReferences: CslItem[];\n /** Search function for filtering */\n searchFn: SearchFunction;\n /** Flow configuration */\n config: CiteFlowConfig;\n /** Style options for style selection */\n styleOptions: SelectOption<string>[];\n /** Whether to show style selection */\n showStyleSelect: boolean;\n}\n\n/**\n * Run the cite flow (reference selection → style selection if needed)\n *\n * This is the main entry point for interactive cite command.\n */\nexport async function runCiteFlow(options: RunCiteFlowOptions): Promise<CiteFlowResult> {\n const { allReferences, searchFn, config, styleOptions, showStyleSelect } = options;\n\n // Convert references to choices\n const choices = allReferences.map(toChoice);\n\n // Calculate effective visible count\n const effectiveLimit = calculateEffectiveLimit(config.limit);\n\n // Create filter function using the provided search function\n const filterFn = (query: string, choices: Choice<CslItem>[]): Choice<CslItem>[] => {\n if (!query.trim()) return choices;\n\n const results = searchFn(query);\n return results.map((r) => toChoice(r.reference));\n };\n\n // Default sort option\n const defaultSort: SortOption = \"updated-desc\";\n\n // Create a promise to capture the result\n return new Promise<CiteFlowResult>((resolve) => {\n let flowResult: CiteFlowResult = {\n identifiers: [],\n cancelled: true,\n };\n\n const handleComplete = (result: CiteFlowResult): void => {\n flowResult = result;\n };\n\n const handleCancel = (): void => {\n flowResult = {\n identifiers: [],\n cancelled: true,\n };\n };\n\n // Render the Ink app (single render for entire flow)\n const { waitUntilExit } = render(\n createElement(CiteFlowApp, {\n choices,\n filterFn,\n visibleCount: effectiveLimit,\n defaultSort,\n styleOptions,\n showStyleSelect,\n onComplete: handleComplete,\n onCancel: handleCancel,\n })\n );\n\n // Wait for the app to exit, then resolve\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(flowResult);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve({\n identifiers: [],\n cancelled: true,\n });\n });\n });\n}\n"],"names":["extractYear","extractPublishedDate","extractUpdatedDate","extractCreatedDate","formatIdentifiers","formatType","toChoice","choices"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a } from "./index-
|
|
2
|
-
import { d, g, l, o, s } from "./index-
|
|
1
|
+
import { a } from "./index-eZatWPDi.js";
|
|
2
|
+
import { d, g, l, o, s } from "./index-BrETQT0g.js";
|
|
3
3
|
export {
|
|
4
4
|
a as addAttachment,
|
|
5
5
|
d as detachAttachment,
|
|
@@ -8,4 +8,4 @@ export {
|
|
|
8
8
|
o as openAttachment,
|
|
9
9
|
s as syncAttachments
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=index-
|
|
11
|
+
//# sourceMappingURL=index-BVDVqLTl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BVDVqLTl.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -5,9 +5,9 @@ import { promises, readFileSync, existsSync, mkdirSync, writeFileSync } from "no
|
|
|
5
5
|
import * as os from "node:os";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import path__default, { join, basename, dirname } from "node:path";
|
|
8
|
-
import { n as normalizePathForOutput, d as deleteDirectoryIfEmpty, p as parseFilename, i as isReservedRole, e as ensureDirectory, a as addAttachment, R as RESERVED_ROLES, g as generateFilename, b as findFulltextFiles, c as findFulltextFile, h as extensionToFormat, j as fulltextAttach, k as fulltextGet, l as fulltextDiscover, m as fulltextFetch, o as fulltextConvert, q as getExtension, B as BUILTIN_STYLES,
|
|
8
|
+
import { n as normalizePathForOutput, d as deleteDirectoryIfEmpty, p as parseFilename, i as isReservedRole, e as ensureDirectory, a as addAttachment, R as RESERVED_ROLES, g as generateFilename, b as findFulltextFiles, c as findFulltextFile, h as extensionToFormat, j as fulltextAttach, k as fulltextGet, l as fulltextDiscover, m as fulltextFetch, o as fulltextConvert, q as getExtension, r as getDefaultExportFromCjs, B as BUILTIN_STYLES, s as getFulltextAttachmentTypes, t as startServerWithFileWatcher } from "./index-eZatWPDi.js";
|
|
9
9
|
import { readFile, unlink, stat, readdir, rename } from "node:fs/promises";
|
|
10
|
-
import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-
|
|
10
|
+
import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-CzviN_sy.js";
|
|
11
11
|
import { spawn, spawnSync } from "node:child_process";
|
|
12
12
|
import process$1, { stdin, stdout } from "node:process";
|
|
13
13
|
import * as readline from "node:readline";
|
|
@@ -19,7 +19,7 @@ import "@citation-js/plugin-csl";
|
|
|
19
19
|
import { ZodOptional as ZodOptional$2, z } from "zod";
|
|
20
20
|
import { serve } from "@hono/node-server";
|
|
21
21
|
const name = "@ncukondo/reference-manager";
|
|
22
|
-
const version$1 = "0.
|
|
22
|
+
const version$1 = "0.23.0";
|
|
23
23
|
const description$1 = "A local reference management tool using CSL-JSON as the single source of truth";
|
|
24
24
|
const packageJson = {
|
|
25
25
|
name,
|
|
@@ -902,15 +902,15 @@ class OperationsLibrary {
|
|
|
902
902
|
}
|
|
903
903
|
// High-level operations
|
|
904
904
|
async search(options) {
|
|
905
|
-
const { searchReferences } = await import("./index-
|
|
905
|
+
const { searchReferences } = await import("./index-eZatWPDi.js").then((n) => n.A);
|
|
906
906
|
return searchReferences(this.library, options);
|
|
907
907
|
}
|
|
908
908
|
async list(options) {
|
|
909
|
-
const { listReferences } = await import("./index-
|
|
909
|
+
const { listReferences } = await import("./index-eZatWPDi.js").then((n) => n.z);
|
|
910
910
|
return listReferences(this.library, options ?? {});
|
|
911
911
|
}
|
|
912
912
|
async cite(options) {
|
|
913
|
-
const { citeReferences } = await import("./index-
|
|
913
|
+
const { citeReferences } = await import("./index-eZatWPDi.js").then((n) => n.y);
|
|
914
914
|
const defaultStyle = options.defaultStyle ?? this.citationConfig?.defaultStyle;
|
|
915
915
|
const cslDirectory = options.cslDirectory ?? this.citationConfig?.cslDirectory;
|
|
916
916
|
const mergedOptions = {
|
|
@@ -921,32 +921,32 @@ class OperationsLibrary {
|
|
|
921
921
|
return citeReferences(this.library, mergedOptions);
|
|
922
922
|
}
|
|
923
923
|
async import(inputs, options) {
|
|
924
|
-
const { addReferences } = await import("./index-
|
|
924
|
+
const { addReferences } = await import("./index-eZatWPDi.js").then((n) => n.x);
|
|
925
925
|
return addReferences(inputs, this.library, options ?? {});
|
|
926
926
|
}
|
|
927
927
|
// Attachment operations
|
|
928
928
|
async attachAdd(options) {
|
|
929
|
-
const { addAttachment: addAttachment2 } = await import("./index-
|
|
929
|
+
const { addAttachment: addAttachment2 } = await import("./index-BVDVqLTl.js");
|
|
930
930
|
return addAttachment2(this.library, options);
|
|
931
931
|
}
|
|
932
932
|
async attachList(options) {
|
|
933
|
-
const { listAttachments: listAttachments2 } = await import("./index-
|
|
933
|
+
const { listAttachments: listAttachments2 } = await import("./index-BVDVqLTl.js");
|
|
934
934
|
return listAttachments2(this.library, options);
|
|
935
935
|
}
|
|
936
936
|
async attachGet(options) {
|
|
937
|
-
const { getAttachment: getAttachment2 } = await import("./index-
|
|
937
|
+
const { getAttachment: getAttachment2 } = await import("./index-BVDVqLTl.js");
|
|
938
938
|
return getAttachment2(this.library, options);
|
|
939
939
|
}
|
|
940
940
|
async attachDetach(options) {
|
|
941
|
-
const { detachAttachment: detachAttachment2 } = await import("./index-
|
|
941
|
+
const { detachAttachment: detachAttachment2 } = await import("./index-BVDVqLTl.js");
|
|
942
942
|
return detachAttachment2(this.library, options);
|
|
943
943
|
}
|
|
944
944
|
async attachSync(options) {
|
|
945
|
-
const { syncAttachments: syncAttachments2 } = await import("./index-
|
|
945
|
+
const { syncAttachments: syncAttachments2 } = await import("./index-BVDVqLTl.js");
|
|
946
946
|
return syncAttachments2(this.library, options);
|
|
947
947
|
}
|
|
948
948
|
async attachOpen(options) {
|
|
949
|
-
const { openAttachment: openAttachment2 } = await import("./index-
|
|
949
|
+
const { openAttachment: openAttachment2 } = await import("./index-BVDVqLTl.js");
|
|
950
950
|
return openAttachment2(this.library, options);
|
|
951
951
|
}
|
|
952
952
|
}
|
|
@@ -1790,7 +1790,7 @@ function getAttachExitCode(result) {
|
|
|
1790
1790
|
}
|
|
1791
1791
|
async function executeInteractiveSelect$2(context, config2) {
|
|
1792
1792
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
1793
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
1793
|
+
const { selectReferencesOrExit } = await import("./reference-select-CogjIATu.js");
|
|
1794
1794
|
const allReferences = await context.library.getAll();
|
|
1795
1795
|
const identifiers = await withAlternateScreen2(
|
|
1796
1796
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -2338,8 +2338,8 @@ function getCiteExitCode(result) {
|
|
|
2338
2338
|
}
|
|
2339
2339
|
async function executeInteractiveCite(options, context, config2) {
|
|
2340
2340
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
2341
|
-
const { runCiteFlow } = await import("./index-
|
|
2342
|
-
const { buildStyleChoices, listCustomStyles } = await import("./style-select-
|
|
2341
|
+
const { runCiteFlow } = await import("./index-BSWbcT3c.js");
|
|
2342
|
+
const { buildStyleChoices, listCustomStyles } = await import("./style-select-CJzZczSq.js");
|
|
2343
2343
|
const { search } = await import("./file-watcher-Dyns9dxx.js").then((n) => n.B);
|
|
2344
2344
|
const { tokenize } = await import("./file-watcher-Dyns9dxx.js").then((n) => n.A);
|
|
2345
2345
|
const { checkTTY } = await import("./tty-BMyaEOhX.js");
|
|
@@ -2427,7 +2427,9 @@ const ENV_OVERRIDE_MAP = {
|
|
|
2427
2427
|
PUBMED_EMAIL: "pubmed.email",
|
|
2428
2428
|
PUBMED_API_KEY: "pubmed.api_key",
|
|
2429
2429
|
UNPAYWALL_EMAIL: "fulltext.sources.unpaywall_email",
|
|
2430
|
-
CORE_API_KEY: "fulltext.sources.core_api_key"
|
|
2430
|
+
CORE_API_KEY: "fulltext.sources.core_api_key",
|
|
2431
|
+
NCBI_EMAIL: "fulltext.sources.ncbi_email",
|
|
2432
|
+
NCBI_TOOL: "fulltext.sources.ncbi_tool"
|
|
2431
2433
|
};
|
|
2432
2434
|
const KEY_TO_ENV_MAP = Object.fromEntries(
|
|
2433
2435
|
Object.entries(ENV_OVERRIDE_MAP).map(([envVar, configKey]) => [configKey, envVar])
|
|
@@ -2521,6 +2523,18 @@ const CONFIG_KEY_REGISTRY = [
|
|
|
2521
2523
|
description: "API key for CORE",
|
|
2522
2524
|
optional: true
|
|
2523
2525
|
},
|
|
2526
|
+
{
|
|
2527
|
+
key: "fulltext.sources.ncbi_email",
|
|
2528
|
+
type: "string",
|
|
2529
|
+
description: "Email for NCBI E-utilities",
|
|
2530
|
+
optional: true
|
|
2531
|
+
},
|
|
2532
|
+
{
|
|
2533
|
+
key: "fulltext.sources.ncbi_tool",
|
|
2534
|
+
type: "string",
|
|
2535
|
+
description: "Tool name for NCBI E-utilities",
|
|
2536
|
+
optional: true
|
|
2537
|
+
},
|
|
2524
2538
|
// attachments section
|
|
2525
2539
|
{ key: "attachments.directory", type: "string", description: "Attachments storage directory" },
|
|
2526
2540
|
// cli section
|
|
@@ -3476,9 +3490,6 @@ const alternateScreen = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
|
|
|
3476
3490
|
restoreStdinAfterInk,
|
|
3477
3491
|
withAlternateScreen
|
|
3478
3492
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
3479
|
-
function getDefaultExportFromCjs(x) {
|
|
3480
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
3481
|
-
}
|
|
3482
3493
|
var jsxRuntime = { exports: {} };
|
|
3483
3494
|
var reactJsxRuntime_production = {};
|
|
3484
3495
|
/**
|
|
@@ -6927,7 +6938,7 @@ function formatEditOutput(result) {
|
|
|
6927
6938
|
}
|
|
6928
6939
|
async function executeInteractiveEdit(options, context, config2) {
|
|
6929
6940
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
6930
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
6941
|
+
const { selectReferencesOrExit } = await import("./reference-select-CogjIATu.js");
|
|
6931
6942
|
const allReferences = await context.library.getAll();
|
|
6932
6943
|
const identifiers = await withAlternateScreen2(
|
|
6933
6944
|
() => selectReferencesOrExit(allReferences, { multiSelect: true }, config2.cli.tui)
|
|
@@ -10468,7 +10479,7 @@ function getFulltextExitCode(result) {
|
|
|
10468
10479
|
}
|
|
10469
10480
|
async function executeInteractiveSelect$1(context, config2) {
|
|
10470
10481
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
10471
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
10482
|
+
const { selectReferencesOrExit } = await import("./reference-select-CogjIATu.js");
|
|
10472
10483
|
const allReferences = await context.library.getAll();
|
|
10473
10484
|
const identifiers = await withAlternateScreen2(
|
|
10474
10485
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -31511,7 +31522,7 @@ function registerFulltextFetchTool(server, getLibraryOperations, getConfig) {
|
|
|
31511
31522
|
server.registerTool(
|
|
31512
31523
|
"fulltext_fetch",
|
|
31513
31524
|
{
|
|
31514
|
-
description: "Download and attach Open Access full-text for a reference. Automatically discovers OA sources, downloads PDF/XML, converts PMC XML to Markdown, and attaches files.",
|
|
31525
|
+
description: "Download and attach Open Access full-text for a reference. Automatically discovers OA sources, downloads PDF/XML/HTML, converts PMC XML and arXiv HTML to Markdown, and attaches files.",
|
|
31515
31526
|
inputSchema: {
|
|
31516
31527
|
id: z.string().describe("Reference ID"),
|
|
31517
31528
|
source: z.enum(["pmc", "arxiv", "unpaywall", "core"]).optional().describe("Preferred source (optional)"),
|
|
@@ -31768,7 +31779,7 @@ async function mcpStart(options) {
|
|
|
31768
31779
|
async function executeRemove(options, context) {
|
|
31769
31780
|
const { identifier, idType = "id", fulltextDirectory, deleteFulltext = false } = options;
|
|
31770
31781
|
if (context.mode === "local" && deleteFulltext && fulltextDirectory) {
|
|
31771
|
-
const { removeReference } = await import("./index-
|
|
31782
|
+
const { removeReference } = await import("./index-eZatWPDi.js").then((n) => n.w);
|
|
31772
31783
|
return removeReference(context.library, {
|
|
31773
31784
|
identifier,
|
|
31774
31785
|
idType,
|
|
@@ -31823,7 +31834,7 @@ Continue?`;
|
|
|
31823
31834
|
}
|
|
31824
31835
|
async function executeInteractiveRemove(context, config2) {
|
|
31825
31836
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
31826
|
-
const { selectReferenceItemsOrExit } = await import("./reference-select-
|
|
31837
|
+
const { selectReferenceItemsOrExit } = await import("./reference-select-CogjIATu.js");
|
|
31827
31838
|
const allReferences = await context.library.getAll();
|
|
31828
31839
|
const selectedItems = await withAlternateScreen2(
|
|
31829
31840
|
() => selectReferenceItemsOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -32048,7 +32059,7 @@ async function executeInteractiveSearch(options, context, config2) {
|
|
|
32048
32059
|
validateInteractiveOptions(options);
|
|
32049
32060
|
const { checkTTY } = await import("./tty-BMyaEOhX.js");
|
|
32050
32061
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
32051
|
-
const { runSearchFlow } = await import("./index-
|
|
32062
|
+
const { runSearchFlow } = await import("./index-BSWbcT3c.js");
|
|
32052
32063
|
const { search } = await import("./file-watcher-Dyns9dxx.js").then((n) => n.B);
|
|
32053
32064
|
const { tokenize } = await import("./file-watcher-Dyns9dxx.js").then((n) => n.A);
|
|
32054
32065
|
checkTTY();
|
|
@@ -32067,7 +32078,7 @@ async function executeInteractiveSearch(options, context, config2) {
|
|
|
32067
32078
|
})
|
|
32068
32079
|
);
|
|
32069
32080
|
if (result.selectedItems && !result.cancelled) {
|
|
32070
|
-
const { isSideEffectAction } = await import("./action-menu-
|
|
32081
|
+
const { isSideEffectAction } = await import("./action-menu-C0-X1ndf.js");
|
|
32071
32082
|
if (isSideEffectAction(result.action)) {
|
|
32072
32083
|
await executeSideEffectAction(result.action, result.selectedItems, context, config2);
|
|
32073
32084
|
return { output: "", cancelled: false, action: result.action };
|
|
@@ -32083,7 +32094,7 @@ async function executeSideEffectAction(action, items2, context, config2) {
|
|
|
32083
32094
|
switch (action) {
|
|
32084
32095
|
case "open-url": {
|
|
32085
32096
|
const { resolveDefaultUrl: resolveDefaultUrl2 } = await Promise.resolve().then(() => url);
|
|
32086
|
-
const { openWithSystemApp: openWithSystemApp2 } = await import("./loader-
|
|
32097
|
+
const { openWithSystemApp: openWithSystemApp2 } = await import("./loader-CzviN_sy.js").then((n) => n.j);
|
|
32087
32098
|
const item = items2[0];
|
|
32088
32099
|
if (!item) return;
|
|
32089
32100
|
const url$1 = resolveDefaultUrl2(item);
|
|
@@ -32470,7 +32481,7 @@ function formatUpdateOutput(result, identifier) {
|
|
|
32470
32481
|
}
|
|
32471
32482
|
async function executeInteractiveUpdate(context, config2) {
|
|
32472
32483
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
32473
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
32484
|
+
const { selectReferencesOrExit } = await import("./reference-select-CogjIATu.js");
|
|
32474
32485
|
const allReferences = await context.library.getAll();
|
|
32475
32486
|
const identifiers = await withAlternateScreen2(
|
|
32476
32487
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -32765,7 +32776,7 @@ function getUrlExitCode(result) {
|
|
|
32765
32776
|
}
|
|
32766
32777
|
async function executeInteractiveSelect(context, config2) {
|
|
32767
32778
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
32768
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
32779
|
+
const { selectReferencesOrExit } = await import("./reference-select-CogjIATu.js");
|
|
32769
32780
|
const allReferences = await context.library.getAll();
|
|
32770
32781
|
const identifiers = await withAlternateScreen2(
|
|
32771
32782
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -33268,7 +33279,7 @@ function shouldAutoFetch(cliFlag, configEnabled) {
|
|
|
33268
33279
|
return configEnabled;
|
|
33269
33280
|
}
|
|
33270
33281
|
async function performAutoFetch(addedItems, context, config2) {
|
|
33271
|
-
const { fulltextFetch: fulltextFetch2 } = await import("./index-
|
|
33282
|
+
const { fulltextFetch: fulltextFetch2 } = await import("./index-eZatWPDi.js").then((n) => n.v);
|
|
33272
33283
|
const fetchResults = await autoFetchFulltext(addedItems, context, {
|
|
33273
33284
|
fulltextConfig: config2.fulltext,
|
|
33274
33285
|
fulltextDirectory: config2.attachments.directory,
|
|
@@ -33547,4 +33558,4 @@ export {
|
|
|
33547
33558
|
restoreStdinAfterInk as r,
|
|
33548
33559
|
syncAttachments as s
|
|
33549
33560
|
};
|
|
33550
|
-
//# sourceMappingURL=index-
|
|
33561
|
+
//# sourceMappingURL=index-BrETQT0g.js.map
|