@ncukondo/reference-manager 0.15.0 → 0.15.1

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.1";
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-DEd6F5Rr.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-DEd6F5Rr.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-DEd6F5Rr.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-DEd6F5Rr.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-DEd6F5Rr.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-DEd6F5Rr.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
  }
@@ -1677,12 +1700,13 @@ async function handleAttachOpenAction(identifierArg, filenameArg, options, globa
1677
1700
  if (!result.success) {
1678
1701
  process.stderr.write(`Error: ${result.error}
1679
1702
  `);
1680
- process.exit(1);
1703
+ setExitCode(ExitCode.ERROR);
1704
+ return;
1681
1705
  }
1682
1706
  if (options.print) {
1683
1707
  process.stdout.write(`${result.path}
1684
1708
  `);
1685
- process.exit(0);
1709
+ setExitCode(ExitCode.SUCCESS);
1686
1710
  }
1687
1711
  if (shouldUseInteractive) {
1688
1712
  await runInteractiveMode(
@@ -1696,11 +1720,11 @@ async function handleAttachOpenAction(identifierArg, filenameArg, options, globa
1696
1720
  process.stderr.write(`${formatAttachOpenOutput(result)}
1697
1721
  `);
1698
1722
  }
1699
- process.exit(0);
1723
+ setExitCode(ExitCode.SUCCESS);
1700
1724
  } catch (error) {
1701
1725
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1702
1726
  `);
1703
- process.exit(4);
1727
+ setExitCode(ExitCode.INTERNAL_ERROR);
1704
1728
  }
1705
1729
  }
1706
1730
  async function handleAttachAddAction(identifierArg, filePathArg, options, globalOpts) {
@@ -1722,11 +1746,11 @@ async function handleAttachAddAction(identifierArg, filePathArg, options, global
1722
1746
  const output = formatAttachAddOutput(result);
1723
1747
  process.stderr.write(`${output}
1724
1748
  `);
1725
- process.exit(getAttachExitCode(result));
1749
+ setExitCode(getAttachExitCode(result));
1726
1750
  } catch (error) {
1727
1751
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1728
1752
  `);
1729
- process.exit(4);
1753
+ setExitCode(ExitCode.INTERNAL_ERROR);
1730
1754
  }
1731
1755
  }
1732
1756
  async function handleAttachListAction(identifierArg, options, globalOpts) {
@@ -1744,11 +1768,11 @@ async function handleAttachListAction(identifierArg, options, globalOpts) {
1744
1768
  const output = formatAttachListOutput(result, identifier);
1745
1769
  process.stdout.write(`${output}
1746
1770
  `);
1747
- process.exit(getAttachExitCode(result));
1771
+ setExitCode(getAttachExitCode(result));
1748
1772
  } catch (error) {
1749
1773
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1750
1774
  `);
1751
- process.exit(4);
1775
+ setExitCode(ExitCode.INTERNAL_ERROR);
1752
1776
  }
1753
1777
  }
1754
1778
  async function handleAttachGetAction(identifierArg, filenameArg, options, globalOpts) {
@@ -1774,11 +1798,11 @@ async function handleAttachGetAction(identifierArg, filenameArg, options, global
1774
1798
  process.stderr.write(`Error: ${result.error}
1775
1799
  `);
1776
1800
  }
1777
- process.exit(getAttachExitCode(result));
1801
+ setExitCode(getAttachExitCode(result));
1778
1802
  } catch (error) {
1779
1803
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1780
1804
  `);
1781
- process.exit(4);
1805
+ setExitCode(ExitCode.INTERNAL_ERROR);
1782
1806
  }
1783
1807
  }
1784
1808
  async function handleAttachDetachAction(identifierArg, filenameArg, options, globalOpts) {
@@ -1799,34 +1823,75 @@ async function handleAttachDetachAction(identifierArg, filenameArg, options, glo
1799
1823
  const output = formatAttachDetachOutput(result);
1800
1824
  process.stderr.write(`${output}
1801
1825
  `);
1802
- process.exit(getAttachExitCode(result));
1826
+ setExitCode(getAttachExitCode(result));
1803
1827
  } catch (error) {
1804
1828
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1805
1829
  `);
1806
- process.exit(4);
1830
+ setExitCode(ExitCode.INTERNAL_ERROR);
1807
1831
  }
1808
1832
  }
1833
+ async function runInteractiveSyncMode(identifier, attachmentsDirectory, idType, context) {
1834
+ const dryRunOptions = {
1835
+ identifier,
1836
+ attachmentsDirectory,
1837
+ ...idType && { idType }
1838
+ };
1839
+ const dryRunResult = await executeAttachSync(dryRunOptions, context);
1840
+ const hasNewFiles = dryRunResult.newFiles.length > 0;
1841
+ const hasMissingFiles = dryRunResult.missingFiles.length > 0;
1842
+ if (!dryRunResult.success || !hasNewFiles && !hasMissingFiles) {
1843
+ process.stderr.write(`${formatAttachSyncOutput(dryRunResult)}
1844
+ `);
1845
+ return;
1846
+ }
1847
+ process.stderr.write(`${formatAttachSyncOutput(dryRunResult)}
1848
+
1849
+ `);
1850
+ const shouldApplyNew = hasNewFiles && await readConfirmation("Add new files to metadata?");
1851
+ const shouldApplyFix = hasMissingFiles && shouldApplyNew && await readConfirmation("Remove missing files?");
1852
+ if (!shouldApplyNew && !shouldApplyFix) {
1853
+ process.stderr.write("No changes applied.\n");
1854
+ return;
1855
+ }
1856
+ const applyOptions = {
1857
+ identifier,
1858
+ attachmentsDirectory,
1859
+ ...shouldApplyNew && { yes: true },
1860
+ ...shouldApplyFix && { fix: true },
1861
+ ...idType && { idType }
1862
+ };
1863
+ const result = await executeAttachSync(applyOptions, context);
1864
+ process.stderr.write(`${formatAttachSyncOutput(result)}
1865
+ `);
1866
+ }
1809
1867
  async function handleAttachSyncAction(identifierArg, options, globalOpts) {
1810
1868
  try {
1811
1869
  const config2 = await loadConfigWithOverrides({ ...globalOpts, ...options });
1812
1870
  const context = await createExecutionContext(config2, Library.load);
1813
1871
  const identifier = await resolveIdentifier(identifierArg, context, config2);
1872
+ const attachmentsDirectory = config2.attachments.directory;
1873
+ const idType = options.uuid ? "uuid" : void 0;
1874
+ const shouldUseInteractive = isTTY() && !options.yes && !options.fix;
1875
+ if (shouldUseInteractive) {
1876
+ await runInteractiveSyncMode(identifier, attachmentsDirectory, idType, context);
1877
+ setExitCode(ExitCode.SUCCESS);
1878
+ return;
1879
+ }
1814
1880
  const syncOptions = {
1815
1881
  identifier,
1816
- attachmentsDirectory: config2.attachments.directory,
1817
- ...options.yes && { yes: options.yes },
1818
- ...options.fix && { fix: options.fix },
1819
- ...options.uuid && { idType: "uuid" }
1882
+ attachmentsDirectory,
1883
+ ...options.yes && { yes: true },
1884
+ ...options.fix && { fix: true },
1885
+ ...idType && { idType }
1820
1886
  };
1821
1887
  const result = await executeAttachSync(syncOptions, context);
1822
- const output = formatAttachSyncOutput(result);
1823
- process.stderr.write(`${output}
1888
+ process.stderr.write(`${formatAttachSyncOutput(result)}
1824
1889
  `);
1825
- process.exit(getAttachExitCode(result));
1890
+ setExitCode(getAttachExitCode(result));
1826
1891
  } catch (error) {
1827
1892
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1828
1893
  `);
1829
- process.exit(4);
1894
+ setExitCode(ExitCode.INTERNAL_ERROR);
1830
1895
  }
1831
1896
  }
1832
1897
  async function validateOptions$2(options) {
@@ -1900,7 +1965,8 @@ async function executeInteractiveCite(options, context, config2) {
1900
1965
  defaultStyle: config2.citation.defaultStyle
1901
1966
  });
1902
1967
  if (styleResult.cancelled) {
1903
- process.exit(0);
1968
+ setExitCode(ExitCode.SUCCESS);
1969
+ return { results: [] };
1904
1970
  }
1905
1971
  style = styleResult.style;
1906
1972
  }
@@ -1920,7 +1986,8 @@ async function handleCiteAction(identifiers, options, globalOpts) {
1920
1986
  process.stderr.write(
1921
1987
  "Error: No identifiers provided. Provide IDs, pipe them via stdin, or run interactively in a TTY.\n"
1922
1988
  );
1923
- process.exit(1);
1989
+ setExitCode(ExitCode.ERROR);
1990
+ return;
1924
1991
  }
1925
1992
  result = await executeCite({ ...options, identifiers: stdinIds }, context);
1926
1993
  }
@@ -1937,11 +2004,11 @@ async function handleCiteAction(identifiers, options, globalOpts) {
1937
2004
  process.stderr.write(`${errors2}
1938
2005
  `);
1939
2006
  }
1940
- process.exit(getCiteExitCode(result));
2007
+ setExitCode(getCiteExitCode(result));
1941
2008
  } catch (error) {
1942
2009
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
1943
2010
  `);
1944
- process.exit(4);
2011
+ setExitCode(ExitCode.INTERNAL_ERROR);
1945
2012
  }
1946
2013
  }
1947
2014
  const ENV_OVERRIDE_MAP = {
@@ -2652,11 +2719,11 @@ function registerConfigCommand(program) {
2652
2719
  });
2653
2720
  process.stdout.write(`${output}
2654
2721
  `);
2655
- process.exit(0);
2722
+ setExitCode(ExitCode.SUCCESS);
2656
2723
  } catch (error) {
2657
2724
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2658
2725
  `);
2659
- process.exit(1);
2726
+ setExitCode(ExitCode.ERROR);
2660
2727
  }
2661
2728
  });
2662
2729
  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 +2741,14 @@ function registerConfigCommand(program) {
2674
2741
  const { formatValue: formatValue2 } = await Promise.resolve().then(() => get);
2675
2742
  process.stdout.write(`${formatValue2(result.value)}
2676
2743
  `);
2677
- process.exit(0);
2744
+ setExitCode(ExitCode.SUCCESS);
2678
2745
  } else {
2679
- process.exit(1);
2746
+ setExitCode(ExitCode.ERROR);
2680
2747
  }
2681
2748
  } catch (error) {
2682
2749
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2683
2750
  `);
2684
- process.exit(1);
2751
+ setExitCode(ExitCode.ERROR);
2685
2752
  }
2686
2753
  });
2687
2754
  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 +2766,18 @@ function registerConfigCommand(program) {
2699
2766
  if (!result.success) {
2700
2767
  process.stderr.write(`Error: ${result.error}
2701
2768
  `);
2702
- process.exit(1);
2769
+ setExitCode(ExitCode.ERROR);
2770
+ return;
2703
2771
  }
2704
2772
  if (result.warning) {
2705
2773
  process.stderr.write(`${result.warning}
2706
2774
  `);
2707
2775
  }
2708
- process.exit(0);
2776
+ setExitCode(ExitCode.SUCCESS);
2709
2777
  } catch (error) {
2710
2778
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2711
2779
  `);
2712
- process.exit(1);
2780
+ setExitCode(ExitCode.ERROR);
2713
2781
  }
2714
2782
  });
2715
2783
  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 +2792,14 @@ function registerConfigCommand(program) {
2724
2792
  if (!result.success) {
2725
2793
  process.stderr.write(`Error: ${result.error}
2726
2794
  `);
2727
- process.exit(1);
2795
+ setExitCode(ExitCode.ERROR);
2796
+ return;
2728
2797
  }
2729
- process.exit(0);
2798
+ setExitCode(ExitCode.SUCCESS);
2730
2799
  } catch (error) {
2731
2800
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2732
2801
  `);
2733
- process.exit(1);
2802
+ setExitCode(ExitCode.ERROR);
2734
2803
  }
2735
2804
  });
2736
2805
  configCmd.command("keys").description("List all available configuration keys").option("--section <name>", "List keys only in a specific section").action(async (options) => {
@@ -2740,11 +2809,11 @@ function registerConfigCommand(program) {
2740
2809
  process.stdout.write(`${output}
2741
2810
  `);
2742
2811
  }
2743
- process.exit(0);
2812
+ setExitCode(ExitCode.SUCCESS);
2744
2813
  } catch (error) {
2745
2814
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2746
2815
  `);
2747
- process.exit(1);
2816
+ setExitCode(ExitCode.ERROR);
2748
2817
  }
2749
2818
  });
2750
2819
  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 +2821,19 @@ function registerConfigCommand(program) {
2752
2821
  const output = showConfigPaths({ user: options.user, local: options.local });
2753
2822
  process.stdout.write(`${output}
2754
2823
  `);
2755
- process.exit(0);
2824
+ setExitCode(ExitCode.SUCCESS);
2756
2825
  } catch (error) {
2757
2826
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2758
2827
  `);
2759
- process.exit(1);
2828
+ setExitCode(ExitCode.ERROR);
2760
2829
  }
2761
2830
  });
2762
2831
  configCmd.command("edit").description("Open configuration file in editor").option("--local", "Edit current directory config").action(async (options) => {
2763
2832
  try {
2764
2833
  if (!process.stdin.isTTY) {
2765
2834
  process.stderr.write("Error: config edit requires a terminal (TTY)\n");
2766
- process.exit(1);
2835
+ setExitCode(ExitCode.ERROR);
2836
+ return;
2767
2837
  }
2768
2838
  const target = getConfigEditTarget({ local: options.local });
2769
2839
  if (!target.exists) {
@@ -2773,11 +2843,11 @@ function registerConfigCommand(program) {
2773
2843
  }
2774
2844
  const editor = resolveEditor();
2775
2845
  const exitCode = openEditor(editor, target.path);
2776
- process.exit(exitCode);
2846
+ setExitCode(exitCode);
2777
2847
  } catch (error) {
2778
2848
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
2779
2849
  `);
2780
- process.exit(1);
2850
+ setExitCode(ExitCode.ERROR);
2781
2851
  }
2782
2852
  });
2783
2853
  }
@@ -5748,7 +5818,7 @@ async function handleEditAction(identifiers, options, globalOpts) {
5748
5818
  const output2 = formatEditOutput(result2);
5749
5819
  process.stderr.write(`${output2}
5750
5820
  `);
5751
- process.exit(result2.success ? 0 : 1);
5821
+ setExitCode(result2.success ? ExitCode.SUCCESS : ExitCode.ERROR);
5752
5822
  return;
5753
5823
  } else {
5754
5824
  const stdinIds = await readIdentifiersFromStdin();
@@ -5756,13 +5826,15 @@ async function handleEditAction(identifiers, options, globalOpts) {
5756
5826
  process.stderr.write(
5757
5827
  "Error: No identifiers provided. Provide IDs, pipe them via stdin, or run interactively in a TTY.\n"
5758
5828
  );
5759
- process.exit(1);
5829
+ setExitCode(ExitCode.ERROR);
5830
+ return;
5760
5831
  }
5761
5832
  resolvedIdentifiers = stdinIds;
5762
5833
  }
5763
5834
  if (!isTTY()) {
5764
5835
  process.stderr.write("Error: Edit command requires a TTY to open the editor.\n");
5765
- process.exit(1);
5836
+ setExitCode(ExitCode.ERROR);
5837
+ return;
5766
5838
  }
5767
5839
  const format2 = options.format ?? config2.cli.edit.defaultFormat;
5768
5840
  const result = await executeEditCommand(
@@ -5777,11 +5849,11 @@ async function handleEditAction(identifiers, options, globalOpts) {
5777
5849
  const output = formatEditOutput(result);
5778
5850
  process.stderr.write(`${output}
5779
5851
  `);
5780
- process.exit(result.success ? 0 : 1);
5852
+ setExitCode(result.success ? ExitCode.SUCCESS : ExitCode.ERROR);
5781
5853
  } catch (error) {
5782
5854
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
5783
5855
  `);
5784
- process.exit(4);
5856
+ setExitCode(ExitCode.INTERNAL_ERROR);
5785
5857
  }
5786
5858
  }
5787
5859
  const ALIAS = Symbol.for("yaml.alias");
@@ -9401,7 +9473,8 @@ async function handleFulltextAttachAction(identifierArg, filePathArg, options, g
9401
9473
  process.stderr.write(
9402
9474
  "Error: No identifier provided. Provide an ID or run interactively in a TTY.\n"
9403
9475
  );
9404
- process.exit(1);
9476
+ setExitCode(ExitCode.ERROR);
9477
+ return;
9405
9478
  }
9406
9479
  identifier = await executeInteractiveSelect(context, config2);
9407
9480
  }
@@ -9421,11 +9494,11 @@ async function handleFulltextAttachAction(identifierArg, filePathArg, options, g
9421
9494
  const output = formatFulltextAttachOutput(result);
9422
9495
  process.stderr.write(`${output}
9423
9496
  `);
9424
- process.exit(getFulltextExitCode(result));
9497
+ setExitCode(getFulltextExitCode(result));
9425
9498
  } catch (error) {
9426
9499
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9427
9500
  `);
9428
- process.exit(4);
9501
+ setExitCode(ExitCode.INTERNAL_ERROR);
9429
9502
  }
9430
9503
  }
9431
9504
  function outputFulltextGetResult(result, useStdout) {
@@ -9457,7 +9530,8 @@ async function handleFulltextGetAction(identifierArg, options, globalOpts) {
9457
9530
  process.stderr.write(
9458
9531
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
9459
9532
  );
9460
- process.exit(1);
9533
+ setExitCode(ExitCode.ERROR);
9534
+ return;
9461
9535
  }
9462
9536
  identifier = stdinId;
9463
9537
  }
@@ -9471,11 +9545,11 @@ async function handleFulltextGetAction(identifierArg, options, globalOpts) {
9471
9545
  };
9472
9546
  const result = await executeFulltextGet(getOptions, context);
9473
9547
  outputFulltextGetResult(result, Boolean(options.stdout));
9474
- process.exit(getFulltextExitCode(result));
9548
+ setExitCode(getFulltextExitCode(result));
9475
9549
  } catch (error) {
9476
9550
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9477
9551
  `);
9478
- process.exit(4);
9552
+ setExitCode(ExitCode.INTERNAL_ERROR);
9479
9553
  }
9480
9554
  }
9481
9555
  async function handleFulltextDetachAction(identifierArg, options, globalOpts) {
@@ -9493,7 +9567,8 @@ async function handleFulltextDetachAction(identifierArg, options, globalOpts) {
9493
9567
  process.stderr.write(
9494
9568
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
9495
9569
  );
9496
- process.exit(1);
9570
+ setExitCode(ExitCode.ERROR);
9571
+ return;
9497
9572
  }
9498
9573
  identifier = stdinId;
9499
9574
  }
@@ -9510,11 +9585,11 @@ async function handleFulltextDetachAction(identifierArg, options, globalOpts) {
9510
9585
  const output = formatFulltextDetachOutput(result);
9511
9586
  process.stderr.write(`${output}
9512
9587
  `);
9513
- process.exit(getFulltextExitCode(result));
9588
+ setExitCode(getFulltextExitCode(result));
9514
9589
  } catch (error) {
9515
9590
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9516
9591
  `);
9517
- process.exit(4);
9592
+ setExitCode(ExitCode.INTERNAL_ERROR);
9518
9593
  }
9519
9594
  }
9520
9595
  async function handleFulltextOpenAction(identifierArg, options, globalOpts) {
@@ -9532,7 +9607,8 @@ async function handleFulltextOpenAction(identifierArg, options, globalOpts) {
9532
9607
  process.stderr.write(
9533
9608
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
9534
9609
  );
9535
- process.exit(1);
9610
+ setExitCode(ExitCode.ERROR);
9611
+ return;
9536
9612
  }
9537
9613
  identifier = stdinId;
9538
9614
  }
@@ -9547,11 +9623,11 @@ async function handleFulltextOpenAction(identifierArg, options, globalOpts) {
9547
9623
  const output = formatFulltextOpenOutput(result);
9548
9624
  process.stderr.write(`${output}
9549
9625
  `);
9550
- process.exit(getFulltextExitCode(result));
9626
+ setExitCode(getFulltextExitCode(result));
9551
9627
  } catch (error) {
9552
9628
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
9553
9629
  `);
9554
- process.exit(4);
9630
+ setExitCode(ExitCode.INTERNAL_ERROR);
9555
9631
  }
9556
9632
  }
9557
9633
  function formatAuthor(author) {
@@ -30480,7 +30556,7 @@ function handleRemoveError(error, identifierArg, outputFormat) {
30480
30556
  `);
30481
30557
  }
30482
30558
  const isUserError = message.includes("not found") || message.includes("No identifier");
30483
- process.exit(isUserError ? 1 : 4);
30559
+ setExitCode(isUserError ? ExitCode.ERROR : ExitCode.INTERNAL_ERROR);
30484
30560
  }
30485
30561
  async function handleRemoveAction(identifierArg, options, globalOpts) {
30486
30562
  const { formatRemoveJsonOutput: formatRemoveJsonOutput2 } = await Promise.resolve().then(() => jsonOutput);
@@ -30501,12 +30577,14 @@ async function handleRemoveAction(identifierArg, options, globalOpts) {
30501
30577
  if (hasFulltext && !isTTY() && !force) {
30502
30578
  process.stderr.write(`Error: ${formatFulltextWarning(fulltextTypes)}
30503
30579
  `);
30504
- process.exit(1);
30580
+ setExitCode(ExitCode.ERROR);
30581
+ return;
30505
30582
  }
30506
30583
  const confirmed = await confirmRemoveIfNeeded(refToRemove, hasFulltext, force);
30507
30584
  if (!confirmed) {
30508
30585
  process.stderr.write("Cancelled.\n");
30509
- process.exit(2);
30586
+ setExitCode(2);
30587
+ return;
30510
30588
  }
30511
30589
  const removeOptions = {
30512
30590
  identifier,
@@ -30516,7 +30594,7 @@ async function handleRemoveAction(identifierArg, options, globalOpts) {
30516
30594
  };
30517
30595
  const result = await executeRemove(removeOptions, context);
30518
30596
  outputResult(result, identifier, outputFormat, options.full, formatRemoveJsonOutput2);
30519
- process.exit(result.removed ? 0 : 1);
30597
+ setExitCode(result.removed ? ExitCode.SUCCESS : ExitCode.ERROR);
30520
30598
  } catch (error) {
30521
30599
  handleRemoveError(error, identifierArg, outputFormat);
30522
30600
  }
@@ -30628,7 +30706,7 @@ async function executeInteractiveSearch(options, context, config2) {
30628
30706
  validateInteractiveOptions(options);
30629
30707
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
30630
30708
  const { runSearchPrompt } = await import("./search-prompt-BrWpOcij.js");
30631
- const { runActionMenu } = await import("./action-menu-DvwR6nMj.js");
30709
+ const { runActionMenu } = await import("./action-menu-DwCcc6Gt.js");
30632
30710
  const { search } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.y);
30633
30711
  const { tokenize } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.x);
30634
30712
  checkTTY();
@@ -30706,7 +30784,7 @@ async function startServerForeground(options) {
30706
30784
  server.close();
30707
30785
  await dispose();
30708
30786
  await removePortfile(options.portfilePath);
30709
- process.exit(0);
30787
+ setExitCode(ExitCode.SUCCESS);
30710
30788
  };
30711
30789
  process.on("SIGINT", cleanup);
30712
30790
  process.on("SIGTERM", cleanup);
@@ -30958,14 +31036,16 @@ async function resolveUpdateIdentifier(identifierArg, hasSetOptions, context, co
30958
31036
  process.stderr.write(
30959
31037
  "Error: No identifier provided. Provide an ID, pipe one via stdin, or run interactively in a TTY.\n"
30960
31038
  );
30961
- process.exit(1);
31039
+ setExitCode(ExitCode.ERROR);
31040
+ return "";
30962
31041
  }
30963
31042
  return stdinId;
30964
31043
  }
30965
31044
  process.stderr.write(
30966
31045
  "Error: No identifier provided. When using stdin for JSON input, identifier must be provided as argument.\n"
30967
31046
  );
30968
- process.exit(1);
31047
+ setExitCode(ExitCode.ERROR);
31048
+ return "";
30969
31049
  }
30970
31050
  function parseUpdateInput(setOptions, file) {
30971
31051
  if (setOptions && setOptions.length > 0 && file) {
@@ -30986,23 +31066,25 @@ function handleUpdateError(error) {
30986
31066
  if (message.includes("Parse error")) {
30987
31067
  process.stderr.write(`Error: ${message}
30988
31068
  `);
30989
- process.exit(3);
31069
+ setExitCode(3);
30990
31070
  }
30991
31071
  if (message.includes("not found") || message.includes("validation")) {
30992
31072
  process.stderr.write(`Error: ${message}
30993
31073
  `);
30994
- process.exit(1);
31074
+ setExitCode(ExitCode.ERROR);
30995
31075
  }
30996
31076
  process.stderr.write(`Error: ${message}
30997
31077
  `);
30998
- process.exit(4);
31078
+ setExitCode(ExitCode.INTERNAL_ERROR);
30999
31079
  }
31000
31080
  function handleUpdateErrorWithFormat(error, identifier, outputFormat) {
31001
31081
  const message = error instanceof Error ? error.message : String(error);
31002
31082
  if (outputFormat === "json") {
31003
31083
  process.stdout.write(`${JSON.stringify({ success: false, id: identifier, error: message })}
31004
31084
  `);
31005
- process.exit(message.includes("not found") || message.includes("validation") ? 1 : 4);
31085
+ setExitCode(
31086
+ message.includes("not found") || message.includes("validation") ? ExitCode.ERROR : ExitCode.INTERNAL_ERROR
31087
+ );
31006
31088
  }
31007
31089
  handleUpdateError(error);
31008
31090
  }
@@ -31036,7 +31118,7 @@ async function handleUpdateAction(identifierArg, file, options, globalOpts) {
31036
31118
  process.stderr.write(`${output}
31037
31119
  `);
31038
31120
  }
31039
- process.exit(result.updated ? 0 : 1);
31121
+ setExitCode(result.updated ? ExitCode.SUCCESS : ExitCode.ERROR);
31040
31122
  } catch (error) {
31041
31123
  handleUpdateErrorWithFormat(error, identifierArg ?? "", outputFormat);
31042
31124
  }
@@ -31321,7 +31403,7 @@ function registerCompletionCommand(program) {
31321
31403
  } else {
31322
31404
  console.error(`Unknown action: ${action}`);
31323
31405
  console.error("Usage: ref completion [install|uninstall]");
31324
- process.exit(1);
31406
+ setExitCode(ExitCode.ERROR);
31325
31407
  }
31326
31408
  });
31327
31409
  }
@@ -31356,11 +31438,9 @@ async function handleListAction(options, program) {
31356
31438
  process.stdout.write(`${output}
31357
31439
  `);
31358
31440
  }
31359
- process.exit(0);
31441
+ setExitCode(ExitCode.SUCCESS);
31360
31442
  } catch (error) {
31361
- process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31362
- `);
31363
- process.exit(4);
31443
+ exitWithError(error instanceof Error ? error.message : String(error), ExitCode.INTERNAL_ERROR);
31364
31444
  }
31365
31445
  }
31366
31446
  function registerListCommand(program) {
@@ -31385,11 +31465,11 @@ async function handleExportAction(ids, options, program) {
31385
31465
  `);
31386
31466
  }
31387
31467
  }
31388
- process.exit(getExportExitCode(result));
31468
+ setExitCode(getExportExitCode(result));
31389
31469
  } catch (error) {
31390
31470
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31391
31471
  `);
31392
- process.exit(4);
31472
+ setExitCode(ExitCode.INTERNAL_ERROR);
31393
31473
  }
31394
31474
  }
31395
31475
  function registerExportCommand(program) {
@@ -31408,7 +31488,7 @@ async function handleSearchAction(query, options, program) {
31408
31488
  process.stdout.write(`${result2.output}
31409
31489
  `);
31410
31490
  }
31411
- process.exit(result2.cancelled ? 0 : 0);
31491
+ setExitCode(ExitCode.SUCCESS);
31412
31492
  }
31413
31493
  const result = await executeSearch({ ...options, query }, context);
31414
31494
  const output = formatSearchOutput(result, { ...options, query });
@@ -31416,18 +31496,19 @@ async function handleSearchAction(query, options, program) {
31416
31496
  process.stdout.write(`${output}
31417
31497
  `);
31418
31498
  }
31419
- process.exit(0);
31499
+ setExitCode(ExitCode.SUCCESS);
31420
31500
  } catch (error) {
31421
31501
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31422
31502
  `);
31423
- process.exit(4);
31503
+ setExitCode(ExitCode.INTERNAL_ERROR);
31424
31504
  }
31425
31505
  }
31426
31506
  function registerSearchCommand(program) {
31427
31507
  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
31508
  if (!options.tui && !query) {
31429
31509
  process.stderr.write("Error: Search query is required unless using --tui\n");
31430
- process.exit(1);
31510
+ setExitCode(ExitCode.ERROR);
31511
+ return;
31431
31512
  }
31432
31513
  await handleSearchAction(query ?? "", options, program);
31433
31514
  });
@@ -31492,7 +31573,7 @@ async function handleAddAction(inputs, options, program) {
31492
31573
  process.stderr.write(`${output}
31493
31574
  `);
31494
31575
  }
31495
- process.exit(getExitCode(result));
31576
+ setExitCode(getExitCode(result));
31496
31577
  } catch (error) {
31497
31578
  const message = error instanceof Error ? error.message : String(error);
31498
31579
  if (outputFormat === "json") {
@@ -31502,7 +31583,7 @@ async function handleAddAction(inputs, options, program) {
31502
31583
  process.stderr.write(`Error: ${message}
31503
31584
  `);
31504
31585
  }
31505
- process.exit(1);
31586
+ setExitCode(ExitCode.ERROR);
31506
31587
  }
31507
31588
  }
31508
31589
  function registerAddCommand(program) {
@@ -31552,18 +31633,18 @@ function registerServerCommand(program) {
31552
31633
  };
31553
31634
  await serverStart(startOptions);
31554
31635
  if (options.daemon) {
31555
- process.exit(0);
31636
+ setExitCode(ExitCode.SUCCESS);
31556
31637
  }
31557
31638
  } catch (error) {
31558
31639
  const message = error instanceof Error ? error.message : String(error);
31559
31640
  if (message.includes("already running") || message.includes("conflict")) {
31560
31641
  process.stderr.write(`Error: ${message}
31561
31642
  `);
31562
- process.exit(1);
31643
+ setExitCode(ExitCode.ERROR);
31563
31644
  }
31564
31645
  process.stderr.write(`Error: ${message}
31565
31646
  `);
31566
- process.exit(4);
31647
+ setExitCode(ExitCode.INTERNAL_ERROR);
31567
31648
  }
31568
31649
  });
31569
31650
  serverCmd.command("stop").description("Stop running server").action(async () => {
@@ -31571,17 +31652,17 @@ function registerServerCommand(program) {
31571
31652
  const portfilePath = getPortfilePath();
31572
31653
  await serverStop(portfilePath);
31573
31654
  process.stderr.write("Server stopped.\n");
31574
- process.exit(0);
31655
+ setExitCode(ExitCode.SUCCESS);
31575
31656
  } catch (error) {
31576
31657
  const message = error instanceof Error ? error.message : String(error);
31577
31658
  if (message.includes("not running")) {
31578
31659
  process.stderr.write(`Error: ${message}
31579
31660
  `);
31580
- process.exit(1);
31661
+ setExitCode(ExitCode.ERROR);
31581
31662
  }
31582
31663
  process.stderr.write(`Error: ${message}
31583
31664
  `);
31584
- process.exit(4);
31665
+ setExitCode(ExitCode.INTERNAL_ERROR);
31585
31666
  }
31586
31667
  });
31587
31668
  serverCmd.command("status").description("Check server status").action(async () => {
@@ -31596,15 +31677,15 @@ PID: ${status.pid}
31596
31677
  Library: ${status.library}
31597
31678
  `
31598
31679
  );
31599
- process.exit(0);
31680
+ setExitCode(ExitCode.SUCCESS);
31600
31681
  } else {
31601
31682
  process.stdout.write("Server not running\n");
31602
- process.exit(1);
31683
+ setExitCode(ExitCode.ERROR);
31603
31684
  }
31604
31685
  } catch (error) {
31605
31686
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31606
31687
  `);
31607
- process.exit(4);
31688
+ setExitCode(ExitCode.INTERNAL_ERROR);
31608
31689
  }
31609
31690
  });
31610
31691
  }
@@ -31633,7 +31714,7 @@ function registerMcpCommand(program) {
31633
31714
  } catch (error) {
31634
31715
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
31635
31716
  `);
31636
- process.exit(1);
31717
+ setExitCode(ExitCode.ERROR);
31637
31718
  }
31638
31719
  });
31639
31720
  }
@@ -31683,10 +31764,10 @@ async function main(argv) {
31683
31764
  return;
31684
31765
  }
31685
31766
  process.on("SIGINT", () => {
31686
- process.exit(130);
31767
+ setExitCode(ExitCode.SIGINT);
31687
31768
  });
31688
31769
  process.on("SIGTERM", () => {
31689
- process.exit(0);
31770
+ setExitCode(ExitCode.SUCCESS);
31690
31771
  });
31691
31772
  await program.parseAsync(argv);
31692
31773
  }
@@ -31701,4 +31782,4 @@ export {
31701
31782
  openAttachment as o,
31702
31783
  syncAttachments as s
31703
31784
  };
31704
- //# sourceMappingURL=index-Bv5IgsL-.js.map
31785
+ //# sourceMappingURL=index-B4RmLBI1.js.map