@ncukondo/reference-manager 0.15.0 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ import * as path from "node:path";
8
8
  import path__default, { extname, join, basename, dirname } from "node:path";
9
9
  import fs__default, { stat, rename, copyFile, readFile, unlink, readdir, mkdir, rm } from "node:fs/promises";
10
10
  import { g as getExtension, i as isValidFulltextFiles, a as isReservedRole, F as FULLTEXT_ROLE, b as formatToExtension, c as findFulltextFiles, d as findFulltextFile, e as extensionToFormat, B as BUILTIN_STYLES, h as getFulltextAttachmentTypes, s as startServerWithFileWatcher } from "./index-DHgeuWGP.js";
11
- import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-4FFB4igw.js";
11
+ import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-DStZe-OB.js";
12
12
  import { spawn, spawnSync } from "node:child_process";
13
13
  import process$1, { stdin, stdout } from "node:process";
14
14
  import { parse as parse$2, stringify as stringify$2 } from "@iarna/toml";
@@ -17,7 +17,7 @@ import "@citation-js/plugin-csl";
17
17
  import { ZodOptional as ZodOptional$2, z } from "zod";
18
18
  import { serve } from "@hono/node-server";
19
19
  const name = "@ncukondo/reference-manager";
20
- const version$1 = "0.15.0";
20
+ const version$1 = "0.15.2";
21
21
  const description$1 = "A local reference management tool using CSL-JSON as the single source of truth";
22
22
  const packageJson = {
23
23
  name,
@@ -903,27 +903,27 @@ class OperationsLibrary {
903
903
  }
904
904
  // Attachment operations
905
905
  async attachAdd(options) {
906
- const { addAttachment: addAttachment2 } = await import("./index-B_WCu-ZQ.js");
906
+ const { addAttachment: addAttachment2 } = await import("./index-C30Ouuee.js");
907
907
  return addAttachment2(this.library, options);
908
908
  }
909
909
  async attachList(options) {
910
- const { listAttachments: listAttachments2 } = await import("./index-B_WCu-ZQ.js");
910
+ const { listAttachments: listAttachments2 } = await import("./index-C30Ouuee.js");
911
911
  return listAttachments2(this.library, options);
912
912
  }
913
913
  async attachGet(options) {
914
- const { getAttachment: getAttachment2 } = await import("./index-B_WCu-ZQ.js");
914
+ const { getAttachment: getAttachment2 } = await import("./index-C30Ouuee.js");
915
915
  return getAttachment2(this.library, options);
916
916
  }
917
917
  async attachDetach(options) {
918
- const { detachAttachment: detachAttachment2 } = await import("./index-B_WCu-ZQ.js");
918
+ const { detachAttachment: detachAttachment2 } = await import("./index-C30Ouuee.js");
919
919
  return detachAttachment2(this.library, options);
920
920
  }
921
921
  async attachSync(options) {
922
- const { syncAttachments: syncAttachments2 } = await import("./index-B_WCu-ZQ.js");
922
+ const { syncAttachments: syncAttachments2 } = await import("./index-C30Ouuee.js");
923
923
  return syncAttachments2(this.library, options);
924
924
  }
925
925
  async attachOpen(options) {
926
- const { openAttachment: openAttachment2 } = await import("./index-B_WCu-ZQ.js");
926
+ const { openAttachment: openAttachment2 } = await import("./index-C30Ouuee.js");
927
927
  return openAttachment2(this.library, options);
928
928
  }
929
929
  }
@@ -1375,6 +1375,24 @@ async function readStdinBuffer() {
1375
1375
  }
1376
1376
  return Buffer.concat(chunks);
1377
1377
  }
1378
+ const ExitCode = {
1379
+ /** Success */
1380
+ SUCCESS: 0,
1381
+ /** General error (e.g., not found, validation failed) */
1382
+ ERROR: 1,
1383
+ /** Internal/unexpected error */
1384
+ INTERNAL_ERROR: 4,
1385
+ /** Interrupted by SIGINT */
1386
+ SIGINT: 130
1387
+ };
1388
+ function setExitCode(code2) {
1389
+ process.exitCode = code2;
1390
+ }
1391
+ function exitWithError(message, code2 = ExitCode.ERROR) {
1392
+ process.stderr.write(`Error: ${message}
1393
+ `);
1394
+ setExitCode(code2);
1395
+ }
1378
1396
  async function executeAttachOpen(options, context) {
1379
1397
  const operationOptions = {
1380
1398
  identifier: options.identifier,
@@ -1545,12 +1563,16 @@ function formatAttachSyncOutput(result) {
1545
1563
  const lines = [];
1546
1564
  formatNewFilesSection(result, lines);
1547
1565
  formatMissingFilesSection(result, lines);
1548
- if (!result.applied) {
1566
+ if (result.applied) {
1567
+ lines.push("Changes applied.");
1568
+ } else {
1569
+ lines.push("");
1570
+ lines.push("(dry-run: no changes made)");
1549
1571
  if (hasNewFiles) {
1550
1572
  lines.push("Run with --yes to add new files");
1551
1573
  }
1552
1574
  if (hasMissingFiles) {
1553
- lines.push("Run with --fix to remove missing files");
1575
+ lines.push("Run with --fix to remove missing files from metadata");
1554
1576
  }
1555
1577
  }
1556
1578
  return lines.join("\n").trimEnd();
@@ -1580,7 +1602,8 @@ async function resolveIdentifier(identifierArg, context, config2) {
1580
1602
  process.stderr.write(
1581
1603
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
1582
1604
  );
1583
- process.exit(1);
1605
+ setExitCode(ExitCode.ERROR);
1606
+ return "";
1584
1607
  }
1585
1608
  return stdinId;
1586
1609
  }
@@ -1604,6 +1627,9 @@ async function waitForEnter() {
1604
1627
  process.stderr.write("Press Enter when done editing...");
1605
1628
  process.stdin.setRawMode(true);
1606
1629
  process.stdin.resume();
1630
+ if (typeof process.stdin.ref === "function") {
1631
+ process.stdin.ref();
1632
+ }
1607
1633
  process.stdin.once("data", () => {
1608
1634
  process.stdin.setRawMode(false);
1609
1635
  process.stdin.pause();
@@ -1677,12 +1703,13 @@ async function handleAttachOpenAction(identifierArg, filenameArg, options, globa
1677
1703
  if (!result.success) {
1678
1704
  process.stderr.write(`Error: ${result.error}
1679
1705
  `);
1680
- process.exit(1);
1706
+ setExitCode(ExitCode.ERROR);
1707
+ return;
1681
1708
  }
1682
1709
  if (options.print) {
1683
1710
  process.stdout.write(`${result.path}
1684
1711
  `);
1685
- process.exit(0);
1712
+ setExitCode(ExitCode.SUCCESS);
1686
1713
  }
1687
1714
  if (shouldUseInteractive) {
1688
1715
  await runInteractiveMode(
@@ -1696,11 +1723,11 @@ async function handleAttachOpenAction(identifierArg, filenameArg, options, globa
1696
1723
  process.stderr.write(`${formatAttachOpenOutput(result)}
1697
1724
  `);
1698
1725
  }
1699
- process.exit(0);
1726
+ setExitCode(ExitCode.SUCCESS);
1700
1727
  } catch (error) {
1701
1728
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1702
1729
  `);
1703
- process.exit(4);
1730
+ setExitCode(ExitCode.INTERNAL_ERROR);
1704
1731
  }
1705
1732
  }
1706
1733
  async function handleAttachAddAction(identifierArg, filePathArg, options, globalOpts) {
@@ -1722,11 +1749,11 @@ async function handleAttachAddAction(identifierArg, filePathArg, options, global
1722
1749
  const output = formatAttachAddOutput(result);
1723
1750
  process.stderr.write(`${output}
1724
1751
  `);
1725
- process.exit(getAttachExitCode(result));
1752
+ setExitCode(getAttachExitCode(result));
1726
1753
  } catch (error) {
1727
1754
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1728
1755
  `);
1729
- process.exit(4);
1756
+ setExitCode(ExitCode.INTERNAL_ERROR);
1730
1757
  }
1731
1758
  }
1732
1759
  async function handleAttachListAction(identifierArg, options, globalOpts) {
@@ -1744,11 +1771,11 @@ async function handleAttachListAction(identifierArg, options, globalOpts) {
1744
1771
  const output = formatAttachListOutput(result, identifier);
1745
1772
  process.stdout.write(`${output}
1746
1773
  `);
1747
- process.exit(getAttachExitCode(result));
1774
+ setExitCode(getAttachExitCode(result));
1748
1775
  } catch (error) {
1749
1776
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1750
1777
  `);
1751
- process.exit(4);
1778
+ setExitCode(ExitCode.INTERNAL_ERROR);
1752
1779
  }
1753
1780
  }
1754
1781
  async function handleAttachGetAction(identifierArg, filenameArg, options, globalOpts) {
@@ -1774,11 +1801,11 @@ async function handleAttachGetAction(identifierArg, filenameArg, options, global
1774
1801
  process.stderr.write(`Error: ${result.error}
1775
1802
  `);
1776
1803
  }
1777
- process.exit(getAttachExitCode(result));
1804
+ setExitCode(getAttachExitCode(result));
1778
1805
  } catch (error) {
1779
1806
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1780
1807
  `);
1781
- process.exit(4);
1808
+ setExitCode(ExitCode.INTERNAL_ERROR);
1782
1809
  }
1783
1810
  }
1784
1811
  async function handleAttachDetachAction(identifierArg, filenameArg, options, globalOpts) {
@@ -1799,34 +1826,75 @@ async function handleAttachDetachAction(identifierArg, filenameArg, options, glo
1799
1826
  const output = formatAttachDetachOutput(result);
1800
1827
  process.stderr.write(`${output}
1801
1828
  `);
1802
- process.exit(getAttachExitCode(result));
1829
+ setExitCode(getAttachExitCode(result));
1803
1830
  } catch (error) {
1804
1831
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1805
1832
  `);
1806
- process.exit(4);
1833
+ setExitCode(ExitCode.INTERNAL_ERROR);
1834
+ }
1835
+ }
1836
+ async function runInteractiveSyncMode(identifier, attachmentsDirectory, idType, context) {
1837
+ const dryRunOptions = {
1838
+ identifier,
1839
+ attachmentsDirectory,
1840
+ ...idType && { idType }
1841
+ };
1842
+ const dryRunResult = await executeAttachSync(dryRunOptions, context);
1843
+ const hasNewFiles = dryRunResult.newFiles.length > 0;
1844
+ const hasMissingFiles = dryRunResult.missingFiles.length > 0;
1845
+ if (!dryRunResult.success || !hasNewFiles && !hasMissingFiles) {
1846
+ process.stderr.write(`${formatAttachSyncOutput(dryRunResult)}
1847
+ `);
1848
+ return;
1807
1849
  }
1850
+ process.stderr.write(`${formatAttachSyncOutput(dryRunResult)}
1851
+
1852
+ `);
1853
+ const shouldApplyNew = hasNewFiles && await readConfirmation("Add new files to metadata?");
1854
+ const shouldApplyFix = hasMissingFiles && shouldApplyNew && await readConfirmation("Remove missing files?");
1855
+ if (!shouldApplyNew && !shouldApplyFix) {
1856
+ process.stderr.write("No changes applied.\n");
1857
+ return;
1858
+ }
1859
+ const applyOptions = {
1860
+ identifier,
1861
+ attachmentsDirectory,
1862
+ ...shouldApplyNew && { yes: true },
1863
+ ...shouldApplyFix && { fix: true },
1864
+ ...idType && { idType }
1865
+ };
1866
+ const result = await executeAttachSync(applyOptions, context);
1867
+ process.stderr.write(`${formatAttachSyncOutput(result)}
1868
+ `);
1808
1869
  }
1809
1870
  async function handleAttachSyncAction(identifierArg, options, globalOpts) {
1810
1871
  try {
1811
1872
  const config2 = await loadConfigWithOverrides({ ...globalOpts, ...options });
1812
1873
  const context = await createExecutionContext(config2, Library.load);
1813
1874
  const identifier = await resolveIdentifier(identifierArg, context, config2);
1875
+ const attachmentsDirectory = config2.attachments.directory;
1876
+ const idType = options.uuid ? "uuid" : void 0;
1877
+ const shouldUseInteractive = isTTY() && !options.yes && !options.fix;
1878
+ if (shouldUseInteractive) {
1879
+ await runInteractiveSyncMode(identifier, attachmentsDirectory, idType, context);
1880
+ setExitCode(ExitCode.SUCCESS);
1881
+ return;
1882
+ }
1814
1883
  const syncOptions = {
1815
1884
  identifier,
1816
- attachmentsDirectory: config2.attachments.directory,
1817
- ...options.yes && { yes: options.yes },
1818
- ...options.fix && { fix: options.fix },
1819
- ...options.uuid && { idType: "uuid" }
1885
+ attachmentsDirectory,
1886
+ ...options.yes && { yes: true },
1887
+ ...options.fix && { fix: true },
1888
+ ...idType && { idType }
1820
1889
  };
1821
1890
  const result = await executeAttachSync(syncOptions, context);
1822
- const output = formatAttachSyncOutput(result);
1823
- process.stderr.write(`${output}
1891
+ process.stderr.write(`${formatAttachSyncOutput(result)}
1824
1892
  `);
1825
- process.exit(getAttachExitCode(result));
1893
+ setExitCode(getAttachExitCode(result));
1826
1894
  } catch (error) {
1827
1895
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1828
1896
  `);
1829
- process.exit(4);
1897
+ setExitCode(ExitCode.INTERNAL_ERROR);
1830
1898
  }
1831
1899
  }
1832
1900
  async function validateOptions$2(options) {
@@ -1900,7 +1968,8 @@ async function executeInteractiveCite(options, context, config2) {
1900
1968
  defaultStyle: config2.citation.defaultStyle
1901
1969
  });
1902
1970
  if (styleResult.cancelled) {
1903
- process.exit(0);
1971
+ setExitCode(ExitCode.SUCCESS);
1972
+ return { results: [] };
1904
1973
  }
1905
1974
  style = styleResult.style;
1906
1975
  }
@@ -1920,7 +1989,8 @@ async function handleCiteAction(identifiers, options, globalOpts) {
1920
1989
  process.stderr.write(
1921
1990
  "Error: No identifiers provided. Provide IDs, pipe them via stdin, or run interactively in a TTY.\n"
1922
1991
  );
1923
- process.exit(1);
1992
+ setExitCode(ExitCode.ERROR);
1993
+ return;
1924
1994
  }
1925
1995
  result = await executeCite({ ...options, identifiers: stdinIds }, context);
1926
1996
  }
@@ -1937,11 +2007,11 @@ async function handleCiteAction(identifiers, options, globalOpts) {
1937
2007
  process.stderr.write(`${errors2}
1938
2008
  `);
1939
2009
  }
1940
- process.exit(getCiteExitCode(result));
2010
+ setExitCode(getCiteExitCode(result));
1941
2011
  } catch (error) {
1942
2012
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1943
2013
  `);
1944
- process.exit(4);
2014
+ setExitCode(ExitCode.INTERNAL_ERROR);
1945
2015
  }
1946
2016
  }
1947
2017
  const ENV_OVERRIDE_MAP = {
@@ -2652,11 +2722,11 @@ function registerConfigCommand(program) {
2652
2722
  });
2653
2723
  process.stdout.write(`${output}
2654
2724
  `);
2655
- process.exit(0);
2725
+ setExitCode(ExitCode.SUCCESS);
2656
2726
  } catch (error) {
2657
2727
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2658
2728
  `);
2659
- process.exit(1);
2729
+ setExitCode(ExitCode.ERROR);
2660
2730
  }
2661
2731
  });
2662
2732
  configCmd.command("get <key>").description("Get a specific configuration value").option("--config-only", "Return only the config file value (ignore env vars)").action(async (key, options) => {
@@ -2674,14 +2744,14 @@ function registerConfigCommand(program) {
2674
2744
  const { formatValue: formatValue2 } = await Promise.resolve().then(() => get);
2675
2745
  process.stdout.write(`${formatValue2(result.value)}
2676
2746
  `);
2677
- process.exit(0);
2747
+ setExitCode(ExitCode.SUCCESS);
2678
2748
  } else {
2679
- process.exit(1);
2749
+ setExitCode(ExitCode.ERROR);
2680
2750
  }
2681
2751
  } catch (error) {
2682
2752
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2683
2753
  `);
2684
- process.exit(1);
2754
+ setExitCode(ExitCode.ERROR);
2685
2755
  }
2686
2756
  });
2687
2757
  configCmd.command("set <key> <value>").description("Set a configuration value").option("--local", "Write to current directory config (create if not exists)").option("--user", "Write to user config (ignore local config even if exists)").action(async (key, value, options) => {
@@ -2699,17 +2769,18 @@ function registerConfigCommand(program) {
2699
2769
  if (!result.success) {
2700
2770
  process.stderr.write(`Error: ${result.error}
2701
2771
  `);
2702
- process.exit(1);
2772
+ setExitCode(ExitCode.ERROR);
2773
+ return;
2703
2774
  }
2704
2775
  if (result.warning) {
2705
2776
  process.stderr.write(`${result.warning}
2706
2777
  `);
2707
2778
  }
2708
- process.exit(0);
2779
+ setExitCode(ExitCode.SUCCESS);
2709
2780
  } catch (error) {
2710
2781
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2711
2782
  `);
2712
- process.exit(1);
2783
+ setExitCode(ExitCode.ERROR);
2713
2784
  }
2714
2785
  });
2715
2786
  configCmd.command("unset <key>").description("Remove a configuration value (revert to default)").option("--local", "Remove from current directory config").option("--user", "Remove from user config (ignore local config even if exists)").action(async (key, options) => {
@@ -2724,13 +2795,14 @@ function registerConfigCommand(program) {
2724
2795
  if (!result.success) {
2725
2796
  process.stderr.write(`Error: ${result.error}
2726
2797
  `);
2727
- process.exit(1);
2798
+ setExitCode(ExitCode.ERROR);
2799
+ return;
2728
2800
  }
2729
- process.exit(0);
2801
+ setExitCode(ExitCode.SUCCESS);
2730
2802
  } catch (error) {
2731
2803
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2732
2804
  `);
2733
- process.exit(1);
2805
+ setExitCode(ExitCode.ERROR);
2734
2806
  }
2735
2807
  });
2736
2808
  configCmd.command("keys").description("List all available configuration keys").option("--section <name>", "List keys only in a specific section").action(async (options) => {
@@ -2740,11 +2812,11 @@ function registerConfigCommand(program) {
2740
2812
  process.stdout.write(`${output}
2741
2813
  `);
2742
2814
  }
2743
- process.exit(0);
2815
+ setExitCode(ExitCode.SUCCESS);
2744
2816
  } catch (error) {
2745
2817
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2746
2818
  `);
2747
- process.exit(1);
2819
+ setExitCode(ExitCode.ERROR);
2748
2820
  }
2749
2821
  });
2750
2822
  configCmd.command("path").description("Show configuration file paths").option("--user", "Show only user config path").option("--local", "Show only local config path").action(async (options) => {
@@ -2752,18 +2824,19 @@ function registerConfigCommand(program) {
2752
2824
  const output = showConfigPaths({ user: options.user, local: options.local });
2753
2825
  process.stdout.write(`${output}
2754
2826
  `);
2755
- process.exit(0);
2827
+ setExitCode(ExitCode.SUCCESS);
2756
2828
  } catch (error) {
2757
2829
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2758
2830
  `);
2759
- process.exit(1);
2831
+ setExitCode(ExitCode.ERROR);
2760
2832
  }
2761
2833
  });
2762
2834
  configCmd.command("edit").description("Open configuration file in editor").option("--local", "Edit current directory config").action(async (options) => {
2763
2835
  try {
2764
2836
  if (!process.stdin.isTTY) {
2765
2837
  process.stderr.write("Error: config edit requires a terminal (TTY)\n");
2766
- process.exit(1);
2838
+ setExitCode(ExitCode.ERROR);
2839
+ return;
2767
2840
  }
2768
2841
  const target = getConfigEditTarget({ local: options.local });
2769
2842
  if (!target.exists) {
@@ -2773,11 +2846,11 @@ function registerConfigCommand(program) {
2773
2846
  }
2774
2847
  const editor = resolveEditor();
2775
2848
  const exitCode = openEditor(editor, target.path);
2776
- process.exit(exitCode);
2849
+ setExitCode(exitCode);
2777
2850
  } catch (error) {
2778
2851
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2779
2852
  `);
2780
- process.exit(1);
2853
+ setExitCode(ExitCode.ERROR);
2781
2854
  }
2782
2855
  });
2783
2856
  }
@@ -5748,7 +5821,7 @@ async function handleEditAction(identifiers, options, globalOpts) {
5748
5821
  const output2 = formatEditOutput(result2);
5749
5822
  process.stderr.write(`${output2}
5750
5823
  `);
5751
- process.exit(result2.success ? 0 : 1);
5824
+ setExitCode(result2.success ? ExitCode.SUCCESS : ExitCode.ERROR);
5752
5825
  return;
5753
5826
  } else {
5754
5827
  const stdinIds = await readIdentifiersFromStdin();
@@ -5756,13 +5829,15 @@ async function handleEditAction(identifiers, options, globalOpts) {
5756
5829
  process.stderr.write(
5757
5830
  "Error: No identifiers provided. Provide IDs, pipe them via stdin, or run interactively in a TTY.\n"
5758
5831
  );
5759
- process.exit(1);
5832
+ setExitCode(ExitCode.ERROR);
5833
+ return;
5760
5834
  }
5761
5835
  resolvedIdentifiers = stdinIds;
5762
5836
  }
5763
5837
  if (!isTTY()) {
5764
5838
  process.stderr.write("Error: Edit command requires a TTY to open the editor.\n");
5765
- process.exit(1);
5839
+ setExitCode(ExitCode.ERROR);
5840
+ return;
5766
5841
  }
5767
5842
  const format2 = options.format ?? config2.cli.edit.defaultFormat;
5768
5843
  const result = await executeEditCommand(
@@ -5777,11 +5852,11 @@ async function handleEditAction(identifiers, options, globalOpts) {
5777
5852
  const output = formatEditOutput(result);
5778
5853
  process.stderr.write(`${output}
5779
5854
  `);
5780
- process.exit(result.success ? 0 : 1);
5855
+ setExitCode(result.success ? ExitCode.SUCCESS : ExitCode.ERROR);
5781
5856
  } catch (error) {
5782
5857
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
5783
5858
  `);
5784
- process.exit(4);
5859
+ setExitCode(ExitCode.INTERNAL_ERROR);
5785
5860
  }
5786
5861
  }
5787
5862
  const ALIAS = Symbol.for("yaml.alias");
@@ -9401,7 +9476,8 @@ async function handleFulltextAttachAction(identifierArg, filePathArg, options, g
9401
9476
  process.stderr.write(
9402
9477
  "Error: No identifier provided. Provide an ID or run interactively in a TTY.\n"
9403
9478
  );
9404
- process.exit(1);
9479
+ setExitCode(ExitCode.ERROR);
9480
+ return;
9405
9481
  }
9406
9482
  identifier = await executeInteractiveSelect(context, config2);
9407
9483
  }
@@ -9421,11 +9497,11 @@ async function handleFulltextAttachAction(identifierArg, filePathArg, options, g
9421
9497
  const output = formatFulltextAttachOutput(result);
9422
9498
  process.stderr.write(`${output}
9423
9499
  `);
9424
- process.exit(getFulltextExitCode(result));
9500
+ setExitCode(getFulltextExitCode(result));
9425
9501
  } catch (error) {
9426
9502
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9427
9503
  `);
9428
- process.exit(4);
9504
+ setExitCode(ExitCode.INTERNAL_ERROR);
9429
9505
  }
9430
9506
  }
9431
9507
  function outputFulltextGetResult(result, useStdout) {
@@ -9457,7 +9533,8 @@ async function handleFulltextGetAction(identifierArg, options, globalOpts) {
9457
9533
  process.stderr.write(
9458
9534
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
9459
9535
  );
9460
- process.exit(1);
9536
+ setExitCode(ExitCode.ERROR);
9537
+ return;
9461
9538
  }
9462
9539
  identifier = stdinId;
9463
9540
  }
@@ -9471,11 +9548,11 @@ async function handleFulltextGetAction(identifierArg, options, globalOpts) {
9471
9548
  };
9472
9549
  const result = await executeFulltextGet(getOptions, context);
9473
9550
  outputFulltextGetResult(result, Boolean(options.stdout));
9474
- process.exit(getFulltextExitCode(result));
9551
+ setExitCode(getFulltextExitCode(result));
9475
9552
  } catch (error) {
9476
9553
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9477
9554
  `);
9478
- process.exit(4);
9555
+ setExitCode(ExitCode.INTERNAL_ERROR);
9479
9556
  }
9480
9557
  }
9481
9558
  async function handleFulltextDetachAction(identifierArg, options, globalOpts) {
@@ -9493,7 +9570,8 @@ async function handleFulltextDetachAction(identifierArg, options, globalOpts) {
9493
9570
  process.stderr.write(
9494
9571
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
9495
9572
  );
9496
- process.exit(1);
9573
+ setExitCode(ExitCode.ERROR);
9574
+ return;
9497
9575
  }
9498
9576
  identifier = stdinId;
9499
9577
  }
@@ -9510,11 +9588,11 @@ async function handleFulltextDetachAction(identifierArg, options, globalOpts) {
9510
9588
  const output = formatFulltextDetachOutput(result);
9511
9589
  process.stderr.write(`${output}
9512
9590
  `);
9513
- process.exit(getFulltextExitCode(result));
9591
+ setExitCode(getFulltextExitCode(result));
9514
9592
  } catch (error) {
9515
9593
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9516
9594
  `);
9517
- process.exit(4);
9595
+ setExitCode(ExitCode.INTERNAL_ERROR);
9518
9596
  }
9519
9597
  }
9520
9598
  async function handleFulltextOpenAction(identifierArg, options, globalOpts) {
@@ -9532,7 +9610,8 @@ async function handleFulltextOpenAction(identifierArg, options, globalOpts) {
9532
9610
  process.stderr.write(
9533
9611
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
9534
9612
  );
9535
- process.exit(1);
9613
+ setExitCode(ExitCode.ERROR);
9614
+ return;
9536
9615
  }
9537
9616
  identifier = stdinId;
9538
9617
  }
@@ -9547,11 +9626,11 @@ async function handleFulltextOpenAction(identifierArg, options, globalOpts) {
9547
9626
  const output = formatFulltextOpenOutput(result);
9548
9627
  process.stderr.write(`${output}
9549
9628
  `);
9550
- process.exit(getFulltextExitCode(result));
9629
+ setExitCode(getFulltextExitCode(result));
9551
9630
  } catch (error) {
9552
9631
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9553
9632
  `);
9554
- process.exit(4);
9633
+ setExitCode(ExitCode.INTERNAL_ERROR);
9555
9634
  }
9556
9635
  }
9557
9636
  function formatAuthor(author) {
@@ -30480,7 +30559,7 @@ function handleRemoveError(error, identifierArg, outputFormat) {
30480
30559
  `);
30481
30560
  }
30482
30561
  const isUserError = message.includes("not found") || message.includes("No identifier");
30483
- process.exit(isUserError ? 1 : 4);
30562
+ setExitCode(isUserError ? ExitCode.ERROR : ExitCode.INTERNAL_ERROR);
30484
30563
  }
30485
30564
  async function handleRemoveAction(identifierArg, options, globalOpts) {
30486
30565
  const { formatRemoveJsonOutput: formatRemoveJsonOutput2 } = await Promise.resolve().then(() => jsonOutput);
@@ -30501,12 +30580,14 @@ async function handleRemoveAction(identifierArg, options, globalOpts) {
30501
30580
  if (hasFulltext && !isTTY() && !force) {
30502
30581
  process.stderr.write(`Error: ${formatFulltextWarning(fulltextTypes)}
30503
30582
  `);
30504
- process.exit(1);
30583
+ setExitCode(ExitCode.ERROR);
30584
+ return;
30505
30585
  }
30506
30586
  const confirmed = await confirmRemoveIfNeeded(refToRemove, hasFulltext, force);
30507
30587
  if (!confirmed) {
30508
30588
  process.stderr.write("Cancelled.\n");
30509
- process.exit(2);
30589
+ setExitCode(2);
30590
+ return;
30510
30591
  }
30511
30592
  const removeOptions = {
30512
30593
  identifier,
@@ -30516,7 +30597,7 @@ async function handleRemoveAction(identifierArg, options, globalOpts) {
30516
30597
  };
30517
30598
  const result = await executeRemove(removeOptions, context);
30518
30599
  outputResult(result, identifier, outputFormat, options.full, formatRemoveJsonOutput2);
30519
- process.exit(result.removed ? 0 : 1);
30600
+ setExitCode(result.removed ? ExitCode.SUCCESS : ExitCode.ERROR);
30520
30601
  } catch (error) {
30521
30602
  handleRemoveError(error, identifierArg, outputFormat);
30522
30603
  }
@@ -30628,7 +30709,7 @@ async function executeInteractiveSearch(options, context, config2) {
30628
30709
  validateInteractiveOptions(options);
30629
30710
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
30630
30711
  const { runSearchPrompt } = await import("./search-prompt-BrWpOcij.js");
30631
- const { runActionMenu } = await import("./action-menu-DvwR6nMj.js");
30712
+ const { runActionMenu } = await import("./action-menu-CLBXtpmg.js");
30632
30713
  const { search } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.y);
30633
30714
  const { tokenize } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.x);
30634
30715
  checkTTY();
@@ -30706,7 +30787,7 @@ async function startServerForeground(options) {
30706
30787
  server.close();
30707
30788
  await dispose();
30708
30789
  await removePortfile(options.portfilePath);
30709
- process.exit(0);
30790
+ setExitCode(ExitCode.SUCCESS);
30710
30791
  };
30711
30792
  process.on("SIGINT", cleanup);
30712
30793
  process.on("SIGTERM", cleanup);
@@ -30958,14 +31039,16 @@ async function resolveUpdateIdentifier(identifierArg, hasSetOptions, context, co
30958
31039
  process.stderr.write(
30959
31040
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
30960
31041
  );
30961
- process.exit(1);
31042
+ setExitCode(ExitCode.ERROR);
31043
+ return "";
30962
31044
  }
30963
31045
  return stdinId;
30964
31046
  }
30965
31047
  process.stderr.write(
30966
31048
  "Error: No identifier provided. When using stdin for JSON input, identifier must be provided as argument.\n"
30967
31049
  );
30968
- process.exit(1);
31050
+ setExitCode(ExitCode.ERROR);
31051
+ return "";
30969
31052
  }
30970
31053
  function parseUpdateInput(setOptions, file) {
30971
31054
  if (setOptions && setOptions.length > 0 && file) {
@@ -30986,23 +31069,25 @@ function handleUpdateError(error) {
30986
31069
  if (message.includes("Parse error")) {
30987
31070
  process.stderr.write(`Error: ${message}
30988
31071
  `);
30989
- process.exit(3);
31072
+ setExitCode(3);
30990
31073
  }
30991
31074
  if (message.includes("not found") || message.includes("validation")) {
30992
31075
  process.stderr.write(`Error: ${message}
30993
31076
  `);
30994
- process.exit(1);
31077
+ setExitCode(ExitCode.ERROR);
30995
31078
  }
30996
31079
  process.stderr.write(`Error: ${message}
30997
31080
  `);
30998
- process.exit(4);
31081
+ setExitCode(ExitCode.INTERNAL_ERROR);
30999
31082
  }
31000
31083
  function handleUpdateErrorWithFormat(error, identifier, outputFormat) {
31001
31084
  const message = error instanceof Error ? error.message : String(error);
31002
31085
  if (outputFormat === "json") {
31003
31086
  process.stdout.write(`${JSON.stringify({ success: false, id: identifier, error: message })}
31004
31087
  `);
31005
- process.exit(message.includes("not found") || message.includes("validation") ? 1 : 4);
31088
+ setExitCode(
31089
+ message.includes("not found") || message.includes("validation") ? ExitCode.ERROR : ExitCode.INTERNAL_ERROR
31090
+ );
31006
31091
  }
31007
31092
  handleUpdateError(error);
31008
31093
  }
@@ -31036,7 +31121,7 @@ async function handleUpdateAction(identifierArg, file, options, globalOpts) {
31036
31121
  process.stderr.write(`${output}
31037
31122
  `);
31038
31123
  }
31039
- process.exit(result.updated ? 0 : 1);
31124
+ setExitCode(result.updated ? ExitCode.SUCCESS : ExitCode.ERROR);
31040
31125
  } catch (error) {
31041
31126
  handleUpdateErrorWithFormat(error, identifierArg ?? "", outputFormat);
31042
31127
  }
@@ -31321,7 +31406,7 @@ function registerCompletionCommand(program) {
31321
31406
  } else {
31322
31407
  console.error(`Unknown action: ${action}`);
31323
31408
  console.error("Usage: ref completion [install|uninstall]");
31324
- process.exit(1);
31409
+ setExitCode(ExitCode.ERROR);
31325
31410
  }
31326
31411
  });
31327
31412
  }
@@ -31356,11 +31441,9 @@ async function handleListAction(options, program) {
31356
31441
  process.stdout.write(`${output}
31357
31442
  `);
31358
31443
  }
31359
- process.exit(0);
31444
+ setExitCode(ExitCode.SUCCESS);
31360
31445
  } catch (error) {
31361
- process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31362
- `);
31363
- process.exit(4);
31446
+ exitWithError(error instanceof Error ? error.message : String(error), ExitCode.INTERNAL_ERROR);
31364
31447
  }
31365
31448
  }
31366
31449
  function registerListCommand(program) {
@@ -31385,11 +31468,11 @@ async function handleExportAction(ids, options, program) {
31385
31468
  `);
31386
31469
  }
31387
31470
  }
31388
- process.exit(getExportExitCode(result));
31471
+ setExitCode(getExportExitCode(result));
31389
31472
  } catch (error) {
31390
31473
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31391
31474
  `);
31392
- process.exit(4);
31475
+ setExitCode(ExitCode.INTERNAL_ERROR);
31393
31476
  }
31394
31477
  }
31395
31478
  function registerExportCommand(program) {
@@ -31408,7 +31491,7 @@ async function handleSearchAction(query, options, program) {
31408
31491
  process.stdout.write(`${result2.output}
31409
31492
  `);
31410
31493
  }
31411
- process.exit(result2.cancelled ? 0 : 0);
31494
+ setExitCode(ExitCode.SUCCESS);
31412
31495
  }
31413
31496
  const result = await executeSearch({ ...options, query }, context);
31414
31497
  const output = formatSearchOutput(result, { ...options, query });
@@ -31416,18 +31499,19 @@ async function handleSearchAction(query, options, program) {
31416
31499
  process.stdout.write(`${output}
31417
31500
  `);
31418
31501
  }
31419
- process.exit(0);
31502
+ setExitCode(ExitCode.SUCCESS);
31420
31503
  } catch (error) {
31421
31504
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31422
31505
  `);
31423
- process.exit(4);
31506
+ setExitCode(ExitCode.INTERNAL_ERROR);
31424
31507
  }
31425
31508
  }
31426
31509
  function registerSearchCommand(program) {
31427
31510
  program.command("search").description("Search references").argument("[query]", "Search query (required unless using --tui)").option("-t, --tui", "Enable TUI (interactive) search mode").option("-o, --output <format>", "Output format: pretty|json|bibtex|ids|uuid").option("--json", "Alias for --output json").option("--bibtex", "Alias for --output bibtex").option("--ids-only", "Alias for --output ids").option("--uuid-only", "Alias for --output uuid").option("--sort <field>", "Sort by field: created|updated|published|author|title|relevance").option("--order <order>", "Sort order: asc|desc").option("-n, --limit <n>", "Maximum number of results", Number.parseInt).option("--offset <n>", "Number of results to skip", Number.parseInt).action(async (query, options) => {
31428
31511
  if (!options.tui && !query) {
31429
31512
  process.stderr.write("Error: Search query is required unless using --tui\n");
31430
- process.exit(1);
31513
+ setExitCode(ExitCode.ERROR);
31514
+ return;
31431
31515
  }
31432
31516
  await handleSearchAction(query ?? "", options, program);
31433
31517
  });
@@ -31492,7 +31576,7 @@ async function handleAddAction(inputs, options, program) {
31492
31576
  process.stderr.write(`${output}
31493
31577
  `);
31494
31578
  }
31495
- process.exit(getExitCode(result));
31579
+ setExitCode(getExitCode(result));
31496
31580
  } catch (error) {
31497
31581
  const message = error instanceof Error ? error.message : String(error);
31498
31582
  if (outputFormat === "json") {
@@ -31502,7 +31586,7 @@ async function handleAddAction(inputs, options, program) {
31502
31586
  process.stderr.write(`Error: ${message}
31503
31587
  `);
31504
31588
  }
31505
- process.exit(1);
31589
+ setExitCode(ExitCode.ERROR);
31506
31590
  }
31507
31591
  }
31508
31592
  function registerAddCommand(program) {
@@ -31552,18 +31636,18 @@ function registerServerCommand(program) {
31552
31636
  };
31553
31637
  await serverStart(startOptions);
31554
31638
  if (options.daemon) {
31555
- process.exit(0);
31639
+ setExitCode(ExitCode.SUCCESS);
31556
31640
  }
31557
31641
  } catch (error) {
31558
31642
  const message = error instanceof Error ? error.message : String(error);
31559
31643
  if (message.includes("already running") || message.includes("conflict")) {
31560
31644
  process.stderr.write(`Error: ${message}
31561
31645
  `);
31562
- process.exit(1);
31646
+ setExitCode(ExitCode.ERROR);
31563
31647
  }
31564
31648
  process.stderr.write(`Error: ${message}
31565
31649
  `);
31566
- process.exit(4);
31650
+ setExitCode(ExitCode.INTERNAL_ERROR);
31567
31651
  }
31568
31652
  });
31569
31653
  serverCmd.command("stop").description("Stop running server").action(async () => {
@@ -31571,17 +31655,17 @@ function registerServerCommand(program) {
31571
31655
  const portfilePath = getPortfilePath();
31572
31656
  await serverStop(portfilePath);
31573
31657
  process.stderr.write("Server stopped.\n");
31574
- process.exit(0);
31658
+ setExitCode(ExitCode.SUCCESS);
31575
31659
  } catch (error) {
31576
31660
  const message = error instanceof Error ? error.message : String(error);
31577
31661
  if (message.includes("not running")) {
31578
31662
  process.stderr.write(`Error: ${message}
31579
31663
  `);
31580
- process.exit(1);
31664
+ setExitCode(ExitCode.ERROR);
31581
31665
  }
31582
31666
  process.stderr.write(`Error: ${message}
31583
31667
  `);
31584
- process.exit(4);
31668
+ setExitCode(ExitCode.INTERNAL_ERROR);
31585
31669
  }
31586
31670
  });
31587
31671
  serverCmd.command("status").description("Check server status").action(async () => {
@@ -31596,15 +31680,15 @@ PID: ${status.pid}
31596
31680
  Library: ${status.library}
31597
31681
  `
31598
31682
  );
31599
- process.exit(0);
31683
+ setExitCode(ExitCode.SUCCESS);
31600
31684
  } else {
31601
31685
  process.stdout.write("Server not running\n");
31602
- process.exit(1);
31686
+ setExitCode(ExitCode.ERROR);
31603
31687
  }
31604
31688
  } catch (error) {
31605
31689
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31606
31690
  `);
31607
- process.exit(4);
31691
+ setExitCode(ExitCode.INTERNAL_ERROR);
31608
31692
  }
31609
31693
  });
31610
31694
  }
@@ -31633,7 +31717,7 @@ function registerMcpCommand(program) {
31633
31717
  } catch (error) {
31634
31718
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31635
31719
  `);
31636
- process.exit(1);
31720
+ setExitCode(ExitCode.ERROR);
31637
31721
  }
31638
31722
  });
31639
31723
  }
@@ -31683,10 +31767,10 @@ async function main(argv) {
31683
31767
  return;
31684
31768
  }
31685
31769
  process.on("SIGINT", () => {
31686
- process.exit(130);
31770
+ setExitCode(ExitCode.SIGINT);
31687
31771
  });
31688
31772
  process.on("SIGTERM", () => {
31689
- process.exit(0);
31773
+ setExitCode(ExitCode.SUCCESS);
31690
31774
  });
31691
31775
  await program.parseAsync(argv);
31692
31776
  }
@@ -31701,4 +31785,4 @@ export {
31701
31785
  openAttachment as o,
31702
31786
  syncAttachments as s
31703
31787
  };
31704
- //# sourceMappingURL=index-Bv5IgsL-.js.map
31788
+ //# sourceMappingURL=index-BIFsFHVj.js.map