@ncukondo/reference-manager 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +4 -4
  2. package/dist/chunks/action-menu-D8gSe1YM.js +87 -0
  3. package/dist/chunks/action-menu-D8gSe1YM.js.map +1 -0
  4. package/dist/chunks/clipboard-KXwFSJ4w.js +56 -0
  5. package/dist/chunks/clipboard-KXwFSJ4w.js.map +1 -0
  6. package/dist/chunks/{format-CduFas9k.js → format-B52BI__9.js} +2 -2
  7. package/dist/chunks/{format-CduFas9k.js.map → format-B52BI__9.js.map} +1 -1
  8. package/dist/chunks/{index-CfuE2EuX.js → index-B5W5srUa.js} +50 -38
  9. package/dist/chunks/index-B5W5srUa.js.map +1 -0
  10. package/dist/chunks/{index-CqrsgD_G.js → index-BPhIwqHO.js} +577 -100
  11. package/dist/chunks/index-BPhIwqHO.js.map +1 -0
  12. package/dist/chunks/{index-D_UafVdu.js → index-iYPq6D80.js} +2 -2
  13. package/dist/chunks/index-iYPq6D80.js.map +1 -0
  14. package/dist/chunks/{loader-BN5sS7lg.js → loader-BtW20O32.js} +41 -35
  15. package/dist/chunks/loader-BtW20O32.js.map +1 -0
  16. package/dist/chunks/{reference-select-DbnF3oWs.js → reference-select-DcClzkw2.js} +3 -3
  17. package/dist/chunks/{reference-select-DbnF3oWs.js.map → reference-select-DcClzkw2.js.map} +1 -1
  18. package/dist/chunks/{style-select-CbV5k3AV.js → style-select-D0bgalgW.js} +2 -2
  19. package/dist/chunks/{style-select-CbV5k3AV.js.map → style-select-D0bgalgW.js.map} +1 -1
  20. package/dist/cli/commands/attach.d.ts.map +1 -1
  21. package/dist/cli/commands/cite.d.ts.map +1 -1
  22. package/dist/cli/commands/config.d.ts.map +1 -1
  23. package/dist/cli/commands/list.d.ts +6 -2
  24. package/dist/cli/commands/list.d.ts.map +1 -1
  25. package/dist/cli/commands/remove.d.ts +5 -0
  26. package/dist/cli/commands/remove.d.ts.map +1 -1
  27. package/dist/cli/commands/search.d.ts +18 -3
  28. package/dist/cli/commands/search.d.ts.map +1 -1
  29. package/dist/cli/commands/url.d.ts +58 -0
  30. package/dist/cli/commands/url.d.ts.map +1 -0
  31. package/dist/cli/helpers.d.ts +19 -0
  32. package/dist/cli/helpers.d.ts.map +1 -1
  33. package/dist/cli/index.d.ts.map +1 -1
  34. package/dist/cli.js +1 -1
  35. package/dist/config/defaults.d.ts +0 -6
  36. package/dist/config/defaults.d.ts.map +1 -1
  37. package/dist/config/env-override.d.ts.map +1 -1
  38. package/dist/config/key-parser.d.ts.map +1 -1
  39. package/dist/config/loader.d.ts +7 -4
  40. package/dist/config/loader.d.ts.map +1 -1
  41. package/dist/config/schema.d.ts +27 -14
  42. package/dist/config/schema.d.ts.map +1 -1
  43. package/dist/features/format/items.d.ts +1 -1
  44. package/dist/features/format/items.d.ts.map +1 -1
  45. package/dist/features/interactive/action-menu.d.ts +40 -5
  46. package/dist/features/interactive/action-menu.d.ts.map +1 -1
  47. package/dist/features/interactive/apps/SearchFlowApp.d.ts +8 -3
  48. package/dist/features/interactive/apps/SearchFlowApp.d.ts.map +1 -1
  49. package/dist/features/interactive/apps/runSearchFlow.d.ts +5 -0
  50. package/dist/features/interactive/apps/runSearchFlow.d.ts.map +1 -1
  51. package/dist/features/operations/url.d.ts +24 -0
  52. package/dist/features/operations/url.d.ts.map +1 -0
  53. package/dist/index.js +1 -1
  54. package/dist/utils/clipboard.d.ts +19 -0
  55. package/dist/utils/clipboard.d.ts.map +1 -0
  56. package/package.json +2 -2
  57. package/dist/chunks/index-CfuE2EuX.js.map +0 -1
  58. package/dist/chunks/index-CqrsgD_G.js.map +0 -1
  59. package/dist/chunks/index-D_UafVdu.js.map +0 -1
  60. package/dist/chunks/loader-BN5sS7lg.js.map +0 -1
package/README.md CHANGED
@@ -582,9 +582,9 @@ log_level = "info"
582
582
  max_generations = 50
583
583
  max_age_days = 365
584
584
 
585
- [fulltext]
586
- # Override fulltext directory (defaults to {data}/fulltext)
587
- directory = "~/references/fulltext"
585
+ [attachments]
586
+ # Override attachments directory (defaults to {data}/attachments)
587
+ directory = "~/references/attachments"
588
588
 
589
589
  [server]
590
590
  auto_start = true
@@ -633,7 +633,7 @@ ref config edit --local # Edit project-local config
633
633
  - `server.*` — HTTP server settings
634
634
  - `citation.*` — Citation defaults (style, locale, format)
635
635
  - `pubmed.*` — PubMed API credentials
636
- - `fulltext.*` — Fulltext storage
636
+ - `attachments.*` — Attachments storage
637
637
  - `cli.*` — CLI behavior (limits, sorting, TUI mode)
638
638
  - `mcp.*` — MCP server settings
639
639
 
@@ -0,0 +1,87 @@
1
+ import "ink";
2
+ import "react";
3
+ import { b as stringify, f as formatBibtex } from "./index-BPhIwqHO.js";
4
+ import { f as formatBibliographyCSL } from "./index-B4gr0P83.js";
5
+ const SIDE_EFFECT_ACTIONS = /* @__PURE__ */ new Set([
6
+ "open-url",
7
+ "open-fulltext",
8
+ "manage-attachments",
9
+ "edit",
10
+ "remove"
11
+ ]);
12
+ function isSideEffectAction(action) {
13
+ return SIDE_EFFECT_ACTIONS.has(action);
14
+ }
15
+ function getActionChoices(count, config = {}) {
16
+ const { defaultKeyFormat = "pandoc" } = config;
17
+ const isSingle = count === 1;
18
+ const formatLabel = defaultKeyFormat === "latex" ? "LaTeX" : "Pandoc";
19
+ const keyLabel = isSingle ? `Citation key (${formatLabel})` : `Citation keys (${formatLabel})`;
20
+ const choices = [
21
+ { label: keyLabel, value: "key-default" },
22
+ { label: "Generate citation", value: "cite-default" },
23
+ { label: "Generate citation (choose style)", value: "cite-choose" }
24
+ ];
25
+ if (isSingle) {
26
+ choices.push(
27
+ { label: "Open URL", value: "open-url" },
28
+ { label: "Open fulltext", value: "open-fulltext" },
29
+ { label: "Manage attachments", value: "manage-attachments" }
30
+ );
31
+ }
32
+ choices.push(
33
+ { label: isSingle ? "Edit reference" : "Edit references", value: "edit" },
34
+ { label: "Output (choose format)", value: "output-format" },
35
+ { label: "Remove", value: "remove" },
36
+ { label: "Cancel", value: "cancel" }
37
+ );
38
+ return choices;
39
+ }
40
+ getActionChoices(1);
41
+ const OUTPUT_FORMAT_CHOICES = [
42
+ { label: "IDs (citation keys)", value: "output-ids" },
43
+ { label: "CSL-JSON", value: "output-csl-json" },
44
+ { label: "BibTeX", value: "output-bibtex" },
45
+ { label: "YAML", value: "output-yaml" },
46
+ { label: "Cancel", value: "cancel" }
47
+ ];
48
+ const STYLE_CHOICES = [
49
+ { label: "APA", value: "apa" },
50
+ { label: "Vancouver", value: "vancouver" },
51
+ { label: "Harvard", value: "harvard" }
52
+ ];
53
+ function generateOutput(action, items, config = {}) {
54
+ const { defaultKeyFormat = "pandoc", defaultStyle = "apa" } = config;
55
+ switch (action) {
56
+ case "output-ids":
57
+ return items.map((item) => item.id).join("\n");
58
+ case "output-csl-json":
59
+ return JSON.stringify(items, null, 2);
60
+ case "output-bibtex":
61
+ return formatBibtex(items);
62
+ case "output-yaml":
63
+ return stringify(items).trimEnd();
64
+ // cite-default uses config.defaultStyle; cite-choose has its style
65
+ // overridden by the caller (processAction/SearchFlowApp) before reaching here.
66
+ case "cite-default":
67
+ case "cite-choose":
68
+ return formatBibliographyCSL(items, { style: defaultStyle });
69
+ case "key-default":
70
+ if (defaultKeyFormat === "latex") {
71
+ return `\\cite{${items.map((i) => i.id).join(",")}}`;
72
+ }
73
+ return items.map((i) => `@${i.id}`).join("; ");
74
+ case "cancel":
75
+ return "";
76
+ default:
77
+ return "";
78
+ }
79
+ }
80
+ export {
81
+ OUTPUT_FORMAT_CHOICES,
82
+ STYLE_CHOICES,
83
+ generateOutput,
84
+ getActionChoices,
85
+ isSideEffectAction
86
+ };
87
+ //# sourceMappingURL=action-menu-D8gSe1YM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-menu-D8gSe1YM.js","sources":["../../src/features/interactive/action-menu.ts"],"sourcesContent":["/**\n * Action menu for interactive search mode.\n * Allows users to perform actions on selected references.\n */\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type React from \"react\";\nimport { stringify as yamlStringify } from \"yaml\";\nimport type { CitationKeyFormat } from \"../../config/schema.js\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { formatBibliographyCSL, formatBibtex } from \"../format/index.js\";\nimport { restoreStdinAfterInk } from \"./alternate-screen.js\";\nimport { Select, type SelectOption } from \"./components/index.js\";\n\n/**\n * Action types available in the action menu.\n */\nexport type ActionType =\n | \"key-default\"\n | \"cite-default\"\n | \"cite-choose\"\n | \"open-url\"\n | \"open-fulltext\"\n | \"manage-attachments\"\n | \"edit\"\n | \"output-format\"\n | \"remove\"\n | \"cancel\";\n\n/**\n * Output format types for the output format submenu.\n */\nexport type OutputFormatType =\n | \"output-ids\"\n | \"output-csl-json\"\n | \"output-bibtex\"\n | \"output-yaml\"\n | \"cancel\";\n\n/**\n * Side-effect action types that perform operations rather than producing stdout output.\n */\nconst SIDE_EFFECT_ACTIONS: ReadonlySet<ActionType> = new Set([\n \"open-url\",\n \"open-fulltext\",\n \"manage-attachments\",\n \"edit\",\n \"remove\",\n]);\n\n/**\n * Check if an action is a side-effect action.\n */\nexport function isSideEffectAction(action: ActionType): boolean {\n return SIDE_EFFECT_ACTIONS.has(action);\n}\n\n/**\n * Result from action menu selection.\n */\nexport interface ActionMenuResult {\n /** Selected action type */\n action: ActionType;\n /** Generated output (empty for cancel and side-effect actions) */\n output: string;\n /** Whether the prompt was cancelled */\n cancelled: boolean;\n /** Selected items (for side-effect actions) */\n selectedItems?: CslItem[];\n}\n\n/**\n * Result from style selection prompt.\n */\nexport interface StyleSelectResult {\n /** Selected style (undefined if cancelled) */\n style?: string;\n /** Whether the prompt was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Config options for action choices.\n */\nexport interface ActionChoicesConfig {\n defaultKeyFormat?: CitationKeyFormat | undefined;\n}\n\n/**\n * Config options for output generation.\n */\nexport interface GenerateOutputConfig {\n defaultKeyFormat?: CitationKeyFormat | undefined;\n defaultStyle?: string | undefined;\n}\n\n/**\n * Generate action choices for the action menu.\n * Returns different choices based on the number of selected entries.\n */\nexport function getActionChoices(\n count: number,\n config: ActionChoicesConfig = {}\n): SelectOption<ActionType>[] {\n const { defaultKeyFormat = \"pandoc\" } = config;\n const isSingle = count === 1;\n const formatLabel = defaultKeyFormat === \"latex\" ? \"LaTeX\" : \"Pandoc\";\n\n const keyLabel = isSingle ? `Citation key (${formatLabel})` : `Citation keys (${formatLabel})`;\n\n const choices: SelectOption<ActionType>[] = [\n { label: keyLabel, value: \"key-default\" },\n { label: \"Generate citation\", value: \"cite-default\" },\n { label: \"Generate citation (choose style)\", value: \"cite-choose\" },\n ];\n\n if (isSingle) {\n choices.push(\n { label: \"Open URL\", value: \"open-url\" },\n { label: \"Open fulltext\", value: \"open-fulltext\" },\n { label: \"Manage attachments\", value: \"manage-attachments\" }\n );\n }\n\n choices.push(\n { label: isSingle ? \"Edit reference\" : \"Edit references\", value: \"edit\" },\n { label: \"Output (choose format)\", value: \"output-format\" },\n { label: \"Remove\", value: \"remove\" },\n { label: \"Cancel\", value: \"cancel\" }\n );\n\n return choices;\n}\n\n/**\n * Available action choices for the action menu (default, single entry).\n * @deprecated Use getActionChoices(count, config) for dynamic choices.\n */\nexport const ACTION_CHOICES: SelectOption<ActionType>[] = getActionChoices(1);\n\n/**\n * Output format choices for the output format submenu.\n */\nexport const OUTPUT_FORMAT_CHOICES: SelectOption<OutputFormatType>[] = [\n { label: \"IDs (citation keys)\", value: \"output-ids\" },\n { label: \"CSL-JSON\", value: \"output-csl-json\" },\n { label: \"BibTeX\", value: \"output-bibtex\" },\n { label: \"YAML\", value: \"output-yaml\" },\n { label: \"Cancel\", value: \"cancel\" },\n];\n\n/**\n * Available style choices for citation style selection.\n */\nexport const STYLE_CHOICES: SelectOption<string>[] = [\n { label: \"APA\", value: \"apa\" },\n { label: \"Vancouver\", value: \"vancouver\" },\n { label: \"Harvard\", value: \"harvard\" },\n];\n\n/**\n * Props for the ActionMenuApp component\n */\ninterface ActionMenuAppProps {\n message: string;\n options: SelectOption<ActionType>[];\n onSelect: (value: ActionType) => void;\n onCancel: () => void;\n}\n\n/**\n * ActionMenuApp component - wraps Select for action menu\n */\nfunction ActionMenuApp({\n message,\n options,\n onSelect,\n onCancel,\n}: ActionMenuAppProps): React.ReactElement {\n return createElement(Select<ActionType>, {\n options,\n message,\n onSelect,\n onCancel,\n });\n}\n\n/**\n * Props for the StyleSelectApp component\n */\ninterface StyleSelectAppProps {\n options: SelectOption<string>[];\n onSelect: (value: string) => void;\n onCancel: () => void;\n}\n\n/**\n * StyleSelectApp component - wraps Select for style selection\n */\nfunction StyleSelectApp({ options, onSelect, onCancel }: StyleSelectAppProps): React.ReactElement {\n return createElement(Select<string>, {\n options,\n message: \"Select citation style:\",\n onSelect,\n onCancel,\n });\n}\n\n/**\n * Generate output for the given action and items.\n */\nexport function generateOutput(\n action: ActionType | OutputFormatType,\n items: CslItem[],\n config: GenerateOutputConfig = {}\n): string {\n const { defaultKeyFormat = \"pandoc\", defaultStyle = \"apa\" } = config;\n\n switch (action) {\n case \"output-ids\":\n return items.map((item) => item.id).join(\"\\n\");\n\n case \"output-csl-json\":\n return JSON.stringify(items, null, 2);\n\n case \"output-bibtex\":\n return formatBibtex(items);\n\n case \"output-yaml\":\n return yamlStringify(items).trimEnd();\n\n // cite-default uses config.defaultStyle; cite-choose has its style\n // overridden by the caller (processAction/SearchFlowApp) before reaching here.\n case \"cite-default\":\n case \"cite-choose\":\n return formatBibliographyCSL(items, { style: defaultStyle });\n\n case \"key-default\":\n if (defaultKeyFormat === \"latex\") {\n return `\\\\cite{${items.map((i) => i.id).join(\",\")}}`;\n }\n return items.map((i) => `@${i.id}`).join(\"; \");\n\n case \"cancel\":\n return \"\";\n\n default:\n return \"\";\n }\n}\n\n/**\n * Run the style selection prompt.\n */\nexport async function runStyleSelectPrompt(): Promise<StyleSelectResult> {\n return new Promise<StyleSelectResult>((resolve) => {\n let result: StyleSelectResult = { cancelled: true };\n\n const handleSelect = (value: string): void => {\n result = {\n style: value,\n cancelled: false,\n };\n };\n\n const handleCancel = (): void => {\n result = {\n cancelled: true,\n };\n };\n\n // Render the Ink app\n const { waitUntilExit } = render(\n createElement(StyleSelectApp, {\n options: STYLE_CHOICES,\n onSelect: handleSelect,\n onCancel: handleCancel,\n })\n );\n\n // Wait for the app to exit, then resolve\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(result);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve({\n cancelled: true,\n });\n });\n });\n}\n\n/**\n * Process the selected action and generate result.\n */\nasync function processAction(\n action: ActionType,\n items: CslItem[],\n config: GenerateOutputConfig = {}\n): Promise<ActionMenuResult> {\n // Handle cite-choose: prompt for style first\n if (action === \"cite-choose\") {\n const styleResult = await runStyleSelectPrompt();\n if (styleResult.cancelled) {\n return {\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n };\n }\n return {\n action,\n output: generateOutput(action, items, {\n ...config,\n defaultStyle: styleResult.style,\n }),\n cancelled: false,\n };\n }\n\n // Handle cancel\n if (action === \"cancel\") {\n return {\n action,\n output: \"\",\n cancelled: true,\n };\n }\n\n // Handle side-effect actions\n if (isSideEffectAction(action)) {\n return {\n action,\n output: \"\",\n cancelled: false,\n selectedItems: items,\n };\n }\n\n // Handle other actions\n return {\n action,\n output: generateOutput(action, items, config),\n cancelled: false,\n };\n}\n\n/**\n * Run the action menu for selected references.\n *\n * @param items - Selected references\n * @param config - Output generation config\n * @returns Action result with output\n */\nexport async function runActionMenu(\n items: CslItem[],\n config: GenerateOutputConfig = {}\n): Promise<ActionMenuResult> {\n const count = items.length;\n const refWord = count === 1 ? \"reference\" : \"references\";\n const message = `Action for ${count} selected ${refWord}:`;\n const actionChoices = getActionChoices(count, {\n defaultKeyFormat: config.defaultKeyFormat,\n });\n\n return new Promise<ActionMenuResult>((resolve) => {\n let selectedAction: ActionType | null = null;\n\n const handleSelect = (action: ActionType): void => {\n selectedAction = action;\n };\n\n const handleCancel = (): void => {\n selectedAction = null;\n };\n\n // Render the Ink app\n const { waitUntilExit } = render(\n createElement(ActionMenuApp, {\n message,\n options: actionChoices,\n onSelect: handleSelect,\n onCancel: handleCancel,\n })\n );\n\n // Wait for the app to exit, then process the action\n waitUntilExit()\n .then(async () => {\n restoreStdinAfterInk();\n\n if (selectedAction === null) {\n resolve({\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n });\n } else {\n const result = await processAction(selectedAction, items, config);\n resolve(result);\n }\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve({\n action: \"cancel\",\n output: \"\",\n cancelled: true,\n });\n });\n });\n}\n"],"names":["yamlStringify"],"mappings":";;;;AA2CA,MAAM,0CAAmD,IAAI;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,SAAS,mBAAmB,QAA6B;AAC9D,SAAO,oBAAoB,IAAI,MAAM;AACvC;AA6CO,SAAS,iBACd,OACA,SAA8B,IACF;AAC5B,QAAM,EAAE,mBAAmB,SAAA,IAAa;AACxC,QAAM,WAAW,UAAU;AAC3B,QAAM,cAAc,qBAAqB,UAAU,UAAU;AAE7D,QAAM,WAAW,WAAW,iBAAiB,WAAW,MAAM,kBAAkB,WAAW;AAE3F,QAAM,UAAsC;AAAA,IAC1C,EAAE,OAAO,UAAU,OAAO,cAAA;AAAA,IAC1B,EAAE,OAAO,qBAAqB,OAAO,eAAA;AAAA,IACrC,EAAE,OAAO,oCAAoC,OAAO,cAAA;AAAA,EAAc;AAGpE,MAAI,UAAU;AACZ,YAAQ;AAAA,MACN,EAAE,OAAO,YAAY,OAAO,WAAA;AAAA,MAC5B,EAAE,OAAO,iBAAiB,OAAO,gBAAA;AAAA,MACjC,EAAE,OAAO,sBAAsB,OAAO,qBAAA;AAAA,IAAqB;AAAA,EAE/D;AAEA,UAAQ;AAAA,IACN,EAAE,OAAO,WAAW,mBAAmB,mBAAmB,OAAO,OAAA;AAAA,IACjE,EAAE,OAAO,0BAA0B,OAAO,gBAAA;AAAA,IAC1C,EAAE,OAAO,UAAU,OAAO,SAAA;AAAA,IAC1B,EAAE,OAAO,UAAU,OAAO,SAAA;AAAA,EAAS;AAGrC,SAAO;AACT;AAM0D,iBAAiB,CAAC;AAKrE,MAAM,wBAA0D;AAAA,EACrE,EAAE,OAAO,uBAAuB,OAAO,aAAA;AAAA,EACvC,EAAE,OAAO,YAAY,OAAO,kBAAA;AAAA,EAC5B,EAAE,OAAO,UAAU,OAAO,gBAAA;AAAA,EAC1B,EAAE,OAAO,QAAQ,OAAO,cAAA;AAAA,EACxB,EAAE,OAAO,UAAU,OAAO,SAAA;AAC5B;AAKO,MAAM,gBAAwC;AAAA,EACnD,EAAE,OAAO,OAAO,OAAO,MAAA;AAAA,EACvB,EAAE,OAAO,aAAa,OAAO,YAAA;AAAA,EAC7B,EAAE,OAAO,WAAW,OAAO,UAAA;AAC7B;AAqDO,SAAS,eACd,QACA,OACA,SAA+B,CAAA,GACvB;AACR,QAAM,EAAE,mBAAmB,UAAU,eAAe,UAAU;AAE9D,UAAQ,QAAA;AAAA,IACN,KAAK;AACH,aAAO,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,EAAE,KAAK,IAAI;AAAA,IAE/C,KAAK;AACH,aAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AAAA,IAEtC,KAAK;AACH,aAAO,aAAa,KAAK;AAAA,IAE3B,KAAK;AACH,aAAOA,UAAc,KAAK,EAAE,QAAA;AAAA;AAAA;AAAA,IAI9B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,sBAAsB,OAAO,EAAE,OAAO,cAAc;AAAA,IAE7D,KAAK;AACH,UAAI,qBAAqB,SAAS;AAChC,eAAO,UAAU,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC;AAAA,MACnD;AACA,aAAO,MAAM,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,IAAI;AAAA,IAE/C,KAAK;AACH,aAAO;AAAA,IAET;AACE,aAAO;AAAA,EAAA;AAEb;"}
@@ -0,0 +1,56 @@
1
+ import { execFile } from "node:child_process";
2
+ import fs__default from "node:fs";
3
+ function isWSL() {
4
+ if (process.env.WSL_DISTRO_NAME !== void 0) {
5
+ return true;
6
+ }
7
+ try {
8
+ return fs__default.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop");
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+ function detectClipboardCommand() {
14
+ if (process.platform === "darwin") {
15
+ return { command: "pbcopy", args: [] };
16
+ }
17
+ if (process.platform === "win32") {
18
+ return { command: "clip.exe", args: [] };
19
+ }
20
+ if (process.platform === "linux") {
21
+ if (isWSL()) {
22
+ return { command: "clip.exe", args: [] };
23
+ }
24
+ if (process.env.WAYLAND_DISPLAY) {
25
+ return { command: "wl-copy", args: [] };
26
+ }
27
+ if (process.env.DISPLAY) {
28
+ return { command: "xclip", args: ["-selection", "clipboard"] };
29
+ }
30
+ }
31
+ return null;
32
+ }
33
+ function copyToClipboard(text) {
34
+ const clipboardCmd = detectClipboardCommand();
35
+ if (!clipboardCmd) {
36
+ return Promise.resolve({ success: false, error: "No clipboard command available" });
37
+ }
38
+ return new Promise((resolve) => {
39
+ const child = execFile(clipboardCmd.command, clipboardCmd.args, (error) => {
40
+ if (error) {
41
+ resolve({ success: false, error: error.message });
42
+ } else {
43
+ resolve({ success: true });
44
+ }
45
+ });
46
+ if (child.stdin) {
47
+ child.stdin.write(text);
48
+ child.stdin.end();
49
+ }
50
+ });
51
+ }
52
+ export {
53
+ copyToClipboard,
54
+ detectClipboardCommand
55
+ };
56
+ //# sourceMappingURL=clipboard-KXwFSJ4w.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipboard-KXwFSJ4w.js","sources":["../../src/utils/clipboard.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport fs from \"node:fs\";\n\nexport interface ClipboardCommand {\n command: string;\n args: string[];\n}\n\nexport interface ClipboardResult {\n success: boolean;\n error?: string;\n}\n\n/**\n * Detect if running in Windows Subsystem for Linux (WSL)\n */\nfunction isWSL(): boolean {\n if (process.env.WSL_DISTRO_NAME !== undefined) {\n return true;\n }\n try {\n return fs.existsSync(\"/proc/sys/fs/binfmt_misc/WSLInterop\");\n } catch {\n return false;\n }\n}\n\n/**\n * Detect available system clipboard command.\n * Detection order: pbcopy (macOS) → clip.exe (WSL) → wl-copy (Wayland) → xclip (X11)\n */\nexport function detectClipboardCommand(): ClipboardCommand | null {\n if (process.platform === \"darwin\") {\n return { command: \"pbcopy\", args: [] };\n }\n\n if (process.platform === \"win32\") {\n return { command: \"clip.exe\", args: [] };\n }\n\n if (process.platform === \"linux\") {\n if (isWSL()) {\n return { command: \"clip.exe\", args: [] };\n }\n if (process.env.WAYLAND_DISPLAY) {\n return { command: \"wl-copy\", args: [] };\n }\n if (process.env.DISPLAY) {\n return { command: \"xclip\", args: [\"-selection\", \"clipboard\"] };\n }\n }\n\n return null;\n}\n\n/**\n * Copy text to system clipboard.\n * Returns success status and optional error message.\n */\nexport function copyToClipboard(text: string): Promise<ClipboardResult> {\n const clipboardCmd = detectClipboardCommand();\n if (!clipboardCmd) {\n return Promise.resolve({ success: false, error: \"No clipboard command available\" });\n }\n\n return new Promise<ClipboardResult>((resolve) => {\n const child = execFile(clipboardCmd.command, clipboardCmd.args, (error: Error | null) => {\n if (error) {\n resolve({ success: false, error: error.message });\n } else {\n resolve({ success: true });\n }\n });\n\n if (child.stdin) {\n child.stdin.write(text);\n child.stdin.end();\n }\n });\n}\n"],"names":["fs"],"mappings":";;AAgBA,SAAS,QAAiB;AACxB,MAAI,QAAQ,IAAI,oBAAoB,QAAW;AAC7C,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAOA,YAAG,WAAW,qCAAqC;AAAA,EAC5D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,yBAAkD;AAChE,MAAI,QAAQ,aAAa,UAAU;AACjC,WAAO,EAAE,SAAS,UAAU,MAAM,CAAA,EAAC;AAAA,EACrC;AAEA,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO,EAAE,SAAS,YAAY,MAAM,CAAA,EAAC;AAAA,EACvC;AAEA,MAAI,QAAQ,aAAa,SAAS;AAChC,QAAI,SAAS;AACX,aAAO,EAAE,SAAS,YAAY,MAAM,CAAA,EAAC;AAAA,IACvC;AACA,QAAI,QAAQ,IAAI,iBAAiB;AAC/B,aAAO,EAAE,SAAS,WAAW,MAAM,CAAA,EAAC;AAAA,IACtC;AACA,QAAI,QAAQ,IAAI,SAAS;AACvB,aAAO,EAAE,SAAS,SAAS,MAAM,CAAC,cAAc,WAAW,EAAA;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,gBAAgB,MAAwC;AACtE,QAAM,eAAe,uBAAA;AACrB,MAAI,CAAC,cAAc;AACjB,WAAO,QAAQ,QAAQ,EAAE,SAAS,OAAO,OAAO,kCAAkC;AAAA,EACpF;AAEA,SAAO,IAAI,QAAyB,CAAC,YAAY;AAC/C,UAAM,QAAQ,SAAS,aAAa,SAAS,aAAa,MAAM,CAAC,UAAwB;AACvF,UAAI,OAAO;AACT,gBAAQ,EAAE,SAAS,OAAO,OAAO,MAAM,SAAS;AAAA,MAClD,OAAO;AACL,gBAAQ,EAAE,SAAS,MAAM;AAAA,MAC3B;AAAA,IACF,CAAC;AAED,QAAI,MAAM,OAAO;AACf,YAAM,MAAM,MAAM,IAAI;AACtB,YAAM,MAAM,IAAA;AAAA,IACd;AAAA,EACF,CAAC;AACH;"}
@@ -1,4 +1,4 @@
1
- import { j as jsxRuntimeExports } from "./index-CqrsgD_G.js";
1
+ import { j as jsxRuntimeExports } from "./index-BPhIwqHO.js";
2
2
  import { useFocus, useStdout, useInput, Box, Text } from "ink";
3
3
  import { useState, useMemo, useEffect, useCallback } from "react";
4
4
  const ANSI_BACKGROUND_OFFSET = 10;
@@ -931,4 +931,4 @@ export {
931
931
  calculateEffectiveLimit as c,
932
932
  formatAuthors as f
933
933
  };
934
- //# sourceMappingURL=format-CduFas9k.js.map
934
+ //# sourceMappingURL=format-B52BI__9.js.map