@ncukondo/reference-manager 0.27.1 → 0.28.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/{SearchableMultiSelect-CixI0oIE.js → SearchableMultiSelect-LIMpJm8A.js} +2 -2
- package/dist/chunks/{SearchableMultiSelect-CixI0oIE.js.map → SearchableMultiSelect-LIMpJm8A.js.map} +1 -1
- package/dist/chunks/{action-menu-DKfv85rC.js → action-menu-CdJjcmdk.js} +3 -3
- package/dist/chunks/{action-menu-DKfv85rC.js.map → action-menu-CdJjcmdk.js.map} +1 -1
- package/dist/chunks/{checker-B-SL7krG.js → checker-CP8vSC-S.js} +5 -5
- package/dist/chunks/{checker-B-SL7krG.js.map → checker-CP8vSC-S.js.map} +1 -1
- package/dist/chunks/{crossref-client-D6g3pLUI.js → crossref-client-C1HVx8LA.js} +2 -2
- package/dist/chunks/{crossref-client-D6g3pLUI.js.map → crossref-client-C1HVx8LA.js.map} +1 -1
- package/dist/chunks/{file-watcher-Dlx0PolG.js → file-watcher-CWHg1yol.js} +48 -2
- package/dist/chunks/file-watcher-CWHg1yol.js.map +1 -0
- package/dist/chunks/{fix-interaction-CAIeqdx5.js → fix-interaction-BR3VVyHq.js} +5 -5
- package/dist/chunks/{fix-interaction-CAIeqdx5.js.map → fix-interaction-BR3VVyHq.js.map} +1 -1
- package/dist/chunks/{index-DS3BUDRy.js → index-BP_TPa_d.js} +4 -4
- package/dist/chunks/{index-DS3BUDRy.js.map → index-BP_TPa_d.js.map} +1 -1
- package/dist/chunks/{index-B1pKaejY.js → index-C9Gc8dcm.js} +98 -43
- package/dist/chunks/index-C9Gc8dcm.js.map +1 -0
- package/dist/chunks/{index-D6flikkH.js → index-CHe855EM.js} +3 -3
- package/dist/chunks/index-CHe855EM.js.map +1 -0
- package/dist/chunks/{index-DUpYvm-W.js → index-T-edKSzd.js} +364 -50
- package/dist/chunks/index-T-edKSzd.js.map +1 -0
- package/dist/chunks/{loader-B-fte1uv.js → loader-B6sytmQd.js} +2 -2
- package/dist/chunks/{loader-B-fte1uv.js.map → loader-B6sytmQd.js.map} +1 -1
- package/dist/chunks/{metadata-comparator-C5zfoYdK.js → metadata-comparator-DvqzC5tX.js} +5 -3
- package/dist/chunks/metadata-comparator-DvqzC5tX.js.map +1 -0
- package/dist/chunks/{pubmed-client-mGn5jDIc.js → pubmed-client-DEo6eaH7.js} +2 -2
- package/dist/chunks/{pubmed-client-mGn5jDIc.js.map → pubmed-client-DEo6eaH7.js.map} +1 -1
- package/dist/chunks/{reference-select-BpTCTnrO.js → reference-select-B54Upu7p.js} +4 -4
- package/dist/chunks/{reference-select-BpTCTnrO.js.map → reference-select-B54Upu7p.js.map} +1 -1
- package/dist/chunks/{style-select-RS-lt5lQ.js → style-select-BUwM-Azt.js} +3 -3
- package/dist/chunks/{style-select-RS-lt5lQ.js.map → style-select-BUwM-Azt.js.map} +1 -1
- package/dist/cli/commands/fulltext.d.ts.map +1 -1
- package/dist/cli/completion.d.ts.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/core/csl-json/types.d.ts +67 -0
- package/dist/core/csl-json/types.d.ts.map +1 -1
- package/dist/features/attachments/types.d.ts +8 -16
- package/dist/features/attachments/types.d.ts.map +1 -1
- package/dist/features/check/metadata-similarity.d.ts +1 -0
- package/dist/features/check/metadata-similarity.d.ts.map +1 -1
- package/dist/features/duplicate/detector.d.ts.map +1 -1
- package/dist/features/duplicate/types.d.ts +2 -1
- package/dist/features/duplicate/types.d.ts.map +1 -1
- package/dist/features/format/citation-fallback.d.ts.map +1 -1
- package/dist/features/format/pretty.d.ts.map +1 -1
- package/dist/features/format/resource-indicators.d.ts.map +1 -1
- package/dist/features/import/cache.d.ts +7 -1
- package/dist/features/import/cache.d.ts.map +1 -1
- package/dist/features/import/detector.d.ts +15 -2
- package/dist/features/import/detector.d.ts.map +1 -1
- package/dist/features/import/fetcher.d.ts +7 -0
- package/dist/features/import/fetcher.d.ts.map +1 -1
- package/dist/features/import/importer.d.ts.map +1 -1
- package/dist/features/import/normalizer.d.ts +16 -0
- package/dist/features/import/normalizer.d.ts.map +1 -1
- package/dist/features/import/rate-limiter.d.ts +1 -1
- package/dist/features/import/rate-limiter.d.ts.map +1 -1
- package/dist/features/operations/attachments/get.d.ts.map +1 -1
- package/dist/features/operations/attachments/list.d.ts.map +1 -1
- package/dist/features/operations/attachments/open.d.ts.map +1 -1
- package/dist/features/operations/fulltext/convert.d.ts.map +1 -1
- package/dist/features/operations/fulltext/detach.d.ts.map +1 -1
- package/dist/features/operations/fulltext/discover.d.ts.map +1 -1
- package/dist/features/operations/fulltext/fetch.d.ts +27 -4
- package/dist/features/operations/fulltext/fetch.d.ts.map +1 -1
- package/dist/features/operations/fulltext/get.d.ts.map +1 -1
- package/dist/features/operations/fulltext/open.d.ts.map +1 -1
- package/dist/features/operations/remove.d.ts.map +1 -1
- package/dist/features/search/matcher.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/mcp/tools/fulltext.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/package.json +2 -2
- package/dist/chunks/file-watcher-Dlx0PolG.js.map +0 -1
- package/dist/chunks/index-B1pKaejY.js.map +0 -1
- package/dist/chunks/index-D6flikkH.js.map +0 -1
- package/dist/chunks/index-DUpYvm-W.js.map +0 -1
- package/dist/chunks/metadata-comparator-C5zfoYdK.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix-interaction-CAIeqdx5.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":";;;AA2BO,SAAS,wBAAwB,SAAoC;AAC1E,UAAQ,QAAQ,MAAA;AAAA,IACd,KAAK;AACH,aAAO;AAAA,QACL,EAAE,MAAM,qBAAqB,OAAO,sBAAA;AAAA,QACpC,EAAE,MAAM,uBAAuB,OAAO,mCAAA;AAAA,QACtC,EAAE,MAAM,uBAAuB,OAAO,sBAAA;AAAA,QACtC,EAAE,MAAM,QAAQ,OAAO,OAAA;AAAA,MAAO;AAAA,IAElC,KAAK;AACH,aAAO;AAAA,QACL,EAAE,MAAM,yBAAyB,OAAO,yCAAA;AAAA,QACxC,EAAE,MAAM,mBAAmB,OAAO,kCAAA;AAAA,QAClC,EAAE,MAAM,QAAQ,OAAO,OAAA;AAAA,MAAO;AAAA,IAElC,KAAK;AACH,aAAO;AAAA,QACL,EAAE,MAAM,mBAAmB,OAAO,kCAAA;AAAA,QAClC,EAAE,MAAM,oBAAoB,OAAO,gCAAA;AAAA,QACnC,EAAE,MAAM,QAAQ,OAAO,OAAA;AAAA,MAAO;AAAA,IAElC,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,QACL,EAAE,MAAM,qBAAqB,OAAO,wCAAA;AAAA,QACpC,EAAE,MAAM,QAAQ,OAAO,OAAA;AAAA,MAAO;AAAA,IAElC;AACE,aAAO,CAAA;AAAA,EAAC;AAEd;AAEA,SAAS,OAAO,MAAe,KAAuB;AACpD,QAAM,WAAY,KAAK,QAAQ,QAAiC,CAAA;AAChE,MAAI,SAAS,SAAS,GAAG,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,SAAO,CAAC,GAAG,UAAU,GAAG;AAC1B;AAEA,SAAS,cAAc,QAAgB,SAA+B;AACpE,QAAM,QAAQ,CAAC,MAAM;AACrB,MAAI,QAAQ,SAAS,gBAAgB;AACnC,UAAM,KAAK,SAAS,QAAQ,QAAQ,cAAc,EAAE;AAAA,EACtD;AACA,MAAI,QAAQ,SAAS,eAAe;AAClC,UAAM,KAAK,QAAQ,QAAQ,QAAQ,aAAa,EAAE;AAAA,EACpD;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,WAAW,cAAkC,SAAyB;AAC7E,MAAI,cAAc;AAChB,WAAO,GAAG,YAAY;AAAA;AAAA,EAAO,OAAO;AAAA,EACtC;AACA,SAAO;AACT;AAEA,eAAe,eACb,SACA,MACA,KAC0B;AAC1B,QAAM,OAAO,OAAO,MAAM,GAAG;AAC7B,QAAM,QAAQ,OAAO,KAAK,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,QAAQ,KAAA,EAAK,GAAyB;AAAA,IACtF,QAAQ;AAAA,EAAA,CACT;AACD,QAAM,QAAQ,KAAA;AACd,SAAO,EAAE,SAAS,MAAM,SAAS,cAAc,GAAG,IAAA;AACpD;AAEA,eAAe,gBACb,SACA,MACA,QACA,SAC0B;AAC1B,QAAM,WAAW,cAAc,QAAQ,OAAO;AAC9C,QAAM,OAAO,WAAW,KAAK,MAAM,QAAQ;AAC3C,QAAM,QAAQ,OAAO,KAAK,IAAI,EAAE,QAA4B,EAAE,QAAQ,MAAM;AAC5E,QAAM,QAAQ,KAAA;AACd,SAAO,EAAE,SAAS,MAAM,SAAS,eAAe,QAAQ,GAAA;AAC1D;AAEA,eAAe,yBACb,SACA,MACA,SAC0B;AAC1B,QAAM,SAAS,QAAQ,SAAS;AAChC,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,SAAS,OAAO,SAAS,gDAAA;AAAA,EACpC;AACA,QAAM,EAAE,SAAA,IAAa,MAAM,OAAO,qBAAsB,EAAA,KAAA,OAAA,EAAA,CAAA;AACxD,QAAM,cAAc,MAAM,SAAS,MAAM;AACzC,MAAI,CAAC,YAAY,SAAS;AACxB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS,gCAAgC,MAAM,KAAK,YAAY,KAAK;AAAA,IAAA;AAAA,EAEzE;AACA,QAAM,EAAE,IAAI,KAAK,QAAQ,SAAS,GAAG,SAAA,IAAa,YAAY;AAC9D,QAAM,QAAQ,OAAO,KAAK,IAAI,UAA8B,EAAE,QAAQ,MAAM;AAC5E,QAAM,QAAQ,KAAA;AACd,SAAO,EAAE,SAAS,MAAM,SAAS,yBAAyB,MAAM,GAAA;AAClE;AAEA,eAAe,qBACb,SACA,MACA,SAC0B;AAC1B,MAAI;AAEJ,MAAI,KAAK,KAAK;AACZ,UAAM,EAAE,SAAA,IAAa,MAAM,OAAO,qBAAsB,EAAA,KAAA,OAAA,EAAA,CAAA;AACxD,UAAM,cAAc,MAAM,SAAS,KAAK,GAAG;AAC3C,QAAI,CAAC,YAAY,SAAS;AACxB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,oCAAoC,KAAK,GAAG,KAAK,YAAY,KAAK;AAAA,MAAA;AAAA,IAE/E;AACA,kBAAc,YAAY;AAAA,EAC5B,WAAW,KAAK,MAAM;AACpB,UAAM,EAAE,WAAA,IAAe,MAAM,OAAO,qBAAsB,EAAA,KAAA,OAAA,EAAA,CAAA;AAC1D,UAAM,UAAU,MAAM,WAAW,CAAC,KAAK,IAAI,GAAG,EAAE;AAChD,UAAM,SAAS,QAAQ,CAAC;AACxB,QAAI,CAAC,UAAU,CAAC,OAAO,SAAS;AAC9B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,qCAAqC,KAAK,IAAI,KAAK,QAAQ,SAAS,eAAe;AAAA,MAAA;AAAA,IAEhG;AACA,kBAAc,OAAO;AAAA,EACvB,OAAO;AACL,WAAO,EAAE,SAAS,OAAO,SAAS,+CAAA;AAAA,EACpC;AAEA,QAAM,gBAAgB,QAAQ,SAAS,iBAAiB,CAAA;AACxD,QAAM,UAA4B,CAAA;AAClC,aAAW,SAAS,eAAe;AACjC,QAAI,SAAS,aAAa;AACvB,cAAoC,KAAK,IAAK,YAAwC,KAAK;AAAA,IAC9F;AAAA,EACF;AACA,MAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,WAAO,EAAE,SAAS,OAAO,SAAS,sBAAA;AAAA,EACpC;AACA,QAAM,QAAQ,OAAO,KAAK,IAAI,SAAS,EAAE,QAAQ,MAAM;AACvD,QAAM,QAAQ,KAAA;AACd,SAAO,EAAE,SAAS,MAAM,SAAS,mBAAmB,cAAc,KAAK,IAAI,CAAC,GAAA;AAC9E;AAEA,eAAsB,eACpB,SACA,MACA,SACA,YAC0B;AAC1B,UAAQ,YAAA;AAAA,IACN,KAAK;AACH,aAAO,eAAe,SAAS,MAAM,WAAW;AAAA,IAElD,KAAK;AACH,aAAO,gBAAgB,SAAS,MAAM,aAAa,OAAO;AAAA,IAE5D,KAAK;AACH,aAAO,eAAe,SAAS,MAAM,uBAAuB;AAAA,IAE9D,KAAK;AACH,aAAO,gBAAgB,SAAS,MAAM,yBAAyB,OAAO;AAAA,IAExE,KAAK;AACH,aAAO,eAAe,SAAS,MAAM,uBAAuB;AAAA,IAE9D,KAAK,uBAAuB;AAC1B,YAAM,eAAe,MAAM,QAAQ,OAAO,KAAK,IAAI,EAAE,QAAQ,MAAM;AACnE,UAAI,CAAC,aAAa,SAAS;AACzB,eAAO,EAAE,SAAS,OAAO,SAAS,oBAAoB,KAAK,EAAE,GAAA;AAAA,MAC/D;AACA,YAAM,QAAQ,KAAA;AACd,aAAO,EAAE,SAAS,MAAM,SAAS,WAAW,KAAK,EAAE,IAAI,SAAS,KAAA;AAAA,IAClE;AAAA,IAEA,KAAK;AACH,aAAO,yBAAyB,SAAS,MAAM,OAAO;AAAA,IAExD,KAAK;AACH,aAAO,qBAAqB,SAAS,MAAM,OAAO;AAAA;AAAA;AAAA;AAAA,IAKpD,KAAK;AACH,aAAO,EAAE,SAAS,OAAO,SAAS,4CAAA;AAAA,IAEpC,KAAK;AACH,aAAO,EAAE,SAAS,MAAM,SAAS,UAAA;AAAA,IAEnC;AACE,aAAO,EAAE,SAAS,OAAO,SAAS,mBAAmB,UAAU,GAAA;AAAA,EAAG;AAExE;ACrNA,SAAS,gBACP,SACA,SAC+B;AAC/B,SAAO,IAAI,QAA8B,CAAC,YAAY;AACpD,QAAI,WAAiC;AAErC,UAAM,EAAE,kBAAkB;AAAA,MACxB,cAAc,QAAuB;AAAA,QACnC;AAAA,QACA;AAAA,QACA,UAAU,CAAC,UAAyB;AAClC,qBAAW;AAAA,QACb;AAAA,QACA,UAAU,MAAM;AACd,qBAAW;AAAA,QACb;AAAA,MAAA,CACD;AAAA,IAAA;AAGH,kBAAA,EACG,KAAK,MAAM;AACV,2BAAA;AACA,cAAQ,QAAQ;AAAA,IAClB,CAAC,EACA,MAAM,MAAM;AACX,2BAAA;AACA,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACL,CAAC;AACH;AAEA,SAAS,eAAe,MAAsB;AAC5C,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAEA,SAAS,mBAAmB,SAAsD;AAChF,SAAO,wBAAwB,OAAO,EAAE,IAAI,CAAC,OAAO;AAAA,IAClD,OAAO,EAAE;AAAA,IACT,OAAO,EAAE;AAAA,EAAA,EACT;AACJ;AAEA,eAAe,eACb,QACA,SACA,MACA,UACA,SACe;AACf,SAAO;AACP,QAAM,UAAU,mBAAmB,OAAO;AAC1C,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,QAAQ,eAAe,QAAQ,IAAI;AACzC,QAAM,UAAU,IAAI,KAAK,KAAK,QAAQ,KAAK,QAAQ,OAAO;AAC1D,QAAM,iBAAiB,MAAM,gBAAgB,SAAS,OAAO;AAE7D,MAAI,mBAAmB,MAAM;AAC3B,WAAO;AACP;AAAA,EACF;AAEA,QAAM,eAAe,MAAM,eAAe,SAAS,MAAM,SAAS,cAAc;AAEhF,MAAI,CAAC,aAAa,SAAS;AACzB,YAAQ,OAAO,MAAM,YAAY,aAAa,OAAO;AAAA,CAAI;AACzD;AAAA,EACF;AAEA,UAAQ,OAAO,MAAM,KAAK,aAAa,OAAO;AAAA,CAAI;AAClD,MAAI,mBAAmB,QAAQ;AAC7B,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AACP,QAAI,aAAa,SAAS;AACxB,aAAO,QAAQ,KAAK,QAAQ;AAAA,IAC9B;AAAA,EACF;AACF;AAEA,eAAsB,kBACpB,SACA,SACA,UAC+B;AAC/B,QAAM,oBAA0C;AAAA,IAC9C,eAAe;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS,CAAA;AAAA,EAAC;AAGZ,QAAM,iBAAiB,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS;AAEnE,aAAW,eAAe,gBAAgB;AACxC,UAAM,OAAO,SAAS,YAAY,EAAE;AACpC,QAAI,CAAC,KAAM;AAEX,eAAW,WAAW,YAAY,UAAU;AAC1C,YAAM,eAAe,mBAAmB,SAAS,MAAM,YAAY,IAAI,OAAO;AAAA,IAChF;AAAA,EACF;AAEA,SAAO;AACT;"}
|
|
1
|
+
{"version":3,"file":"fix-interaction-BR3VVyHq.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,8 +1,8 @@
|
|
|
1
1
|
import { useApp, Box, render } from "ink";
|
|
2
2
|
import { useState, useEffect, createElement } from "react";
|
|
3
|
-
import { getActionChoices, OUTPUT_FORMAT_CHOICES, STYLE_CHOICES, isSideEffectAction, generateOutput } from "./action-menu-
|
|
4
|
-
import { S as SearchableMultiSelect, t as toChoice$1, c as calculateEffectiveLimit, f as formatAuthors, a as formatIdentifiers } from "./SearchableMultiSelect-
|
|
5
|
-
import { S as Select, r as restoreStdinAfterInk } from "./index-
|
|
3
|
+
import { getActionChoices, OUTPUT_FORMAT_CHOICES, STYLE_CHOICES, isSideEffectAction, generateOutput } from "./action-menu-CdJjcmdk.js";
|
|
4
|
+
import { S as SearchableMultiSelect, t as toChoice$1, c as calculateEffectiveLimit, f as formatAuthors, a as formatIdentifiers } from "./SearchableMultiSelect-LIMpJm8A.js";
|
|
5
|
+
import { S as Select, r as restoreStdinAfterInk } from "./index-C9Gc8dcm.js";
|
|
6
6
|
function SearchFlowApp({
|
|
7
7
|
choices,
|
|
8
8
|
filterFn,
|
|
@@ -392,4 +392,4 @@ export {
|
|
|
392
392
|
runCiteFlow,
|
|
393
393
|
runSearchFlow
|
|
394
394
|
};
|
|
395
|
-
//# sourceMappingURL=index-
|
|
395
|
+
//# sourceMappingURL=index-BP_TPa_d.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DS3BUDRy.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 type { SearchResult } from \"../../search/types.js\";\nimport type { ActionMenuResult } from \"../action-menu.js\";\nimport { restoreStdinAfterInk } from \"../alternate-screen.js\";\nimport { toChoice } from \"../choice-builder.js\";\nimport { type Choice, type SortOption, calculateEffectiveLimit } from \"../components/index.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 * 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 { formatIdentifiers } from \"../choice-builder.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 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":["toChoice","choices"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-BP_TPa_d.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 type { SearchResult } from \"../../search/types.js\";\nimport type { ActionMenuResult } from \"../action-menu.js\";\nimport { restoreStdinAfterInk } from \"../alternate-screen.js\";\nimport { toChoice } from \"../choice-builder.js\";\nimport { type Choice, type SortOption, calculateEffectiveLimit } from \"../components/index.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 * 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 { formatIdentifiers } from \"../choice-builder.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 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":["toChoice","choices"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Command, Option } from "commander";
|
|
2
|
-
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-
|
|
2
|
+
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";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { promises, readFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
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, 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 getFulltextAttachmentTypes, u as startServerWithFileWatcher } from "./index-
|
|
8
|
+
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 getFulltextAttachmentTypes, u as startServerWithFileWatcher } from "./index-T-edKSzd.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-B6sytmQd.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.28.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,
|
|
@@ -802,10 +802,9 @@ async function resolveDirectory(ref2, attachmentsDirectory) {
|
|
|
802
802
|
}
|
|
803
803
|
return { dirPath, directoryCreated };
|
|
804
804
|
}
|
|
805
|
-
async function updateDirectoryMetadata(library,
|
|
805
|
+
async function updateDirectoryMetadata(library, item, dirPath) {
|
|
806
806
|
const dirName = basename(dirPath);
|
|
807
|
-
|
|
808
|
-
await library.update(ref2.id, {
|
|
807
|
+
await library.update(item.id, {
|
|
809
808
|
custom: {
|
|
810
809
|
...item.custom,
|
|
811
810
|
attachments: {
|
|
@@ -860,7 +859,7 @@ async function openAttachment(library, options) {
|
|
|
860
859
|
const attachments = ref2.custom?.attachments;
|
|
861
860
|
const { dirPath, directoryCreated } = await resolveDirectory(ref2, attachmentsDirectory);
|
|
862
861
|
if (directoryCreated && !attachments?.directory) {
|
|
863
|
-
await updateDirectoryMetadata(library,
|
|
862
|
+
await updateDirectoryMetadata(library, item, dirPath);
|
|
864
863
|
}
|
|
865
864
|
const targetResult = await resolveTargetPath(dirPath, filename, role, attachments);
|
|
866
865
|
if ("error" in targetResult) {
|
|
@@ -902,15 +901,15 @@ class OperationsLibrary {
|
|
|
902
901
|
}
|
|
903
902
|
// High-level operations
|
|
904
903
|
async search(options) {
|
|
905
|
-
const { searchReferences } = await import("./index-
|
|
904
|
+
const { searchReferences } = await import("./index-T-edKSzd.js").then((n) => n.E);
|
|
906
905
|
return searchReferences(this.library, options);
|
|
907
906
|
}
|
|
908
907
|
async list(options) {
|
|
909
|
-
const { listReferences } = await import("./index-
|
|
908
|
+
const { listReferences } = await import("./index-T-edKSzd.js").then((n) => n.D);
|
|
910
909
|
return listReferences(this.library, options ?? {});
|
|
911
910
|
}
|
|
912
911
|
async cite(options) {
|
|
913
|
-
const { citeReferences } = await import("./index-
|
|
912
|
+
const { citeReferences } = await import("./index-T-edKSzd.js").then((n) => n.C);
|
|
914
913
|
const defaultStyle = options.defaultStyle ?? this.citationConfig?.defaultStyle;
|
|
915
914
|
const cslDirectory = options.cslDirectory ?? this.citationConfig?.cslDirectory;
|
|
916
915
|
const mergedOptions = {
|
|
@@ -921,36 +920,36 @@ class OperationsLibrary {
|
|
|
921
920
|
return citeReferences(this.library, mergedOptions);
|
|
922
921
|
}
|
|
923
922
|
async import(inputs, options) {
|
|
924
|
-
const { addReferences } = await import("./index-
|
|
923
|
+
const { addReferences } = await import("./index-T-edKSzd.js").then((n) => n.z);
|
|
925
924
|
return addReferences(inputs, this.library, options ?? {});
|
|
926
925
|
}
|
|
927
926
|
async check(options) {
|
|
928
|
-
const { checkReferences } = await import("./index-
|
|
927
|
+
const { checkReferences } = await import("./index-T-edKSzd.js").then((n) => n.A);
|
|
929
928
|
return checkReferences(this.library, options);
|
|
930
929
|
}
|
|
931
930
|
// Attachment operations
|
|
932
931
|
async attachAdd(options) {
|
|
933
|
-
const { addAttachment: addAttachment2 } = await import("./index-
|
|
932
|
+
const { addAttachment: addAttachment2 } = await import("./index-CHe855EM.js");
|
|
934
933
|
return addAttachment2(this.library, options);
|
|
935
934
|
}
|
|
936
935
|
async attachList(options) {
|
|
937
|
-
const { listAttachments: listAttachments2 } = await import("./index-
|
|
936
|
+
const { listAttachments: listAttachments2 } = await import("./index-CHe855EM.js");
|
|
938
937
|
return listAttachments2(this.library, options);
|
|
939
938
|
}
|
|
940
939
|
async attachGet(options) {
|
|
941
|
-
const { getAttachment: getAttachment2 } = await import("./index-
|
|
940
|
+
const { getAttachment: getAttachment2 } = await import("./index-CHe855EM.js");
|
|
942
941
|
return getAttachment2(this.library, options);
|
|
943
942
|
}
|
|
944
943
|
async attachDetach(options) {
|
|
945
|
-
const { detachAttachment: detachAttachment2 } = await import("./index-
|
|
944
|
+
const { detachAttachment: detachAttachment2 } = await import("./index-CHe855EM.js");
|
|
946
945
|
return detachAttachment2(this.library, options);
|
|
947
946
|
}
|
|
948
947
|
async attachSync(options) {
|
|
949
|
-
const { syncAttachments: syncAttachments2 } = await import("./index-
|
|
948
|
+
const { syncAttachments: syncAttachments2 } = await import("./index-CHe855EM.js");
|
|
950
949
|
return syncAttachments2(this.library, options);
|
|
951
950
|
}
|
|
952
951
|
async attachOpen(options) {
|
|
953
|
-
const { openAttachment: openAttachment2 } = await import("./index-
|
|
952
|
+
const { openAttachment: openAttachment2 } = await import("./index-CHe855EM.js");
|
|
954
953
|
return openAttachment2(this.library, options);
|
|
955
954
|
}
|
|
956
955
|
}
|
|
@@ -1806,7 +1805,7 @@ function getAttachExitCode(result) {
|
|
|
1806
1805
|
}
|
|
1807
1806
|
async function executeInteractiveSelect$2(context, config2) {
|
|
1808
1807
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
1809
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
1808
|
+
const { selectReferencesOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
1810
1809
|
const allReferences = await context.library.getAll();
|
|
1811
1810
|
const identifiers = await withAlternateScreen2(
|
|
1812
1811
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -2471,7 +2470,7 @@ async function handleCheckAction(identifiers, options, globalOpts) {
|
|
|
2471
2470
|
const jsonOptions = buildJsonOptionsFromRefs(options, outputFormat, result, allRefs);
|
|
2472
2471
|
outputCheckResult(result, outputFormat, jsonOptions);
|
|
2473
2472
|
if (options.fix && result.summary.warnings > 0 && allRefs) {
|
|
2474
|
-
const { runFixInteraction } = await import("./fix-interaction-
|
|
2473
|
+
const { runFixInteraction } = await import("./fix-interaction-BR3VVyHq.js");
|
|
2475
2474
|
const findItem = (id2) => allRefs.find((item) => item.id === id2);
|
|
2476
2475
|
const fixResult = await runFixInteraction(result.results, context.library, findItem);
|
|
2477
2476
|
const removedSuffix = fixResult.removed.length > 0 ? `, ${fixResult.removed.length} removed` : "";
|
|
@@ -2539,7 +2538,7 @@ function outputCheckError(error, format2) {
|
|
|
2539
2538
|
}
|
|
2540
2539
|
async function selectReferencesInteractively(context, config2) {
|
|
2541
2540
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
2542
|
-
const { selectReferenceItemsOrExit } = await import("./reference-select-
|
|
2541
|
+
const { selectReferenceItemsOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
2543
2542
|
const allReferences = await context.library.getAll();
|
|
2544
2543
|
if (allReferences.length === 0) {
|
|
2545
2544
|
process.stderr.write("No references in library.\n");
|
|
@@ -2607,10 +2606,10 @@ function getCiteExitCode(result) {
|
|
|
2607
2606
|
}
|
|
2608
2607
|
async function executeInteractiveCite(options, context, config2) {
|
|
2609
2608
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
2610
|
-
const { runCiteFlow } = await import("./index-
|
|
2611
|
-
const { buildStyleChoices, listCustomStyles } = await import("./style-select-
|
|
2612
|
-
const { search } = await import("./file-watcher-
|
|
2613
|
-
const { tokenize } = await import("./file-watcher-
|
|
2609
|
+
const { runCiteFlow } = await import("./index-BP_TPa_d.js");
|
|
2610
|
+
const { buildStyleChoices, listCustomStyles } = await import("./style-select-BUwM-Azt.js");
|
|
2611
|
+
const { search } = await import("./file-watcher-CWHg1yol.js").then((n) => n.B);
|
|
2612
|
+
const { tokenize } = await import("./file-watcher-CWHg1yol.js").then((n) => n.A);
|
|
2614
2613
|
const { checkTTY } = await import("./tty-BMyaEOhX.js");
|
|
2615
2614
|
checkTTY();
|
|
2616
2615
|
const allReferences = await context.library.getAll();
|
|
@@ -7209,7 +7208,7 @@ function formatEditOutput(result) {
|
|
|
7209
7208
|
}
|
|
7210
7209
|
async function executeInteractiveEdit(options, context, config2) {
|
|
7211
7210
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
7212
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
7211
|
+
const { selectReferencesOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
7213
7212
|
const allReferences = await context.library.getAll();
|
|
7214
7213
|
const identifiers = await withAlternateScreen2(
|
|
7215
7214
|
() => selectReferencesOrExit(allReferences, { multiSelect: true }, config2.cli.tui)
|
|
@@ -10728,7 +10727,7 @@ function formatFulltextDiscoverOutput(result, identifier) {
|
|
|
10728
10727
|
}
|
|
10729
10728
|
function formatFulltextFetchOutput(result) {
|
|
10730
10729
|
if (!result.success) {
|
|
10731
|
-
return
|
|
10730
|
+
return formatFetchErrorOutput(result);
|
|
10732
10731
|
}
|
|
10733
10732
|
const lines = [];
|
|
10734
10733
|
if (result.source) {
|
|
@@ -10739,6 +10738,27 @@ function formatFulltextFetchOutput(result) {
|
|
|
10739
10738
|
}
|
|
10740
10739
|
return lines.join("\n");
|
|
10741
10740
|
}
|
|
10741
|
+
function formatFetchErrorOutput(result) {
|
|
10742
|
+
const lines = [`Error: ${result.error}`];
|
|
10743
|
+
if (result.checkedSources && result.checkedSources.length > 0) {
|
|
10744
|
+
lines.push(` Checked: ${result.checkedSources.join(", ")}`);
|
|
10745
|
+
}
|
|
10746
|
+
if (result.skipped && result.skipped.length > 0) {
|
|
10747
|
+
const skippedParts = result.skipped.map((s) => `${s.source} (${s.reason})`);
|
|
10748
|
+
lines.push(` Skipped: ${skippedParts.join(", ")}`);
|
|
10749
|
+
}
|
|
10750
|
+
for (const de of result.discoveryErrors ?? []) {
|
|
10751
|
+
lines.push(` ${de.source}: ${de.error}`);
|
|
10752
|
+
}
|
|
10753
|
+
for (const attempt of result.attempts ?? []) {
|
|
10754
|
+
const fileType = attempt.fileType.toUpperCase();
|
|
10755
|
+
lines.push(` ${attempt.source}: ${fileType} ${attempt.phase} → ${attempt.error}`);
|
|
10756
|
+
}
|
|
10757
|
+
if (result.hint) {
|
|
10758
|
+
lines.push(` Hint: ${result.hint}`);
|
|
10759
|
+
}
|
|
10760
|
+
return lines.join("\n");
|
|
10761
|
+
}
|
|
10742
10762
|
function formatFulltextConvertOutput(result) {
|
|
10743
10763
|
if (!result.success) {
|
|
10744
10764
|
return `Error: ${result.error}`;
|
|
@@ -10750,7 +10770,7 @@ function getFulltextExitCode(result) {
|
|
|
10750
10770
|
}
|
|
10751
10771
|
async function executeInteractiveSelect$1(context, config2, multiSelect = false) {
|
|
10752
10772
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
10753
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
10773
|
+
const { selectReferencesOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
10754
10774
|
const allReferences = await context.library.getAll();
|
|
10755
10775
|
const identifiers = await withAlternateScreen2(
|
|
10756
10776
|
() => selectReferencesOrExit(allReferences, { multiSelect }, config2.cli.tui)
|
|
@@ -11190,6 +11210,7 @@ function buildResourceIndicators(item) {
|
|
|
11190
11210
|
return labels.join(" ");
|
|
11191
11211
|
}
|
|
11192
11212
|
function formatAuthor(author) {
|
|
11213
|
+
if (author.literal) return author.literal;
|
|
11193
11214
|
const family = author.family || "";
|
|
11194
11215
|
const givenInitial = author.given ? `${author.given.charAt(0)}.` : "";
|
|
11195
11216
|
return givenInitial ? `${family}, ${givenInitial}` : family;
|
|
@@ -31944,7 +31965,7 @@ function registerFulltextFetchTool(server, getLibraryOperations, getConfig) {
|
|
|
31944
31965
|
});
|
|
31945
31966
|
if (!result.success) {
|
|
31946
31967
|
return {
|
|
31947
|
-
content: [{ type: "text", text: result
|
|
31968
|
+
content: [{ type: "text", text: formatFetchError(result) }],
|
|
31948
31969
|
isError: true
|
|
31949
31970
|
};
|
|
31950
31971
|
}
|
|
@@ -31960,6 +31981,27 @@ function registerFulltextFetchTool(server, getLibraryOperations, getConfig) {
|
|
|
31960
31981
|
}
|
|
31961
31982
|
);
|
|
31962
31983
|
}
|
|
31984
|
+
function formatFetchError(result) {
|
|
31985
|
+
const lines = [result.error ?? "Unknown error"];
|
|
31986
|
+
if (result.checkedSources && result.checkedSources.length > 0) {
|
|
31987
|
+
lines.push(`Checked: ${result.checkedSources.join(", ")}`);
|
|
31988
|
+
}
|
|
31989
|
+
if (result.skipped && result.skipped.length > 0) {
|
|
31990
|
+
const skippedParts = result.skipped.map((s) => `${s.source} (${s.reason})`);
|
|
31991
|
+
lines.push(`Skipped: ${skippedParts.join(", ")}`);
|
|
31992
|
+
}
|
|
31993
|
+
for (const de of result.discoveryErrors ?? []) {
|
|
31994
|
+
lines.push(`${de.source}: ${de.error}`);
|
|
31995
|
+
}
|
|
31996
|
+
for (const attempt of result.attempts ?? []) {
|
|
31997
|
+
const fileType = attempt.fileType.toUpperCase();
|
|
31998
|
+
lines.push(`${attempt.source}: ${fileType} ${attempt.phase} → ${attempt.error}`);
|
|
31999
|
+
}
|
|
32000
|
+
if (result.hint) {
|
|
32001
|
+
lines.push(`Hint: ${result.hint}`);
|
|
32002
|
+
}
|
|
32003
|
+
return lines.join("\n");
|
|
32004
|
+
}
|
|
31963
32005
|
function registerFulltextConvertTool(server, getLibraryOperations, getConfig) {
|
|
31964
32006
|
server.registerTool(
|
|
31965
32007
|
"fulltext_convert",
|
|
@@ -32183,7 +32225,7 @@ async function mcpStart(options) {
|
|
|
32183
32225
|
async function executeRemove(options, context) {
|
|
32184
32226
|
const { identifier, idType = "id", fulltextDirectory, deleteFulltext = false } = options;
|
|
32185
32227
|
if (context.mode === "local" && deleteFulltext && fulltextDirectory) {
|
|
32186
|
-
const { removeReference } = await import("./index-
|
|
32228
|
+
const { removeReference } = await import("./index-T-edKSzd.js").then((n) => n.x);
|
|
32187
32229
|
return removeReference(context.library, {
|
|
32188
32230
|
identifier,
|
|
32189
32231
|
idType,
|
|
@@ -32238,7 +32280,7 @@ Continue?`;
|
|
|
32238
32280
|
}
|
|
32239
32281
|
async function executeInteractiveRemove(context, config2) {
|
|
32240
32282
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
32241
|
-
const { selectReferenceItemsOrExit } = await import("./reference-select-
|
|
32283
|
+
const { selectReferenceItemsOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
32242
32284
|
const allReferences = await context.library.getAll();
|
|
32243
32285
|
const selectedItems = await withAlternateScreen2(
|
|
32244
32286
|
() => selectReferenceItemsOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -32463,9 +32505,9 @@ async function executeInteractiveSearch(options, context, config2) {
|
|
|
32463
32505
|
validateInteractiveOptions(options);
|
|
32464
32506
|
const { checkTTY } = await import("./tty-BMyaEOhX.js");
|
|
32465
32507
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
32466
|
-
const { runSearchFlow } = await import("./index-
|
|
32467
|
-
const { search } = await import("./file-watcher-
|
|
32468
|
-
const { tokenize } = await import("./file-watcher-
|
|
32508
|
+
const { runSearchFlow } = await import("./index-BP_TPa_d.js");
|
|
32509
|
+
const { search } = await import("./file-watcher-CWHg1yol.js").then((n) => n.B);
|
|
32510
|
+
const { tokenize } = await import("./file-watcher-CWHg1yol.js").then((n) => n.A);
|
|
32469
32511
|
checkTTY();
|
|
32470
32512
|
const allReferences = await context.library.getAll();
|
|
32471
32513
|
const searchFn = (query) => {
|
|
@@ -32482,7 +32524,7 @@ async function executeInteractiveSearch(options, context, config2) {
|
|
|
32482
32524
|
})
|
|
32483
32525
|
);
|
|
32484
32526
|
if (result.selectedItems && !result.cancelled) {
|
|
32485
|
-
const { isSideEffectAction } = await import("./action-menu-
|
|
32527
|
+
const { isSideEffectAction } = await import("./action-menu-CdJjcmdk.js");
|
|
32486
32528
|
if (isSideEffectAction(result.action)) {
|
|
32487
32529
|
await executeSideEffectAction(result.action, result.selectedItems, context, config2);
|
|
32488
32530
|
return { output: "", cancelled: false, action: result.action };
|
|
@@ -32498,7 +32540,7 @@ async function executeSideEffectAction(action, items2, context, config2) {
|
|
|
32498
32540
|
switch (action) {
|
|
32499
32541
|
case "open-url": {
|
|
32500
32542
|
const { resolveDefaultUrl: resolveDefaultUrl2 } = await Promise.resolve().then(() => url);
|
|
32501
|
-
const { openWithSystemApp: openWithSystemApp2 } = await import("./loader-
|
|
32543
|
+
const { openWithSystemApp: openWithSystemApp2 } = await import("./loader-B6sytmQd.js").then((n) => n.j);
|
|
32502
32544
|
const item = items2[0];
|
|
32503
32545
|
if (!item) return;
|
|
32504
32546
|
const url$1 = resolveDefaultUrl2(item);
|
|
@@ -32885,7 +32927,7 @@ function formatUpdateOutput(result, identifier) {
|
|
|
32885
32927
|
}
|
|
32886
32928
|
async function executeInteractiveUpdate(context, config2) {
|
|
32887
32929
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
32888
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
32930
|
+
const { selectReferencesOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
32889
32931
|
const allReferences = await context.library.getAll();
|
|
32890
32932
|
const identifiers = await withAlternateScreen2(
|
|
32891
32933
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -33180,7 +33222,7 @@ function getUrlExitCode(result) {
|
|
|
33180
33222
|
}
|
|
33181
33223
|
async function executeInteractiveSelect(context, config2) {
|
|
33182
33224
|
const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
|
|
33183
|
-
const { selectReferencesOrExit } = await import("./reference-select-
|
|
33225
|
+
const { selectReferencesOrExit } = await import("./reference-select-B54Upu7p.js");
|
|
33184
33226
|
const allReferences = await context.library.getAll();
|
|
33185
33227
|
const identifiers = await withAlternateScreen2(
|
|
33186
33228
|
() => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
|
|
@@ -33233,7 +33275,16 @@ const LIST_OUTPUT_FORMATS = ["pretty", "json", "bibtex", "ids", "uuid"];
|
|
|
33233
33275
|
const MUTATION_OUTPUT_FORMATS = ["json", "text"];
|
|
33234
33276
|
const CONFIG_OUTPUT_FORMATS = ["text", "json"];
|
|
33235
33277
|
const LOG_LEVELS = ["silent", "info", "debug"];
|
|
33236
|
-
const ADD_INPUT_FORMATS = [
|
|
33278
|
+
const ADD_INPUT_FORMATS = [
|
|
33279
|
+
"json",
|
|
33280
|
+
"bibtex",
|
|
33281
|
+
"ris",
|
|
33282
|
+
"pmid",
|
|
33283
|
+
"doi",
|
|
33284
|
+
"isbn",
|
|
33285
|
+
"arxiv",
|
|
33286
|
+
"auto"
|
|
33287
|
+
];
|
|
33237
33288
|
const CONFIG_SECTIONS = [
|
|
33238
33289
|
"backup",
|
|
33239
33290
|
"citation",
|
|
@@ -33728,7 +33779,7 @@ function shouldAutoFetch(cliFlag, configEnabled) {
|
|
|
33728
33779
|
return configEnabled;
|
|
33729
33780
|
}
|
|
33730
33781
|
async function performAutoFetch(addedItems, context, config2) {
|
|
33731
|
-
const { fulltextFetch: fulltextFetch2 } = await import("./index-
|
|
33782
|
+
const { fulltextFetch: fulltextFetch2 } = await import("./index-T-edKSzd.js").then((n) => n.w);
|
|
33732
33783
|
const fetchResults = await autoFetchFulltext(addedItems, context, {
|
|
33733
33784
|
fulltextConfig: config2.fulltext,
|
|
33734
33785
|
fulltextDirectory: config2.attachments.directory,
|
|
@@ -33786,7 +33837,11 @@ async function handleAddAction(inputs, options, program) {
|
|
|
33786
33837
|
}
|
|
33787
33838
|
}
|
|
33788
33839
|
function registerAddCommand(program) {
|
|
33789
|
-
program.command("add").description("Add new reference(s) to the library").argument("[input...]", "File paths or identifiers (PMID/DOI/ISBN), or use stdin").option("-f, --force", "Skip duplicate detection").option(
|
|
33840
|
+
program.command("add").description("Add new reference(s) to the library").argument("[input...]", "File paths or identifiers (PMID/DOI/ISBN/arXiv), or use stdin").option("-f, --force", "Skip duplicate detection").option(
|
|
33841
|
+
"-i, --input <format>",
|
|
33842
|
+
"Input format: json|bibtex|ris|pmid|doi|isbn|arxiv|auto",
|
|
33843
|
+
"auto"
|
|
33844
|
+
).option("--verbose", "Show detailed error information").option("-o, --output <format>", "Output format: json|text", "text").option("--full", "Include full CSL-JSON data in JSON output").option("--fetch-fulltext", "Auto-fetch OA fulltext after adding").option("--no-fetch-fulltext", "Disable auto-fetch fulltext (overrides config)").action(async (inputs, options) => {
|
|
33790
33845
|
await handleAddAction(inputs, options, program);
|
|
33791
33846
|
});
|
|
33792
33847
|
}
|
|
@@ -34016,4 +34071,4 @@ export {
|
|
|
34016
34071
|
restoreStdinAfterInk as r,
|
|
34017
34072
|
syncAttachments as s
|
|
34018
34073
|
};
|
|
34019
|
-
//# sourceMappingURL=index-
|
|
34074
|
+
//# sourceMappingURL=index-C9Gc8dcm.js.map
|