@ncukondo/reference-manager 0.14.1 → 0.15.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 (98) hide show
  1. package/README.md +64 -16
  2. package/bin/reference-manager.js +0 -0
  3. package/dist/chunks/{action-menu-CVSizwXm.js → action-menu-DvwR6nMj.js} +3 -3
  4. package/dist/chunks/{action-menu-CVSizwXm.js.map → action-menu-DvwR6nMj.js.map} +1 -1
  5. package/dist/chunks/{file-watcher-D2Y-SlcE.js → file-watcher-B_WpVHSV.js} +18 -18
  6. package/dist/chunks/{file-watcher-D2Y-SlcE.js.map → file-watcher-B_WpVHSV.js.map} +1 -1
  7. package/dist/chunks/index-B_WCu-ZQ.js +10 -0
  8. package/dist/chunks/index-B_WCu-ZQ.js.map +1 -0
  9. package/dist/chunks/{index-CXoDLO8W.js → index-Bv5IgsL-.js} +1522 -409
  10. package/dist/chunks/index-Bv5IgsL-.js.map +1 -0
  11. package/dist/chunks/{index-DapYyqAC.js → index-DHgeuWGP.js} +112 -35
  12. package/dist/chunks/index-DHgeuWGP.js.map +1 -0
  13. package/dist/chunks/{loader-C1EpnyPm.js → loader-4FFB4igw.js} +66 -27
  14. package/dist/chunks/loader-4FFB4igw.js.map +1 -0
  15. package/dist/chunks/{reference-select-DSVwE9iu.js → reference-select-B9w9CLa1.js} +3 -3
  16. package/dist/chunks/{reference-select-DSVwE9iu.js.map → reference-select-B9w9CLa1.js.map} +1 -1
  17. package/dist/chunks/{style-select-CYo0O7MZ.js → style-select-BNQHC79W.js} +2 -2
  18. package/dist/chunks/{style-select-CYo0O7MZ.js.map → style-select-BNQHC79W.js.map} +1 -1
  19. package/dist/chunks/{tty-CDBIQraQ.js → tty-BMyaEOhX.js} +2 -2
  20. package/dist/chunks/tty-BMyaEOhX.js.map +1 -0
  21. package/dist/cli/commands/attach.d.ts +204 -0
  22. package/dist/cli/commands/attach.d.ts.map +1 -0
  23. package/dist/cli/commands/cite.d.ts +1 -1
  24. package/dist/cli/commands/export.d.ts +1 -1
  25. package/dist/cli/commands/fulltext.d.ts +2 -2
  26. package/dist/cli/commands/fulltext.d.ts.map +1 -1
  27. package/dist/cli/commands/list.d.ts +2 -1
  28. package/dist/cli/commands/list.d.ts.map +1 -1
  29. package/dist/cli/commands/search.d.ts +3 -2
  30. package/dist/cli/commands/search.d.ts.map +1 -1
  31. package/dist/cli/completion.d.ts.map +1 -1
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/server-client.d.ts +37 -1
  34. package/dist/cli/server-client.d.ts.map +1 -1
  35. package/dist/cli.js +2 -2
  36. package/dist/config/defaults.d.ts +7 -1
  37. package/dist/config/defaults.d.ts.map +1 -1
  38. package/dist/config/key-parser.d.ts +1 -1
  39. package/dist/config/loader.d.ts.map +1 -1
  40. package/dist/config/schema.d.ts +22 -8
  41. package/dist/config/schema.d.ts.map +1 -1
  42. package/dist/features/attachments/directory-manager.d.ts +40 -0
  43. package/dist/features/attachments/directory-manager.d.ts.map +1 -0
  44. package/dist/features/attachments/directory.d.ts +36 -0
  45. package/dist/features/attachments/directory.d.ts.map +1 -0
  46. package/dist/features/attachments/filename.d.ts +30 -0
  47. package/dist/features/attachments/filename.d.ts.map +1 -0
  48. package/dist/features/attachments/types.d.ts +38 -0
  49. package/dist/features/attachments/types.d.ts.map +1 -0
  50. package/dist/features/fulltext/manager.d.ts +1 -1
  51. package/dist/features/fulltext/manager.d.ts.map +1 -1
  52. package/dist/features/interactive/tty.d.ts +2 -2
  53. package/dist/features/operations/attachments/add.d.ts +42 -0
  54. package/dist/features/operations/attachments/add.d.ts.map +1 -0
  55. package/dist/features/operations/attachments/detach.d.ts +38 -0
  56. package/dist/features/operations/attachments/detach.d.ts.map +1 -0
  57. package/dist/features/operations/attachments/get.d.ts +35 -0
  58. package/dist/features/operations/attachments/get.d.ts.map +1 -0
  59. package/dist/features/operations/attachments/index.d.ts +16 -0
  60. package/dist/features/operations/attachments/index.d.ts.map +1 -0
  61. package/dist/features/operations/attachments/list.d.ts +32 -0
  62. package/dist/features/operations/attachments/list.d.ts.map +1 -0
  63. package/dist/features/operations/attachments/open.d.ts +39 -0
  64. package/dist/features/operations/attachments/open.d.ts.map +1 -0
  65. package/dist/features/operations/attachments/sync.d.ts +50 -0
  66. package/dist/features/operations/attachments/sync.d.ts.map +1 -0
  67. package/dist/features/operations/fulltext/attach.d.ts +8 -2
  68. package/dist/features/operations/fulltext/attach.d.ts.map +1 -1
  69. package/dist/features/operations/fulltext/detach.d.ts +9 -3
  70. package/dist/features/operations/fulltext/detach.d.ts.map +1 -1
  71. package/dist/features/operations/fulltext/get.d.ts +8 -2
  72. package/dist/features/operations/fulltext/get.d.ts.map +1 -1
  73. package/dist/features/operations/fulltext/open.d.ts +8 -2
  74. package/dist/features/operations/fulltext/open.d.ts.map +1 -1
  75. package/dist/features/operations/fulltext-adapter/fulltext-adapter.d.ts +39 -0
  76. package/dist/features/operations/fulltext-adapter/fulltext-adapter.d.ts.map +1 -0
  77. package/dist/features/operations/fulltext-adapter/index.d.ts +7 -0
  78. package/dist/features/operations/fulltext-adapter/index.d.ts.map +1 -0
  79. package/dist/features/operations/index.d.ts +1 -0
  80. package/dist/features/operations/index.d.ts.map +1 -1
  81. package/dist/features/operations/library-operations.d.ts +43 -0
  82. package/dist/features/operations/library-operations.d.ts.map +1 -1
  83. package/dist/features/operations/operations-library.d.ts +7 -0
  84. package/dist/features/operations/operations-library.d.ts.map +1 -1
  85. package/dist/features/operations/remove.d.ts +1 -0
  86. package/dist/features/operations/remove.d.ts.map +1 -1
  87. package/dist/index.js +15 -15
  88. package/dist/index.js.map +1 -1
  89. package/dist/server.js +3 -3
  90. package/dist/utils/opener.d.ts +6 -1
  91. package/dist/utils/opener.d.ts.map +1 -1
  92. package/dist/utils/path.d.ts +28 -0
  93. package/dist/utils/path.d.ts.map +1 -0
  94. package/package.json +2 -1
  95. package/dist/chunks/index-CXoDLO8W.js.map +0 -1
  96. package/dist/chunks/index-DapYyqAC.js.map +0 -1
  97. package/dist/chunks/loader-C1EpnyPm.js.map +0 -1
  98. package/dist/chunks/tty-CDBIQraQ.js.map +0 -1
@@ -1,16 +1,29 @@
1
1
  import { spawn } from "node:child_process";
2
- import { existsSync, readFileSync } from "node:fs";
2
+ import fs__default, { existsSync, readFileSync } from "node:fs";
3
3
  import os__default, { homedir as homedir$1 } from "node:os";
4
4
  import path__default, { join } from "node:path";
5
5
  import { parse } from "@iarna/toml";
6
6
  import process$1 from "node:process";
7
7
  import { z } from "zod";
8
- import { q as sortOrderSchema, u as sortFieldSchema } from "./file-watcher-D2Y-SlcE.js";
9
- function getOpenerCommand(platform) {
8
+ import { a as sortOrderSchema, b as sortFieldSchema } from "./file-watcher-B_WpVHSV.js";
9
+ function isWSL() {
10
+ if (process.env.WSL_DISTRO_NAME !== void 0) {
11
+ return true;
12
+ }
13
+ try {
14
+ return fs__default.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop");
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+ function getOpenerCommand(platform, wsl = isWSL()) {
10
20
  switch (platform) {
11
21
  case "darwin":
12
22
  return ["open"];
13
23
  case "linux":
24
+ if (wsl) {
25
+ return ["wslview"];
26
+ }
14
27
  return ["xdg-open"];
15
28
  case "win32":
16
29
  return ["cmd", "/c", "start", ""];
@@ -41,7 +54,7 @@ async function openWithSystemApp(filePath, platform = process.platform) {
41
54
  });
42
55
  }
43
56
  const logLevelSchema = z.enum(["silent", "info", "debug"]);
44
- const interactiveConfigSchema = z.object({
57
+ const tuiConfigSchema = z.object({
45
58
  limit: z.number().int().nonnegative(),
46
59
  debounceMs: z.number().int().nonnegative()
47
60
  });
@@ -53,7 +66,7 @@ const cliConfigSchema = z.object({
53
66
  defaultLimit: z.number().int().nonnegative(),
54
67
  defaultSort: sortFieldSchema,
55
68
  defaultOrder: sortOrderSchema,
56
- interactive: interactiveConfigSchema,
69
+ tui: tuiConfigSchema,
57
70
  edit: editConfigSchema
58
71
  });
59
72
  const mcpConfigSchema = z.object({
@@ -88,6 +101,9 @@ const pubmedConfigSchema = z.object({
88
101
  const fulltextConfigSchema = z.object({
89
102
  directory: z.string().min(1)
90
103
  });
104
+ const attachmentsConfigSchema = z.object({
105
+ directory: z.string().min(1)
106
+ });
91
107
  const configSchema = z.object({
92
108
  library: z.string().min(1),
93
109
  logLevel: logLevelSchema,
@@ -97,6 +113,7 @@ const configSchema = z.object({
97
113
  citation: citationConfigSchema,
98
114
  pubmed: pubmedConfigSchema,
99
115
  fulltext: fulltextConfigSchema,
116
+ attachments: attachmentsConfigSchema,
100
117
  cli: cliConfigSchema,
101
118
  mcp: mcpConfigSchema
102
119
  });
@@ -146,6 +163,9 @@ const partialConfigSchema = z.object({
146
163
  fulltext: z.object({
147
164
  directory: z.string().min(1).optional()
148
165
  }).optional(),
166
+ attachments: z.object({
167
+ directory: z.string().min(1).optional()
168
+ }).optional(),
149
169
  cli: z.object({
150
170
  defaultLimit: z.number().int().nonnegative().optional(),
151
171
  default_limit: z.number().int().nonnegative().optional(),
@@ -153,7 +173,7 @@ const partialConfigSchema = z.object({
153
173
  default_sort: sortFieldSchema.optional(),
154
174
  defaultOrder: sortOrderSchema.optional(),
155
175
  default_order: sortOrderSchema.optional(),
156
- interactive: z.object({
176
+ tui: z.object({
157
177
  limit: z.number().int().nonnegative().optional(),
158
178
  debounceMs: z.number().int().nonnegative().optional(),
159
179
  debounce_ms: z.number().int().nonnegative().optional()
@@ -253,6 +273,7 @@ const sectionNormalizers = {
253
273
  citation: normalizeCitationConfig,
254
274
  pubmed: normalizePubmedConfig,
255
275
  fulltext: normalizeFulltextConfig,
276
+ attachments: normalizeAttachmentsConfig,
256
277
  cli: normalizeCliConfig,
257
278
  mcp: normalizeMcpConfig
258
279
  };
@@ -286,12 +307,19 @@ function normalizeFulltextConfig(fulltext) {
286
307
  }
287
308
  return Object.keys(normalized).length > 0 ? normalized : void 0;
288
309
  }
289
- function normalizeInteractiveSection(interactive) {
310
+ function normalizeAttachmentsConfig(attachments) {
290
311
  const normalized = {};
291
- if (interactive.limit !== void 0) {
292
- normalized.limit = interactive.limit;
312
+ if (attachments.directory !== void 0) {
313
+ normalized.directory = attachments.directory;
293
314
  }
294
- const debounceMs = interactive.debounceMs ?? interactive.debounce_ms;
315
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
316
+ }
317
+ function normalizeTuiSection(tui) {
318
+ const normalized = {};
319
+ if (tui.limit !== void 0) {
320
+ normalized.limit = tui.limit;
321
+ }
322
+ const debounceMs = tui.debounceMs ?? tui.debounce_ms;
295
323
  if (debounceMs !== void 0) {
296
324
  normalized.debounceMs = debounceMs;
297
325
  }
@@ -319,10 +347,10 @@ function normalizeCliConfig(cli) {
319
347
  if (defaultOrder !== void 0) {
320
348
  normalized.defaultOrder = defaultOrder;
321
349
  }
322
- if (cli.interactive !== void 0) {
323
- const interactive = normalizeInteractiveSection(cli.interactive);
324
- if (interactive) {
325
- normalized.interactive = interactive;
350
+ if (cli.tui !== void 0) {
351
+ const tui = normalizeTuiSection(cli.tui);
352
+ if (tui) {
353
+ normalized.tui = tui;
326
354
  }
327
355
  }
328
356
  if (cli.edit !== void 0) {
@@ -415,8 +443,8 @@ function getDefaultCurrentDirConfigFilename() {
415
443
  function getDefaultCslDirectory() {
416
444
  return join(getPaths().data, "csl");
417
445
  }
418
- function getDefaultFulltextDirectory() {
419
- return join(getPaths().data, "fulltext");
446
+ function getDefaultAttachmentsDirectory() {
447
+ return join(getPaths().data, "attachments");
420
448
  }
421
449
  const defaultConfig = {
422
450
  library: getDefaultLibraryPath(),
@@ -447,13 +475,16 @@ const defaultConfig = {
447
475
  apiKey: void 0
448
476
  },
449
477
  fulltext: {
450
- directory: getDefaultFulltextDirectory()
478
+ directory: getDefaultAttachmentsDirectory()
479
+ },
480
+ attachments: {
481
+ directory: getDefaultAttachmentsDirectory()
451
482
  },
452
483
  cli: {
453
484
  defaultLimit: 0,
454
485
  defaultSort: "updated",
455
486
  defaultOrder: "desc",
456
- interactive: {
487
+ tui: {
457
488
  limit: 20,
458
489
  debounceMs: 200
459
490
  },
@@ -481,13 +512,13 @@ function loadTOMLFile(path) {
481
512
  }
482
513
  }
483
514
  function mergeCliConfig(base, override) {
484
- const { interactive: overrideInteractive, ...overrideCliRest } = override;
485
- const { interactive: baseInteractive, ...baseCliRest } = base ?? {};
486
- const mergedInteractive = overrideInteractive !== void 0 ? { ...baseInteractive, ...overrideInteractive } : baseInteractive;
515
+ const { tui: overrideTui, ...overrideCliRest } = override;
516
+ const { tui: baseTui, ...baseCliRest } = base ?? {};
517
+ const mergedTui = overrideTui !== void 0 ? { ...baseTui, ...overrideTui } : baseTui;
487
518
  return {
488
519
  ...baseCliRest,
489
520
  ...overrideCliRest,
490
- ...mergedInteractive !== void 0 ? { interactive: mergedInteractive } : {}
521
+ ...mergedTui !== void 0 ? { tui: mergedTui } : {}
491
522
  };
492
523
  }
493
524
  function mergeConfigs(base, ...overrides) {
@@ -547,6 +578,7 @@ function fillDefaults(partial) {
547
578
  citation: fillCitationDefaults(partial.citation),
548
579
  pubmed: fillPubmedDefaults(partial.pubmed),
549
580
  fulltext: fillFulltextDefaults(partial.fulltext),
581
+ attachments: fillAttachmentsDefaults(partial.attachments),
550
582
  cli: fillCliDefaults(partial.cli),
551
583
  mcp: fillMcpDefaults(partial.mcp)
552
584
  };
@@ -574,12 +606,19 @@ function expandTilde(path) {
574
606
  return path;
575
607
  }
576
608
  function fillFulltextDefaults(partial) {
577
- const envDir = process.env.REFERENCE_MANAGER_FULLTEXT_DIR;
609
+ const envDir = process.env.REFERENCE_MANAGER_ATTACHMENTS_DIR;
578
610
  const directory = envDir ?? partial?.directory ?? defaultConfig.fulltext.directory;
579
611
  return {
580
612
  directory: expandTilde(directory)
581
613
  };
582
614
  }
615
+ function fillAttachmentsDefaults(partial) {
616
+ const envDir = process.env.REFERENCE_MANAGER_ATTACHMENTS_DIR;
617
+ const directory = envDir ?? partial?.directory ?? defaultConfig.attachments.directory;
618
+ return {
619
+ directory: expandTilde(directory)
620
+ };
621
+ }
583
622
  function fillCliDefaults(partial) {
584
623
  const envLimit = process.env.REFERENCE_MANAGER_CLI_DEFAULT_LIMIT;
585
624
  const defaultLimit = envLimit !== void 0 ? Number(envLimit) : partial?.defaultLimit ?? defaultConfig.cli.defaultLimit;
@@ -587,9 +626,9 @@ function fillCliDefaults(partial) {
587
626
  defaultLimit,
588
627
  defaultSort: partial?.defaultSort ?? defaultConfig.cli.defaultSort,
589
628
  defaultOrder: partial?.defaultOrder ?? defaultConfig.cli.defaultOrder,
590
- interactive: {
591
- limit: partial?.interactive?.limit ?? defaultConfig.cli.interactive.limit,
592
- debounceMs: partial?.interactive?.debounceMs ?? defaultConfig.cli.interactive.debounceMs
629
+ tui: {
630
+ limit: partial?.tui?.limit ?? defaultConfig.cli.tui.limit,
631
+ debounceMs: partial?.tui?.debounceMs ?? defaultConfig.cli.tui.debounceMs
593
632
  },
594
633
  edit: {
595
634
  defaultFormat: partial?.edit?.defaultFormat ?? defaultConfig.cli.edit.defaultFormat
@@ -646,4 +685,4 @@ export {
646
685
  partialConfigSchema as p,
647
686
  watchConfigSchema as w
648
687
  };
649
- //# sourceMappingURL=loader-C1EpnyPm.js.map
688
+ //# sourceMappingURL=loader-4FFB4igw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-4FFB4igw.js","sources":["../../src/utils/opener.ts","../../src/config/schema.ts","../../node_modules/env-paths/index.js","../../src/config/paths.ts","../../src/config/defaults.ts","../../src/config/loader.ts"],"sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\n\n/**\n * Detect if running in Windows Subsystem for Linux (WSL)\n */\nexport function isWSL(): boolean {\n // Check for WSL_DISTRO_NAME environment variable\n if (process.env.WSL_DISTRO_NAME !== undefined) {\n return true;\n }\n\n // Check for WSLInterop file\n try {\n return fs.existsSync(\"/proc/sys/fs/binfmt_misc/WSLInterop\");\n } catch {\n return false;\n }\n}\n\n/**\n * Get the system opener command for the specified platform.\n * @param platform - The platform (darwin, linux, win32)\n * @param wsl - Whether running in WSL (defaults to isWSL())\n * @returns The command array to execute\n */\nexport function getOpenerCommand(platform: string, wsl: boolean = isWSL()): string[] {\n switch (platform) {\n case \"darwin\":\n return [\"open\"];\n case \"linux\":\n if (wsl) {\n return [\"wslview\"];\n }\n return [\"xdg-open\"];\n case \"win32\":\n return [\"cmd\", \"/c\", \"start\", \"\"];\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n}\n\n/**\n * Open a file with the system's default application.\n * @param filePath - The path to the file to open\n * @param platform - The platform (defaults to process.platform)\n */\nexport async function openWithSystemApp(\n filePath: string,\n platform: string = process.platform\n): Promise<void> {\n const commandParts = getOpenerCommand(platform);\n const [command, ...baseArgs] = commandParts;\n const args = [...baseArgs, filePath];\n\n return new Promise((resolve, reject) => {\n const proc: ChildProcess = spawn(command as string, args, {\n detached: true,\n stdio: \"ignore\",\n });\n\n proc.on(\"error\", () => {\n reject(new Error(`Failed to open file: ${filePath}`));\n });\n\n proc.on(\"close\", (code: number | null) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Failed to open file: ${filePath}`));\n }\n });\n\n proc.unref();\n });\n}\n","/**\n * Configuration schema using Zod\n */\n\nimport { z } from \"zod\";\nimport { sortFieldSchema, sortOrderSchema } from \"../features/pagination/types.js\";\n\n/**\n * Log level schema\n */\nexport const logLevelSchema = z.enum([\"silent\", \"info\", \"debug\"]);\n\n/**\n * TUI (interactive) search configuration schema\n */\nexport const tuiConfigSchema = z.object({\n limit: z.number().int().nonnegative(),\n debounceMs: z.number().int().nonnegative(),\n});\n\n/**\n * Edit format schema\n */\nexport const editFormatSchema = z.enum([\"yaml\", \"json\"]);\n\n/**\n * Edit command configuration schema\n */\nexport const editConfigSchema = z.object({\n defaultFormat: editFormatSchema,\n});\n\n/**\n * CLI configuration schema\n */\nexport const cliConfigSchema = z.object({\n defaultLimit: z.number().int().nonnegative(),\n defaultSort: sortFieldSchema,\n defaultOrder: sortOrderSchema,\n tui: tuiConfigSchema,\n edit: editConfigSchema,\n});\n\n/**\n * MCP configuration schema\n */\nexport const mcpConfigSchema = z.object({\n defaultLimit: z.number().int().nonnegative(),\n});\n\n/**\n * Backup configuration schema\n */\nexport const backupConfigSchema = z.object({\n maxGenerations: z.number().int().positive(),\n maxAgeDays: z.number().int().positive(),\n directory: z.string().min(1),\n});\n\n/**\n * File watching configuration schema\n * Note: File watching is always enabled in server mode (HTTP/MCP).\n * CLI mode does not use file watching.\n */\nexport const watchConfigSchema = z.object({\n debounceMs: z.number().int().nonnegative(),\n pollIntervalMs: z.number().int().positive(),\n retryIntervalMs: z.number().int().positive(),\n maxRetries: z.number().int().nonnegative(),\n});\n\n/**\n * Server configuration schema\n */\nexport const serverConfigSchema = z.object({\n autoStart: z.boolean(),\n autoStopMinutes: z.number().int().nonnegative(),\n});\n\n/**\n * Citation format schema\n */\nexport const citationFormatSchema = z.enum([\"text\", \"html\", \"rtf\"]);\n\n/**\n * Citation configuration schema\n */\nexport const citationConfigSchema = z.object({\n defaultStyle: z.string(),\n cslDirectory: z.array(z.string()),\n defaultLocale: z.string(),\n defaultFormat: citationFormatSchema,\n});\n\n/**\n * PubMed API configuration schema\n */\nexport const pubmedConfigSchema = z.object({\n email: z.string().optional(),\n apiKey: z.string().optional(),\n});\n\n/**\n * Fulltext storage configuration schema\n */\nexport const fulltextConfigSchema = z.object({\n directory: z.string().min(1),\n});\n\n/**\n * Attachments storage configuration schema\n */\nexport const attachmentsConfigSchema = z.object({\n directory: z.string().min(1),\n});\n\n/**\n * Complete configuration schema\n */\nexport const configSchema = z.object({\n library: z.string().min(1),\n logLevel: logLevelSchema,\n backup: backupConfigSchema,\n watch: watchConfigSchema,\n server: serverConfigSchema,\n citation: citationConfigSchema,\n pubmed: pubmedConfigSchema,\n fulltext: fulltextConfigSchema,\n attachments: attachmentsConfigSchema,\n cli: cliConfigSchema,\n mcp: mcpConfigSchema,\n});\n\n/**\n * Partial configuration schema (for TOML files)\n * Supports both camelCase and snake_case field names\n */\nexport const partialConfigSchema = z\n .object({\n library: z.string().min(1).optional(),\n logLevel: logLevelSchema.optional(),\n log_level: logLevelSchema.optional(), // snake_case support\n backup: z\n .object({\n maxGenerations: z.number().int().positive().optional(),\n max_generations: z.number().int().positive().optional(),\n maxAgeDays: z.number().int().positive().optional(),\n max_age_days: z.number().int().positive().optional(),\n directory: z.string().min(1).optional(),\n })\n .optional(),\n watch: z\n .object({\n debounceMs: z.number().int().nonnegative().optional(),\n debounce_ms: z.number().int().nonnegative().optional(),\n pollIntervalMs: z.number().int().positive().optional(),\n poll_interval_ms: z.number().int().positive().optional(),\n retryIntervalMs: z.number().int().positive().optional(),\n retry_interval_ms: z.number().int().positive().optional(),\n maxRetries: z.number().int().nonnegative().optional(),\n max_retries: z.number().int().nonnegative().optional(),\n })\n .optional(),\n server: z\n .object({\n autoStart: z.boolean().optional(),\n auto_start: z.boolean().optional(),\n autoStopMinutes: z.number().int().nonnegative().optional(),\n auto_stop_minutes: z.number().int().nonnegative().optional(),\n })\n .optional(),\n citation: z\n .object({\n defaultStyle: z.string().optional(),\n default_style: z.string().optional(),\n cslDirectory: z.union([z.string(), z.array(z.string())]).optional(),\n csl_directory: z.union([z.string(), z.array(z.string())]).optional(),\n defaultLocale: z.string().optional(),\n default_locale: z.string().optional(),\n defaultFormat: citationFormatSchema.optional(),\n default_format: citationFormatSchema.optional(),\n })\n .optional(),\n pubmed: z\n .object({\n email: z.string().optional(),\n apiKey: z.string().optional(),\n api_key: z.string().optional(),\n })\n .optional(),\n fulltext: z\n .object({\n directory: z.string().min(1).optional(),\n })\n .optional(),\n attachments: z\n .object({\n directory: z.string().min(1).optional(),\n })\n .optional(),\n cli: z\n .object({\n defaultLimit: z.number().int().nonnegative().optional(),\n default_limit: z.number().int().nonnegative().optional(),\n defaultSort: sortFieldSchema.optional(),\n default_sort: sortFieldSchema.optional(),\n defaultOrder: sortOrderSchema.optional(),\n default_order: sortOrderSchema.optional(),\n tui: z\n .object({\n limit: z.number().int().nonnegative().optional(),\n debounceMs: z.number().int().nonnegative().optional(),\n debounce_ms: z.number().int().nonnegative().optional(),\n })\n .optional(),\n edit: z\n .object({\n defaultFormat: editFormatSchema.optional(),\n default_format: editFormatSchema.optional(),\n })\n .optional(),\n })\n .optional(),\n mcp: z\n .object({\n defaultLimit: z.number().int().nonnegative().optional(),\n default_limit: z.number().int().nonnegative().optional(),\n })\n .optional(),\n })\n .passthrough(); // Allow unknown fields in TOML files\n\n/**\n * Inferred types from schemas\n */\nexport type LogLevel = z.infer<typeof logLevelSchema>;\nexport type BackupConfig = z.infer<typeof backupConfigSchema>;\nexport type WatchConfig = z.infer<typeof watchConfigSchema>;\nexport type ServerConfig = z.infer<typeof serverConfigSchema>;\nexport type CitationFormat = z.infer<typeof citationFormatSchema>;\nexport type CitationConfig = z.infer<typeof citationConfigSchema>;\nexport type PubmedConfig = z.infer<typeof pubmedConfigSchema>;\nexport type FulltextConfig = z.infer<typeof fulltextConfigSchema>;\nexport type AttachmentsConfig = z.infer<typeof attachmentsConfigSchema>;\nexport type TuiConfig = z.infer<typeof tuiConfigSchema>;\nexport type EditConfigFormat = z.infer<typeof editFormatSchema>;\nexport type EditConfig = z.infer<typeof editConfigSchema>;\nexport type CliConfig = z.infer<typeof cliConfigSchema>;\nexport type McpConfig = z.infer<typeof mcpConfigSchema>;\nexport type Config = z.infer<typeof configSchema>;\nexport type PartialConfig = z.infer<typeof partialConfigSchema>;\n\n/**\n * Deep partial type for Config\n */\nexport type DeepPartialConfig = {\n library?: string;\n logLevel?: LogLevel;\n backup?: Partial<BackupConfig>;\n watch?: Partial<WatchConfig>;\n server?: Partial<ServerConfig>;\n citation?: Partial<CitationConfig>;\n pubmed?: Partial<PubmedConfig>;\n fulltext?: Partial<FulltextConfig>;\n attachments?: Partial<AttachmentsConfig>;\n cli?: Partial<Omit<CliConfig, \"tui\" | \"edit\">> & {\n tui?: Partial<TuiConfig>;\n edit?: Partial<EditConfig>;\n };\n mcp?: Partial<McpConfig>;\n};\n\n/**\n * Normalize backup configuration from snake_case to camelCase\n */\nfunction normalizeBackupConfig(\n backup: Partial<{\n maxGenerations?: number;\n max_generations?: number;\n maxAgeDays?: number;\n max_age_days?: number;\n directory?: string;\n }>\n): Partial<BackupConfig> | undefined {\n const normalized: Partial<BackupConfig> = {};\n\n const maxGenerations = backup.maxGenerations ?? backup.max_generations;\n if (maxGenerations !== undefined) {\n normalized.maxGenerations = maxGenerations;\n }\n\n const maxAgeDays = backup.maxAgeDays ?? backup.max_age_days;\n if (maxAgeDays !== undefined) {\n normalized.maxAgeDays = maxAgeDays;\n }\n\n if (backup.directory !== undefined) {\n normalized.directory = backup.directory;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize watch configuration from snake_case to camelCase\n */\nfunction normalizeWatchConfig(\n watch: Partial<{\n debounceMs?: number;\n debounce_ms?: number;\n pollIntervalMs?: number;\n poll_interval_ms?: number;\n retryIntervalMs?: number;\n retry_interval_ms?: number;\n maxRetries?: number;\n max_retries?: number;\n }>\n): Partial<WatchConfig> | undefined {\n const normalized: Partial<WatchConfig> = {};\n\n const debounceMs = watch.debounceMs ?? watch.debounce_ms;\n if (debounceMs !== undefined) {\n normalized.debounceMs = debounceMs;\n }\n\n const pollIntervalMs = watch.pollIntervalMs ?? watch.poll_interval_ms;\n if (pollIntervalMs !== undefined) {\n normalized.pollIntervalMs = pollIntervalMs;\n }\n\n const retryIntervalMs = watch.retryIntervalMs ?? watch.retry_interval_ms;\n if (retryIntervalMs !== undefined) {\n normalized.retryIntervalMs = retryIntervalMs;\n }\n\n const maxRetries = watch.maxRetries ?? watch.max_retries;\n if (maxRetries !== undefined) {\n normalized.maxRetries = maxRetries;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize server configuration from snake_case to camelCase\n */\nfunction normalizeServerConfig(\n server: Partial<{\n autoStart?: boolean;\n auto_start?: boolean;\n autoStopMinutes?: number;\n auto_stop_minutes?: number;\n }>\n): Partial<ServerConfig> | undefined {\n const normalized: Partial<ServerConfig> = {};\n\n const autoStart = server.autoStart ?? server.auto_start;\n if (autoStart !== undefined) {\n normalized.autoStart = autoStart;\n }\n\n const autoStopMinutes = server.autoStopMinutes ?? server.auto_stop_minutes;\n if (autoStopMinutes !== undefined) {\n normalized.autoStopMinutes = autoStopMinutes;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize citation configuration from snake_case to camelCase\n */\nfunction normalizeCitationConfig(\n citation: Partial<{\n defaultStyle?: string;\n default_style?: string;\n cslDirectory?: string | string[];\n csl_directory?: string | string[];\n defaultLocale?: string;\n default_locale?: string;\n defaultFormat?: CitationFormat;\n default_format?: CitationFormat;\n }>\n): Partial<CitationConfig> | undefined {\n const normalized: Partial<CitationConfig> = {};\n\n const defaultStyle = citation.defaultStyle ?? citation.default_style;\n if (defaultStyle !== undefined) {\n normalized.defaultStyle = defaultStyle;\n }\n\n const cslDirectory = citation.cslDirectory ?? citation.csl_directory;\n if (cslDirectory !== undefined) {\n // Normalize to array: string -> [string]\n normalized.cslDirectory = Array.isArray(cslDirectory) ? cslDirectory : [cslDirectory];\n }\n\n const defaultLocale = citation.defaultLocale ?? citation.default_locale;\n if (defaultLocale !== undefined) {\n normalized.defaultLocale = defaultLocale;\n }\n\n const defaultFormat = citation.defaultFormat ?? citation.default_format;\n if (defaultFormat !== undefined) {\n normalized.defaultFormat = defaultFormat;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize pubmed configuration from snake_case to camelCase\n */\nfunction normalizePubmedConfig(\n pubmed: Partial<{\n email?: string;\n apiKey?: string;\n api_key?: string;\n }>\n): Partial<PubmedConfig> | undefined {\n const normalized: Partial<PubmedConfig> = {};\n\n if (pubmed.email !== undefined) {\n normalized.email = pubmed.email;\n }\n\n const apiKey = pubmed.apiKey ?? pubmed.api_key;\n if (apiKey !== undefined) {\n normalized.apiKey = apiKey;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Section normalizers mapping\n */\nconst sectionNormalizers = {\n backup: normalizeBackupConfig,\n watch: normalizeWatchConfig,\n server: normalizeServerConfig,\n citation: normalizeCitationConfig,\n pubmed: normalizePubmedConfig,\n fulltext: normalizeFulltextConfig,\n attachments: normalizeAttachmentsConfig,\n cli: normalizeCliConfig,\n mcp: normalizeMcpConfig,\n} as const;\n\ntype SectionKey = keyof typeof sectionNormalizers;\n\n/**\n * Helper to apply a normalizer function to a config section\n */\nfunction applyNormalizer<K extends SectionKey>(\n normalized: DeepPartialConfig,\n partial: PartialConfig,\n key: K,\n normalizer: (typeof sectionNormalizers)[K]\n): void {\n const value = partial[key];\n if (value !== undefined) {\n const result = (normalizer as (input: unknown) => DeepPartialConfig[K] | undefined)(value);\n if (result) {\n normalized[key] = result;\n }\n }\n}\n\n/**\n * Normalize snake_case fields to camelCase\n */\nexport function normalizePartialConfig(partial: PartialConfig): DeepPartialConfig {\n const normalized: DeepPartialConfig = {};\n\n // Simple fields\n if (partial.library !== undefined) {\n normalized.library = partial.library;\n }\n const logLevel = partial.logLevel ?? partial.log_level;\n if (logLevel !== undefined) {\n normalized.logLevel = logLevel;\n }\n\n // Section fields\n for (const key of Object.keys(sectionNormalizers) as SectionKey[]) {\n applyNormalizer(normalized, partial, key, sectionNormalizers[key]);\n }\n\n return normalized;\n}\n\n/**\n * Normalize fulltext configuration\n */\nfunction normalizeFulltextConfig(fulltext: {\n directory?: string | undefined;\n}): Partial<FulltextConfig> | undefined {\n const normalized: Partial<FulltextConfig> = {};\n\n if (fulltext.directory !== undefined) {\n normalized.directory = fulltext.directory;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize attachments configuration\n */\nfunction normalizeAttachmentsConfig(attachments: {\n directory?: string | undefined;\n}): Partial<AttachmentsConfig> | undefined {\n const normalized: Partial<AttachmentsConfig> = {};\n\n if (attachments.directory !== undefined) {\n normalized.directory = attachments.directory;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize TUI config subsection\n */\nfunction normalizeTuiSection(\n tui: Partial<{\n limit?: number;\n debounceMs?: number;\n debounce_ms?: number;\n }>\n): Partial<TuiConfig> | undefined {\n const normalized: Partial<TuiConfig> = {};\n if (tui.limit !== undefined) {\n normalized.limit = tui.limit;\n }\n const debounceMs = tui.debounceMs ?? tui.debounce_ms;\n if (debounceMs !== undefined) {\n normalized.debounceMs = debounceMs;\n }\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize edit config subsection\n */\nfunction normalizeEditSection(\n edit: Partial<{\n defaultFormat?: EditConfigFormat;\n default_format?: EditConfigFormat;\n }>\n): Partial<EditConfig> | undefined {\n const normalized: Partial<EditConfig> = {};\n const defaultFormat = edit.defaultFormat ?? edit.default_format;\n if (defaultFormat !== undefined) {\n normalized.defaultFormat = defaultFormat;\n }\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize CLI configuration from snake_case to camelCase\n */\nfunction normalizeCliConfig(\n cli: Partial<{\n defaultLimit?: number;\n default_limit?: number;\n defaultSort?: CliConfig[\"defaultSort\"];\n default_sort?: CliConfig[\"defaultSort\"];\n defaultOrder?: CliConfig[\"defaultOrder\"];\n default_order?: CliConfig[\"defaultOrder\"];\n tui?: Partial<{\n limit?: number;\n debounceMs?: number;\n debounce_ms?: number;\n }>;\n edit?: Partial<{\n defaultFormat?: EditConfigFormat;\n default_format?: EditConfigFormat;\n }>;\n }>\n): Partial<CliConfig> | undefined {\n const normalized: Partial<CliConfig> = {};\n\n const defaultLimit = cli.defaultLimit ?? cli.default_limit;\n if (defaultLimit !== undefined) {\n normalized.defaultLimit = defaultLimit;\n }\n\n const defaultSort = cli.defaultSort ?? cli.default_sort;\n if (defaultSort !== undefined) {\n normalized.defaultSort = defaultSort;\n }\n\n const defaultOrder = cli.defaultOrder ?? cli.default_order;\n if (defaultOrder !== undefined) {\n normalized.defaultOrder = defaultOrder;\n }\n\n if (cli.tui !== undefined) {\n const tui = normalizeTuiSection(cli.tui);\n if (tui) {\n normalized.tui = tui as TuiConfig;\n }\n }\n\n if (cli.edit !== undefined) {\n const edit = normalizeEditSection(cli.edit);\n if (edit) {\n normalized.edit = edit as EditConfig;\n }\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\n/**\n * Normalize MCP configuration from snake_case to camelCase\n */\nfunction normalizeMcpConfig(\n mcp: Partial<{\n defaultLimit?: number;\n default_limit?: number;\n }>\n): Partial<McpConfig> | undefined {\n const normalized: Partial<McpConfig> = {};\n\n const defaultLimit = mcp.defaultLimit ?? mcp.default_limit;\n if (defaultLimit !== undefined) {\n normalized.defaultLimit = defaultLimit;\n }\n\n return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n","import path from 'node:path';\nimport os from 'node:os';\nimport process from 'node:process';\n\nconst homedir = os.homedir();\nconst tmpdir = os.tmpdir();\nconst {env} = process;\n\nconst macos = name => {\n\tconst library = path.join(homedir, 'Library');\n\n\treturn {\n\t\tdata: path.join(library, 'Application Support', name),\n\t\tconfig: path.join(library, 'Preferences', name),\n\t\tcache: path.join(library, 'Caches', name),\n\t\tlog: path.join(library, 'Logs', name),\n\t\ttemp: path.join(tmpdir, name),\n\t};\n};\n\nconst windows = name => {\n\tconst appData = env.APPDATA || path.join(homedir, 'AppData', 'Roaming');\n\tconst localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');\n\n\treturn {\n\t\t// Data/config/cache/log are invented by me as Windows isn't opinionated about this\n\t\tdata: path.join(localAppData, name, 'Data'),\n\t\tconfig: path.join(appData, name, 'Config'),\n\t\tcache: path.join(localAppData, name, 'Cache'),\n\t\tlog: path.join(localAppData, name, 'Log'),\n\t\ttemp: path.join(tmpdir, name),\n\t};\n};\n\n// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\nconst linux = name => {\n\tconst username = path.basename(homedir);\n\n\treturn {\n\t\tdata: path.join(env.XDG_DATA_HOME || path.join(homedir, '.local', 'share'), name),\n\t\tconfig: path.join(env.XDG_CONFIG_HOME || path.join(homedir, '.config'), name),\n\t\tcache: path.join(env.XDG_CACHE_HOME || path.join(homedir, '.cache'), name),\n\t\t// https://wiki.debian.org/XDGBaseDirectorySpecification#state\n\t\tlog: path.join(env.XDG_STATE_HOME || path.join(homedir, '.local', 'state'), name),\n\t\ttemp: path.join(tmpdir, username, name),\n\t};\n};\n\nexport default function envPaths(name, {suffix = 'nodejs'} = {}) {\n\tif (typeof name !== 'string') {\n\t\tthrow new TypeError(`Expected a string, got ${typeof name}`);\n\t}\n\n\tif (suffix) {\n\t\t// Add suffix to prevent possible conflict with native apps\n\t\tname += `-${suffix}`;\n\t}\n\n\tif (process.platform === 'darwin') {\n\t\treturn macos(name);\n\t}\n\n\tif (process.platform === 'win32') {\n\t\treturn windows(name);\n\t}\n\n\treturn linux(name);\n}\n","/**\n * Platform-specific paths using env-paths\n *\n * Returns XDG-compliant paths on Linux, standard paths on macOS/Windows\n */\n\nimport envPaths from \"env-paths\";\n\nconst paths = envPaths(\"reference-manager\", { suffix: \"\" });\n\nexport interface Paths {\n config: string;\n data: string;\n cache: string;\n}\n\n/**\n * Get platform-specific paths for config, data, and cache directories\n *\n * - Linux: XDG Base Directory Specification (~/.config, ~/.local/share, ~/.cache)\n * - macOS: ~/Library/Preferences, ~/Library/Application Support, ~/Library/Caches\n * - Windows: %APPDATA%, %LOCALAPPDATA%\n */\nexport function getPaths(): Paths {\n return {\n config: paths.config,\n data: paths.data,\n cache: paths.cache,\n };\n}\n","/**\n * Default configuration values\n */\n\nimport { join } from \"node:path\";\nimport { getPaths } from \"./paths.js\";\nimport type { Config } from \"./schema.js\";\n\n/**\n * Get the default backup directory\n * Uses platform-specific cache path + backups/\n */\nexport function getDefaultBackupDirectory(): string {\n return join(getPaths().cache, \"backups\");\n}\n\n/**\n * Get the default library path\n * Uses platform-specific data path + library.json\n */\nexport function getDefaultLibraryPath(): string {\n return join(getPaths().data, \"library.json\");\n}\n\n/**\n * Get the default user config path\n * Uses platform-specific config path + config.toml\n */\nexport function getDefaultUserConfigPath(): string {\n return join(getPaths().config, \"config.toml\");\n}\n\n/**\n * Get the default current directory config filename\n * Uses .reference-manager.config.toml\n */\nexport function getDefaultCurrentDirConfigFilename(): string {\n return \".reference-manager.config.toml\";\n}\n\n/**\n * Get the default CSL directory\n * Uses platform-specific data path + csl/\n */\nexport function getDefaultCslDirectory(): string {\n return join(getPaths().data, \"csl\");\n}\n\n/**\n * Get the default fulltext directory\n * @deprecated Use getDefaultAttachmentsDirectory() instead.\n * Fulltext is now stored in the attachments directory.\n */\nexport function getDefaultFulltextDirectory(): string {\n return getDefaultAttachmentsDirectory();\n}\n\n/**\n * Get the default attachments directory\n * Uses platform-specific data path + attachments/\n */\nexport function getDefaultAttachmentsDirectory(): string {\n return join(getPaths().data, \"attachments\");\n}\n\n/**\n * Default configuration\n */\nexport const defaultConfig: Config = {\n library: getDefaultLibraryPath(),\n logLevel: \"info\",\n backup: {\n maxGenerations: 50,\n maxAgeDays: 365,\n directory: getDefaultBackupDirectory(),\n },\n watch: {\n debounceMs: 500,\n pollIntervalMs: 5000,\n retryIntervalMs: 200,\n maxRetries: 10,\n },\n server: {\n autoStart: false,\n autoStopMinutes: 0,\n },\n citation: {\n defaultStyle: \"apa\",\n cslDirectory: [getDefaultCslDirectory()],\n defaultLocale: \"en-US\",\n defaultFormat: \"text\",\n },\n pubmed: {\n email: undefined,\n apiKey: undefined,\n },\n fulltext: {\n directory: getDefaultAttachmentsDirectory(),\n },\n attachments: {\n directory: getDefaultAttachmentsDirectory(),\n },\n cli: {\n defaultLimit: 0,\n defaultSort: \"updated\",\n defaultOrder: \"desc\",\n tui: {\n limit: 20,\n debounceMs: 200,\n },\n edit: {\n defaultFormat: \"yaml\",\n },\n },\n mcp: {\n defaultLimit: 20,\n },\n};\n","/**\n * Configuration loader\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { parse as parseTOML } from \"@iarna/toml\";\nimport {\n defaultConfig,\n getDefaultCurrentDirConfigFilename,\n getDefaultUserConfigPath,\n} from \"./defaults.js\";\nimport {\n type Config,\n type DeepPartialConfig,\n type PartialConfig,\n configSchema,\n normalizePartialConfig,\n partialConfigSchema,\n} from \"./schema.js\";\n\n/**\n * Options for loading configuration\n */\nexport interface LoadConfigOptions {\n /** Current working directory (default: process.cwd()) */\n cwd?: string;\n /** User config path (default: ~/.reference-manager/config.toml) */\n userConfigPath?: string;\n /** CLI argument overrides */\n overrides?: Partial<Config>;\n}\n\n/**\n * Load and parse a TOML config file\n */\nfunction loadTOMLFile(path: string): PartialConfig | null {\n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const content = readFileSync(path, \"utf-8\");\n const parsed = parseTOML(content);\n\n // Validate with partial schema\n const validated = partialConfigSchema.parse(parsed);\n return validated;\n } catch (error) {\n throw new Error(\n `Failed to load config from ${path}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * Merge CLI config with nested interactive section\n */\nfunction mergeCliConfig(\n base: DeepPartialConfig[\"cli\"],\n override: NonNullable<DeepPartialConfig[\"cli\"]>\n): NonNullable<DeepPartialConfig[\"cli\"]> {\n const { tui: overrideTui, ...overrideCliRest } = override;\n const { tui: baseTui, ...baseCliRest } = base ?? {};\n const mergedTui = overrideTui !== undefined ? { ...baseTui, ...overrideTui } : baseTui;\n return {\n ...baseCliRest,\n ...overrideCliRest,\n ...(mergedTui !== undefined ? { tui: mergedTui } : {}),\n };\n}\n\n/**\n * Merge partial configurations\n * Later configs override earlier ones\n */\nfunction mergeConfigs(\n base: DeepPartialConfig,\n ...overrides: (DeepPartialConfig | null | undefined)[]\n): DeepPartialConfig {\n const result: DeepPartialConfig = { ...base };\n\n const sectionKeys = [\n \"backup\",\n \"watch\",\n \"server\",\n \"citation\",\n \"pubmed\",\n \"fulltext\",\n \"mcp\",\n ] as const;\n\n for (const override of overrides) {\n if (!override) continue;\n\n // Merge top-level primitive fields\n if (override.library !== undefined) {\n result.library = override.library;\n }\n if (override.logLevel !== undefined) {\n result.logLevel = override.logLevel;\n }\n\n // Merge section configs\n for (const key of sectionKeys) {\n if (override[key] !== undefined) {\n result[key] = {\n ...result[key],\n ...override[key],\n };\n }\n }\n\n // Merge cli config with nested interactive\n if (override.cli !== undefined) {\n result.cli = mergeCliConfig(result.cli, override.cli);\n }\n }\n\n return result;\n}\n\n/**\n * Fill missing fields with defaults\n */\nfunction fillDefaults(partial: DeepPartialConfig): Config {\n const envLibrary = process.env.REFERENCE_MANAGER_LIBRARY;\n const library = envLibrary ?? partial.library ?? defaultConfig.library;\n return {\n library: expandTilde(library),\n logLevel: partial.logLevel ?? defaultConfig.logLevel,\n backup: {\n maxGenerations: partial.backup?.maxGenerations ?? defaultConfig.backup.maxGenerations,\n maxAgeDays: partial.backup?.maxAgeDays ?? defaultConfig.backup.maxAgeDays,\n directory: partial.backup?.directory ?? defaultConfig.backup.directory,\n },\n watch: {\n debounceMs: partial.watch?.debounceMs ?? defaultConfig.watch.debounceMs,\n pollIntervalMs: partial.watch?.pollIntervalMs ?? defaultConfig.watch.pollIntervalMs,\n retryIntervalMs: partial.watch?.retryIntervalMs ?? defaultConfig.watch.retryIntervalMs,\n maxRetries: partial.watch?.maxRetries ?? defaultConfig.watch.maxRetries,\n },\n server: {\n autoStart: partial.server?.autoStart ?? defaultConfig.server.autoStart,\n autoStopMinutes: partial.server?.autoStopMinutes ?? defaultConfig.server.autoStopMinutes,\n },\n citation: fillCitationDefaults(partial.citation),\n pubmed: fillPubmedDefaults(partial.pubmed),\n fulltext: fillFulltextDefaults(partial.fulltext),\n attachments: fillAttachmentsDefaults(partial.attachments),\n cli: fillCliDefaults(partial.cli),\n mcp: fillMcpDefaults(partial.mcp),\n };\n}\n\n/**\n * Fill citation config with defaults\n */\nfunction fillCitationDefaults(partial: DeepPartialConfig[\"citation\"]): Config[\"citation\"] {\n return {\n defaultStyle: partial?.defaultStyle ?? defaultConfig.citation.defaultStyle,\n cslDirectory: partial?.cslDirectory ?? defaultConfig.citation.cslDirectory,\n defaultLocale: partial?.defaultLocale ?? defaultConfig.citation.defaultLocale,\n defaultFormat: partial?.defaultFormat ?? defaultConfig.citation.defaultFormat,\n };\n}\n\n/**\n * Fill pubmed config with defaults\n * Environment variables take priority over config file values\n */\nfunction fillPubmedDefaults(partial: DeepPartialConfig[\"pubmed\"]): Config[\"pubmed\"] {\n // Environment variables take priority\n const email = process.env.PUBMED_EMAIL ?? partial?.email ?? defaultConfig.pubmed.email;\n const apiKey = process.env.PUBMED_API_KEY ?? partial?.apiKey ?? defaultConfig.pubmed.apiKey;\n\n return {\n email,\n apiKey,\n };\n}\n\n/**\n * Expand ~ to home directory\n */\nfunction expandTilde(path: string): string {\n if (path.startsWith(\"~/\")) {\n return join(homedir(), path.slice(2));\n }\n return path;\n}\n\n/**\n * Fill fulltext config with defaults\n *\n * @deprecated Fulltext now uses attachments directory.\n * Priority:\n * 1. Environment variable REFERENCE_MANAGER_ATTACHMENTS_DIR\n * 2. Config file setting\n * 3. Default value (same as attachments.directory)\n */\nfunction fillFulltextDefaults(partial: DeepPartialConfig[\"fulltext\"]): Config[\"fulltext\"] {\n const envDir = process.env.REFERENCE_MANAGER_ATTACHMENTS_DIR;\n const directory = envDir ?? partial?.directory ?? defaultConfig.fulltext.directory;\n return {\n directory: expandTilde(directory),\n };\n}\n\n/**\n * Fill attachments config with defaults\n *\n * Priority:\n * 1. Environment variable REFERENCE_MANAGER_ATTACHMENTS_DIR\n * 2. Config file setting\n * 3. Default value\n */\nfunction fillAttachmentsDefaults(partial: DeepPartialConfig[\"attachments\"]): Config[\"attachments\"] {\n const envDir = process.env.REFERENCE_MANAGER_ATTACHMENTS_DIR;\n const directory = envDir ?? partial?.directory ?? defaultConfig.attachments.directory;\n return {\n directory: expandTilde(directory),\n };\n}\n\n/**\n * Fill CLI config with defaults\n *\n * Priority:\n * 1. Environment variable REFERENCE_MANAGER_CLI_DEFAULT_LIMIT\n * 2. Config file setting\n * 3. Default value\n */\nfunction fillCliDefaults(partial: DeepPartialConfig[\"cli\"]): Config[\"cli\"] {\n const envLimit = process.env.REFERENCE_MANAGER_CLI_DEFAULT_LIMIT;\n const defaultLimit =\n envLimit !== undefined\n ? Number(envLimit)\n : (partial?.defaultLimit ?? defaultConfig.cli.defaultLimit);\n return {\n defaultLimit,\n defaultSort: partial?.defaultSort ?? defaultConfig.cli.defaultSort,\n defaultOrder: partial?.defaultOrder ?? defaultConfig.cli.defaultOrder,\n tui: {\n limit: partial?.tui?.limit ?? defaultConfig.cli.tui.limit,\n debounceMs: partial?.tui?.debounceMs ?? defaultConfig.cli.tui.debounceMs,\n },\n edit: {\n defaultFormat: partial?.edit?.defaultFormat ?? defaultConfig.cli.edit.defaultFormat,\n },\n };\n}\n\n/**\n * Fill MCP config with defaults\n *\n * Priority:\n * 1. Environment variable REFERENCE_MANAGER_MCP_DEFAULT_LIMIT\n * 2. Config file setting\n * 3. Default value\n */\nfunction fillMcpDefaults(partial: DeepPartialConfig[\"mcp\"]): Config[\"mcp\"] {\n const envLimit = process.env.REFERENCE_MANAGER_MCP_DEFAULT_LIMIT;\n const defaultLimit =\n envLimit !== undefined\n ? Number(envLimit)\n : (partial?.defaultLimit ?? defaultConfig.mcp.defaultLimit);\n return {\n defaultLimit,\n };\n}\n\n/**\n * Load configuration from multiple sources\n *\n * Priority (highest to lowest):\n * 1. CLI argument overrides\n * 2. Current directory config (.reference-manager.config.toml)\n * 3. Environment variable (REFERENCE_MANAGER_CONFIG)\n * 4. User config (~/.reference-manager/config.toml)\n * 5. Default values\n */\nexport function loadConfig(options: LoadConfigOptions = {}): Config {\n const cwd = options.cwd ?? process.cwd();\n const userConfigPath = options.userConfigPath ?? getDefaultUserConfigPath();\n\n // 1. Load user config (lowest priority)\n const userConfig = loadTOMLFile(userConfigPath);\n\n // 2. Load environment variable config\n const envConfigPath = process.env.REFERENCE_MANAGER_CONFIG;\n const envConfig = envConfigPath ? loadTOMLFile(envConfigPath) : null;\n\n // 3. Load current directory config (highest priority)\n const currentConfigPath = join(cwd, getDefaultCurrentDirConfigFilename());\n const currentConfig = loadTOMLFile(currentConfigPath);\n\n // Normalize snake_case to camelCase\n const normalizedUser = userConfig ? normalizePartialConfig(userConfig) : null;\n const normalizedEnv = envConfig ? normalizePartialConfig(envConfig) : null;\n const normalizedCurrent = currentConfig ? normalizePartialConfig(currentConfig) : null;\n\n // Merge configs (priority: current > env > user > defaults)\n const merged = mergeConfigs(\n {},\n normalizedUser,\n normalizedEnv,\n normalizedCurrent,\n options.overrides\n );\n\n // Fill missing fields with defaults\n const config = fillDefaults(merged);\n\n // Validate final config\n try {\n return configSchema.parse(config);\n } catch (error) {\n throw new Error(\n `Invalid configuration: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n"],"names":["fs","os","process","path","parseTOML","homedir"],"mappings":"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","x_google_ignoreList":[2]}
@@ -1,6 +1,6 @@
1
- import { t as tokenize, s as search } from "./file-watcher-D2Y-SlcE.js";
1
+ import { t as tokenize, s as search } from "./file-watcher-B_WpVHSV.js";
2
2
  import { runSearchPrompt } from "./search-prompt-BrWpOcij.js";
3
- import { checkTTY } from "./tty-CDBIQraQ.js";
3
+ import { checkTTY } from "./tty-BMyaEOhX.js";
4
4
  async function runReferenceSelect(allReferences, options, config) {
5
5
  checkTTY();
6
6
  const searchFn = (query) => {
@@ -49,4 +49,4 @@ export {
49
49
  selectReferenceItemsOrExit,
50
50
  selectReferencesOrExit
51
51
  };
52
- //# sourceMappingURL=reference-select-DSVwE9iu.js.map
52
+ //# sourceMappingURL=reference-select-B9w9CLa1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reference-select-DSVwE9iu.js","sources":["../../src/features/interactive/reference-select.ts"],"sourcesContent":["/**\n * Shared reference selection utility for interactive ID selection.\n *\n * This module provides a reusable function to select references interactively\n * using the existing search prompt infrastructure.\n */\n\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { search } from \"../search/matcher.js\";\nimport { tokenize } from \"../search/tokenizer.js\";\nimport { type SearchPromptConfig, runSearchPrompt } from \"./search-prompt.js\";\nimport { checkTTY } from \"./tty.js\";\n\n/**\n * Options for reference selection\n */\nexport interface ReferenceSelectOptions {\n /** Whether to allow multiple selection (default: true) */\n multiSelect: boolean;\n /** Custom prompt message */\n prompt?: string;\n /** Initial search query */\n initialQuery?: string;\n}\n\n/**\n * Result from reference selection\n */\nexport interface ReferenceSelectResult {\n /** Selected references */\n selected: CslItem[];\n /** Whether the selection was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Run interactive reference selection.\n *\n * Launches an interactive search prompt to select references from the library.\n * Supports both single and multiple selection modes.\n *\n * @param allReferences - All references available for selection\n * @param options - Selection options\n * @param config - Interactive prompt configuration\n * @returns Selection result with selected references\n * @throws TTYError if not running in a TTY environment\n */\nexport async function runReferenceSelect(\n allReferences: CslItem[],\n options: ReferenceSelectOptions,\n config: SearchPromptConfig\n): Promise<ReferenceSelectResult> {\n // Check TTY requirement\n checkTTY();\n\n // Create search function for runSearchPrompt\n const searchFn = (query: string) => {\n const { tokens } = tokenize(query);\n return search(allReferences, tokens);\n };\n\n // Run search prompt\n const searchResult = await runSearchPrompt(\n allReferences,\n searchFn,\n config,\n options.initialQuery ?? \"\"\n );\n\n if (searchResult.cancelled) {\n return { selected: [], cancelled: true };\n }\n\n // For single-select mode, return only the first selected item\n const selected = options.multiSelect ? searchResult.selected : searchResult.selected.slice(0, 1);\n\n return {\n selected,\n cancelled: false,\n };\n}\n\n/**\n * Options for selectReferencesOrExit helper\n */\nexport interface SelectReferencesOrExitOptions {\n /** Whether to allow multiple selection */\n multiSelect: boolean;\n /** Initial search query */\n initialQuery?: string;\n}\n\n/**\n * Select references interactively or exit if cancelled/empty.\n *\n * This is a convenience wrapper around runReferenceSelect that handles\n * common patterns:\n * - Exits with code 0 if library is empty\n * - Exits with code 0 if selection is cancelled\n * - Returns selected identifiers\n *\n * @param allReferences - All references available for selection\n * @param options - Selection options\n * @param config - Interactive prompt configuration\n * @returns Array of selected reference IDs (never empty)\n */\nexport async function selectReferencesOrExit(\n allReferences: CslItem[],\n options: SelectReferencesOrExitOptions,\n config: SearchPromptConfig\n): Promise<string[]> {\n if (allReferences.length === 0) {\n process.stderr.write(\"No references in library.\\n\");\n process.exit(0);\n }\n\n const selectResult = await runReferenceSelect(allReferences, options, config);\n\n if (selectResult.cancelled || selectResult.selected.length === 0) {\n process.exit(0);\n }\n\n return selectResult.selected.map((item) => item.id);\n}\n\n/**\n * Select reference items interactively or exit if cancelled/empty.\n *\n * Similar to selectReferencesOrExit but returns full CslItem objects\n * instead of just identifiers. Useful when the caller needs access to\n * the full reference data (e.g., for confirmation dialogs).\n *\n * @param allReferences - All references available for selection\n * @param options - Selection options\n * @param config - Interactive prompt configuration\n * @returns Array of selected CslItem objects (never empty)\n */\nexport async function selectReferenceItemsOrExit(\n allReferences: CslItem[],\n options: SelectReferencesOrExitOptions,\n config: SearchPromptConfig\n): Promise<CslItem[]> {\n if (allReferences.length === 0) {\n process.stderr.write(\"No references in library.\\n\");\n process.exit(0);\n }\n\n const selectResult = await runReferenceSelect(allReferences, options, config);\n\n if (selectResult.cancelled || selectResult.selected.length === 0) {\n process.exit(0);\n }\n\n return selectResult.selected;\n}\n"],"names":[],"mappings":";;;AA+CA,eAAsB,mBACpB,eACA,SACA,QACgC;AAEhC,WAAA;AAGA,QAAM,WAAW,CAAC,UAAkB;AAClC,UAAM,EAAE,OAAA,IAAW,SAAS,KAAK;AACjC,WAAO,OAAO,eAAe,MAAM;AAAA,EACrC;AAGA,QAAM,eAAe,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,gBAAgB;AAAA,EAAA;AAG1B,MAAI,aAAa,WAAW;AAC1B,WAAO,EAAE,UAAU,IAAI,WAAW,KAAA;AAAA,EACpC;AAGA,QAAM,WAAW,QAAQ,cAAc,aAAa,WAAW,aAAa,SAAS,MAAM,GAAG,CAAC;AAE/F,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,EAAA;AAEf;AA0BA,eAAsB,uBACpB,eACA,SACA,QACmB;AACnB,MAAI,cAAc,WAAW,GAAG;AAC9B,YAAQ,OAAO,MAAM,6BAA6B;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,eAAe,MAAM,mBAAmB,eAAe,SAAS,MAAM;AAE5E,MAAI,aAAa,aAAa,aAAa,SAAS,WAAW,GAAG;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,aAAa,SAAS,IAAI,CAAC,SAAS,KAAK,EAAE;AACpD;AAcA,eAAsB,2BACpB,eACA,SACA,QACoB;AACpB,MAAI,cAAc,WAAW,GAAG;AAC9B,YAAQ,OAAO,MAAM,6BAA6B;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,eAAe,MAAM,mBAAmB,eAAe,SAAS,MAAM;AAE5E,MAAI,aAAa,aAAa,aAAa,SAAS,WAAW,GAAG;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,aAAa;AACtB;"}
1
+ {"version":3,"file":"reference-select-B9w9CLa1.js","sources":["../../src/features/interactive/reference-select.ts"],"sourcesContent":["/**\n * Shared reference selection utility for interactive ID selection.\n *\n * This module provides a reusable function to select references interactively\n * using the existing search prompt infrastructure.\n */\n\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { search } from \"../search/matcher.js\";\nimport { tokenize } from \"../search/tokenizer.js\";\nimport { type SearchPromptConfig, runSearchPrompt } from \"./search-prompt.js\";\nimport { checkTTY } from \"./tty.js\";\n\n/**\n * Options for reference selection\n */\nexport interface ReferenceSelectOptions {\n /** Whether to allow multiple selection (default: true) */\n multiSelect: boolean;\n /** Custom prompt message */\n prompt?: string;\n /** Initial search query */\n initialQuery?: string;\n}\n\n/**\n * Result from reference selection\n */\nexport interface ReferenceSelectResult {\n /** Selected references */\n selected: CslItem[];\n /** Whether the selection was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Run interactive reference selection.\n *\n * Launches an interactive search prompt to select references from the library.\n * Supports both single and multiple selection modes.\n *\n * @param allReferences - All references available for selection\n * @param options - Selection options\n * @param config - Interactive prompt configuration\n * @returns Selection result with selected references\n * @throws TTYError if not running in a TTY environment\n */\nexport async function runReferenceSelect(\n allReferences: CslItem[],\n options: ReferenceSelectOptions,\n config: SearchPromptConfig\n): Promise<ReferenceSelectResult> {\n // Check TTY requirement\n checkTTY();\n\n // Create search function for runSearchPrompt\n const searchFn = (query: string) => {\n const { tokens } = tokenize(query);\n return search(allReferences, tokens);\n };\n\n // Run search prompt\n const searchResult = await runSearchPrompt(\n allReferences,\n searchFn,\n config,\n options.initialQuery ?? \"\"\n );\n\n if (searchResult.cancelled) {\n return { selected: [], cancelled: true };\n }\n\n // For single-select mode, return only the first selected item\n const selected = options.multiSelect ? searchResult.selected : searchResult.selected.slice(0, 1);\n\n return {\n selected,\n cancelled: false,\n };\n}\n\n/**\n * Options for selectReferencesOrExit helper\n */\nexport interface SelectReferencesOrExitOptions {\n /** Whether to allow multiple selection */\n multiSelect: boolean;\n /** Initial search query */\n initialQuery?: string;\n}\n\n/**\n * Select references interactively or exit if cancelled/empty.\n *\n * This is a convenience wrapper around runReferenceSelect that handles\n * common patterns:\n * - Exits with code 0 if library is empty\n * - Exits with code 0 if selection is cancelled\n * - Returns selected identifiers\n *\n * @param allReferences - All references available for selection\n * @param options - Selection options\n * @param config - Interactive prompt configuration\n * @returns Array of selected reference IDs (never empty)\n */\nexport async function selectReferencesOrExit(\n allReferences: CslItem[],\n options: SelectReferencesOrExitOptions,\n config: SearchPromptConfig\n): Promise<string[]> {\n if (allReferences.length === 0) {\n process.stderr.write(\"No references in library.\\n\");\n process.exit(0);\n }\n\n const selectResult = await runReferenceSelect(allReferences, options, config);\n\n if (selectResult.cancelled || selectResult.selected.length === 0) {\n process.exit(0);\n }\n\n return selectResult.selected.map((item) => item.id);\n}\n\n/**\n * Select reference items interactively or exit if cancelled/empty.\n *\n * Similar to selectReferencesOrExit but returns full CslItem objects\n * instead of just identifiers. Useful when the caller needs access to\n * the full reference data (e.g., for confirmation dialogs).\n *\n * @param allReferences - All references available for selection\n * @param options - Selection options\n * @param config - Interactive prompt configuration\n * @returns Array of selected CslItem objects (never empty)\n */\nexport async function selectReferenceItemsOrExit(\n allReferences: CslItem[],\n options: SelectReferencesOrExitOptions,\n config: SearchPromptConfig\n): Promise<CslItem[]> {\n if (allReferences.length === 0) {\n process.stderr.write(\"No references in library.\\n\");\n process.exit(0);\n }\n\n const selectResult = await runReferenceSelect(allReferences, options, config);\n\n if (selectResult.cancelled || selectResult.selected.length === 0) {\n process.exit(0);\n }\n\n return selectResult.selected;\n}\n"],"names":[],"mappings":";;;AA+CA,eAAsB,mBACpB,eACA,SACA,QACgC;AAEhC,WAAA;AAGA,QAAM,WAAW,CAAC,UAAkB;AAClC,UAAM,EAAE,OAAA,IAAW,SAAS,KAAK;AACjC,WAAO,OAAO,eAAe,MAAM;AAAA,EACrC;AAGA,QAAM,eAAe,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,gBAAgB;AAAA,EAAA;AAG1B,MAAI,aAAa,WAAW;AAC1B,WAAO,EAAE,UAAU,IAAI,WAAW,KAAA;AAAA,EACpC;AAGA,QAAM,WAAW,QAAQ,cAAc,aAAa,WAAW,aAAa,SAAS,MAAM,GAAG,CAAC;AAE/F,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,EAAA;AAEf;AA0BA,eAAsB,uBACpB,eACA,SACA,QACmB;AACnB,MAAI,cAAc,WAAW,GAAG;AAC9B,YAAQ,OAAO,MAAM,6BAA6B;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,eAAe,MAAM,mBAAmB,eAAe,SAAS,MAAM;AAE5E,MAAI,aAAa,aAAa,aAAa,SAAS,WAAW,GAAG;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,aAAa,SAAS,IAAI,CAAC,SAAS,KAAK,EAAE;AACpD;AAcA,eAAsB,2BACpB,eACA,SACA,QACoB;AACpB,MAAI,cAAc,WAAW,GAAG;AAC9B,YAAQ,OAAO,MAAM,6BAA6B;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,eAAe,MAAM,mBAAmB,eAAe,SAAS,MAAM;AAE5E,MAAI,aAAa,aAAa,aAAa,SAAS,WAAW,GAAG;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,aAAa;AACtB;"}
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { B as BUILTIN_STYLES } from "./index-DapYyqAC.js";
3
+ import { B as BUILTIN_STYLES } from "./index-DHgeuWGP.js";
4
4
  function expandTilde(filePath) {
5
5
  if (filePath.startsWith("~/")) {
6
6
  const home = process.env.HOME || process.env.USERPROFILE || "";
@@ -83,4 +83,4 @@ export {
83
83
  listCustomStyles,
84
84
  runStyleSelect
85
85
  };
86
- //# sourceMappingURL=style-select-CYo0O7MZ.js.map
86
+ //# sourceMappingURL=style-select-BNQHC79W.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"style-select-CYo0O7MZ.js","sources":["../../src/features/interactive/style-select.ts"],"sourcesContent":["/**\n * Style selection prompt for citation style selection.\n *\n * Lists built-in styles and custom styles from csl_directory,\n * with the default style shown first.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { BUILTIN_STYLES } from \"../../config/csl-styles.js\";\n\n/**\n * Options for style selection\n */\nexport interface StyleSelectOptions {\n /** Directory or directories containing custom CSL files */\n cslDirectory?: string | string[];\n /** Default style to show first */\n defaultStyle?: string;\n}\n\n/**\n * Result from style selection\n */\nexport interface StyleSelectResult {\n /** Selected style name */\n style?: string;\n /** Whether the selection was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Choice definition for Enquirer Select prompt\n */\ninterface StyleChoice {\n name: string;\n message: string;\n value: string;\n}\n\n/**\n * Expand tilde (~) in path to home directory\n */\nfunction expandTilde(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n return path.join(home, filePath.slice(2));\n }\n return filePath;\n}\n\n/**\n * List custom CSL style names from the specified directory/directories.\n *\n * @param cslDirectory - Directory or directories to search for CSL files\n * @returns Array of style names (without .csl extension)\n */\nexport function listCustomStyles(cslDirectory: string | string[] | undefined): string[] {\n if (!cslDirectory) {\n return [];\n }\n\n const directories = Array.isArray(cslDirectory) ? cslDirectory : [cslDirectory];\n const styles = new Set<string>();\n\n for (const dir of directories) {\n const expandedDir = expandTilde(dir);\n\n if (!fs.existsSync(expandedDir)) {\n continue;\n }\n\n try {\n const files = fs.readdirSync(expandedDir);\n for (const file of files) {\n if (file.endsWith(\".csl\")) {\n styles.add(file.slice(0, -4)); // Remove .csl extension\n }\n }\n } catch {\n // Ignore read errors\n }\n }\n\n return Array.from(styles).sort();\n}\n\n/**\n * Build style choices for the selection prompt.\n *\n * @param customStyles - Custom style names from csl_directory\n * @param defaultStyle - Default style to show first\n * @returns Array of choices for Enquirer Select prompt\n */\nexport function buildStyleChoices(customStyles: string[], defaultStyle = \"apa\"): StyleChoice[] {\n const choices: StyleChoice[] = [];\n const addedStyles = new Set<string>();\n\n // Helper to add a style choice\n const addChoice = (styleName: string, isDefault: boolean) => {\n if (addedStyles.has(styleName)) return;\n addedStyles.add(styleName);\n\n choices.push({\n name: styleName,\n message: isDefault ? `${styleName} (default)` : styleName,\n value: styleName,\n });\n };\n\n // Add default style first\n addChoice(defaultStyle, true);\n\n // Add built-in styles\n for (const style of BUILTIN_STYLES) {\n addChoice(style, false);\n }\n\n // Add custom styles (excluding any that match built-in names)\n for (const style of customStyles) {\n addChoice(style, false);\n }\n\n return choices;\n}\n\n/**\n * Run the style selection prompt.\n *\n * @param options - Style selection options\n * @returns Selection result with style name\n */\nexport async function runStyleSelect(options: StyleSelectOptions): Promise<StyleSelectResult> {\n // Dynamic import to allow mocking in tests\n const enquirer = await import(\"enquirer\");\n const Select = (enquirer.default as unknown as Record<string, unknown>).Select as new (\n opts: Record<string, unknown>\n ) => { run(): Promise<string> };\n\n // List custom styles from csl_directory\n const customStyles = listCustomStyles(options.cslDirectory);\n\n // Build choices with default first\n const choices = buildStyleChoices(customStyles, options.defaultStyle);\n\n const promptOptions = {\n name: \"style\",\n message: \"Select citation style:\",\n choices,\n };\n\n try {\n const prompt = new Select(promptOptions);\n const result = await prompt.run();\n\n return {\n style: result,\n cancelled: false,\n };\n } catch (error) {\n // Enquirer throws an empty string when cancelled\n if (error === \"\" || (error instanceof Error && error.message === \"\")) {\n return {\n cancelled: true,\n };\n }\n throw error;\n }\n}\n"],"names":[],"mappings":";;;AA2CA,SAAS,YAAY,UAA0B;AAC7C,MAAI,SAAS,WAAW,IAAI,GAAG;AAC7B,UAAM,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AAC5D,WAAO,KAAK,KAAK,MAAM,SAAS,MAAM,CAAC,CAAC;AAAA,EAC1C;AACA,SAAO;AACT;AAQO,SAAS,iBAAiB,cAAuD;AACtF,MAAI,CAAC,cAAc;AACjB,WAAO,CAAA;AAAA,EACT;AAEA,QAAM,cAAc,MAAM,QAAQ,YAAY,IAAI,eAAe,CAAC,YAAY;AAC9E,QAAM,6BAAa,IAAA;AAEnB,aAAW,OAAO,aAAa;AAC7B,UAAM,cAAc,YAAY,GAAG;AAEnC,QAAI,CAAC,GAAG,WAAW,WAAW,GAAG;AAC/B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,QAAQ,GAAG,YAAY,WAAW;AACxC,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,SAAS,MAAM,GAAG;AACzB,iBAAO,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,MAAM,EAAE,KAAA;AAC5B;AASO,SAAS,kBAAkB,cAAwB,eAAe,OAAsB;AAC7F,QAAM,UAAyB,CAAA;AAC/B,QAAM,kCAAkB,IAAA;AAGxB,QAAM,YAAY,CAAC,WAAmB,cAAuB;AAC3D,QAAI,YAAY,IAAI,SAAS,EAAG;AAChC,gBAAY,IAAI,SAAS;AAEzB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,SAAS,YAAY,GAAG,SAAS,eAAe;AAAA,MAChD,OAAO;AAAA,IAAA,CACR;AAAA,EACH;AAGA,YAAU,cAAc,IAAI;AAG5B,aAAW,SAAS,gBAAgB;AAClC,cAAU,OAAO,KAAK;AAAA,EACxB;AAGA,aAAW,SAAS,cAAc;AAChC,cAAU,OAAO,KAAK;AAAA,EACxB;AAEA,SAAO;AACT;AAQA,eAAsB,eAAe,SAAyD;AAE5F,QAAM,WAAW,MAAM,OAAO,UAAU;AACxC,QAAM,SAAU,SAAS,QAA+C;AAKxE,QAAM,eAAe,iBAAiB,QAAQ,YAAY;AAG1D,QAAM,UAAU,kBAAkB,cAAc,QAAQ,YAAY;AAEpE,QAAM,gBAAgB;AAAA,IACpB,MAAM;AAAA,IACN,SAAS;AAAA,IACT;AAAA,EAAA;AAGF,MAAI;AACF,UAAM,SAAS,IAAI,OAAO,aAAa;AACvC,UAAM,SAAS,MAAM,OAAO,IAAA;AAE5B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,WAAW;AAAA,IAAA;AAAA,EAEf,SAAS,OAAO;AAEd,QAAI,UAAU,MAAO,iBAAiB,SAAS,MAAM,YAAY,IAAK;AACpE,aAAO;AAAA,QACL,WAAW;AAAA,MAAA;AAAA,IAEf;AACA,UAAM;AAAA,EACR;AACF;"}
1
+ {"version":3,"file":"style-select-BNQHC79W.js","sources":["../../src/features/interactive/style-select.ts"],"sourcesContent":["/**\n * Style selection prompt for citation style selection.\n *\n * Lists built-in styles and custom styles from csl_directory,\n * with the default style shown first.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { BUILTIN_STYLES } from \"../../config/csl-styles.js\";\n\n/**\n * Options for style selection\n */\nexport interface StyleSelectOptions {\n /** Directory or directories containing custom CSL files */\n cslDirectory?: string | string[];\n /** Default style to show first */\n defaultStyle?: string;\n}\n\n/**\n * Result from style selection\n */\nexport interface StyleSelectResult {\n /** Selected style name */\n style?: string;\n /** Whether the selection was cancelled */\n cancelled: boolean;\n}\n\n/**\n * Choice definition for Enquirer Select prompt\n */\ninterface StyleChoice {\n name: string;\n message: string;\n value: string;\n}\n\n/**\n * Expand tilde (~) in path to home directory\n */\nfunction expandTilde(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n return path.join(home, filePath.slice(2));\n }\n return filePath;\n}\n\n/**\n * List custom CSL style names from the specified directory/directories.\n *\n * @param cslDirectory - Directory or directories to search for CSL files\n * @returns Array of style names (without .csl extension)\n */\nexport function listCustomStyles(cslDirectory: string | string[] | undefined): string[] {\n if (!cslDirectory) {\n return [];\n }\n\n const directories = Array.isArray(cslDirectory) ? cslDirectory : [cslDirectory];\n const styles = new Set<string>();\n\n for (const dir of directories) {\n const expandedDir = expandTilde(dir);\n\n if (!fs.existsSync(expandedDir)) {\n continue;\n }\n\n try {\n const files = fs.readdirSync(expandedDir);\n for (const file of files) {\n if (file.endsWith(\".csl\")) {\n styles.add(file.slice(0, -4)); // Remove .csl extension\n }\n }\n } catch {\n // Ignore read errors\n }\n }\n\n return Array.from(styles).sort();\n}\n\n/**\n * Build style choices for the selection prompt.\n *\n * @param customStyles - Custom style names from csl_directory\n * @param defaultStyle - Default style to show first\n * @returns Array of choices for Enquirer Select prompt\n */\nexport function buildStyleChoices(customStyles: string[], defaultStyle = \"apa\"): StyleChoice[] {\n const choices: StyleChoice[] = [];\n const addedStyles = new Set<string>();\n\n // Helper to add a style choice\n const addChoice = (styleName: string, isDefault: boolean) => {\n if (addedStyles.has(styleName)) return;\n addedStyles.add(styleName);\n\n choices.push({\n name: styleName,\n message: isDefault ? `${styleName} (default)` : styleName,\n value: styleName,\n });\n };\n\n // Add default style first\n addChoice(defaultStyle, true);\n\n // Add built-in styles\n for (const style of BUILTIN_STYLES) {\n addChoice(style, false);\n }\n\n // Add custom styles (excluding any that match built-in names)\n for (const style of customStyles) {\n addChoice(style, false);\n }\n\n return choices;\n}\n\n/**\n * Run the style selection prompt.\n *\n * @param options - Style selection options\n * @returns Selection result with style name\n */\nexport async function runStyleSelect(options: StyleSelectOptions): Promise<StyleSelectResult> {\n // Dynamic import to allow mocking in tests\n const enquirer = await import(\"enquirer\");\n const Select = (enquirer.default as unknown as Record<string, unknown>).Select as new (\n opts: Record<string, unknown>\n ) => { run(): Promise<string> };\n\n // List custom styles from csl_directory\n const customStyles = listCustomStyles(options.cslDirectory);\n\n // Build choices with default first\n const choices = buildStyleChoices(customStyles, options.defaultStyle);\n\n const promptOptions = {\n name: \"style\",\n message: \"Select citation style:\",\n choices,\n };\n\n try {\n const prompt = new Select(promptOptions);\n const result = await prompt.run();\n\n return {\n style: result,\n cancelled: false,\n };\n } catch (error) {\n // Enquirer throws an empty string when cancelled\n if (error === \"\" || (error instanceof Error && error.message === \"\")) {\n return {\n cancelled: true,\n };\n }\n throw error;\n }\n}\n"],"names":[],"mappings":";;;AA2CA,SAAS,YAAY,UAA0B;AAC7C,MAAI,SAAS,WAAW,IAAI,GAAG;AAC7B,UAAM,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AAC5D,WAAO,KAAK,KAAK,MAAM,SAAS,MAAM,CAAC,CAAC;AAAA,EAC1C;AACA,SAAO;AACT;AAQO,SAAS,iBAAiB,cAAuD;AACtF,MAAI,CAAC,cAAc;AACjB,WAAO,CAAA;AAAA,EACT;AAEA,QAAM,cAAc,MAAM,QAAQ,YAAY,IAAI,eAAe,CAAC,YAAY;AAC9E,QAAM,6BAAa,IAAA;AAEnB,aAAW,OAAO,aAAa;AAC7B,UAAM,cAAc,YAAY,GAAG;AAEnC,QAAI,CAAC,GAAG,WAAW,WAAW,GAAG;AAC/B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,QAAQ,GAAG,YAAY,WAAW;AACxC,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,SAAS,MAAM,GAAG;AACzB,iBAAO,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,MAAM,EAAE,KAAA;AAC5B;AASO,SAAS,kBAAkB,cAAwB,eAAe,OAAsB;AAC7F,QAAM,UAAyB,CAAA;AAC/B,QAAM,kCAAkB,IAAA;AAGxB,QAAM,YAAY,CAAC,WAAmB,cAAuB;AAC3D,QAAI,YAAY,IAAI,SAAS,EAAG;AAChC,gBAAY,IAAI,SAAS;AAEzB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,SAAS,YAAY,GAAG,SAAS,eAAe;AAAA,MAChD,OAAO;AAAA,IAAA,CACR;AAAA,EACH;AAGA,YAAU,cAAc,IAAI;AAG5B,aAAW,SAAS,gBAAgB;AAClC,cAAU,OAAO,KAAK;AAAA,EACxB;AAGA,aAAW,SAAS,cAAc;AAChC,cAAU,OAAO,KAAK;AAAA,EACxB;AAEA,SAAO;AACT;AAQA,eAAsB,eAAe,SAAyD;AAE5F,QAAM,WAAW,MAAM,OAAO,UAAU;AACxC,QAAM,SAAU,SAAS,QAA+C;AAKxE,QAAM,eAAe,iBAAiB,QAAQ,YAAY;AAG1D,QAAM,UAAU,kBAAkB,cAAc,QAAQ,YAAY;AAEpE,QAAM,gBAAgB;AAAA,IACpB,MAAM;AAAA,IACN,SAAS;AAAA,IACT;AAAA,EAAA;AAGF,MAAI;AACF,UAAM,SAAS,IAAI,OAAO,aAAa;AACvC,UAAM,SAAS,MAAM,OAAO,IAAA;AAE5B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,WAAW;AAAA,IAAA;AAAA,EAEf,SAAS,OAAO;AAEd,QAAI,UAAU,MAAO,iBAAiB,SAAS,MAAM,YAAY,IAAK;AACpE,aAAO;AAAA,QACL,WAAW;AAAA,MAAA;AAAA,IAEf;AACA,UAAM;AAAA,EACR;AACF;"}
@@ -7,11 +7,11 @@ class TTYError extends Error {
7
7
  }
8
8
  function checkTTY() {
9
9
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
10
- throw new TTYError("Interactive mode requires a TTY");
10
+ throw new TTYError("TUI mode requires a TTY");
11
11
  }
12
12
  }
13
13
  export {
14
14
  TTYError,
15
15
  checkTTY
16
16
  };
17
- //# sourceMappingURL=tty-CDBIQraQ.js.map
17
+ //# sourceMappingURL=tty-BMyaEOhX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tty-BMyaEOhX.js","sources":["../../src/features/interactive/tty.ts"],"sourcesContent":["/**\n * TTY detection for TUI mode\n */\n\n/**\n * Error thrown when TTY is required but not available\n */\nexport class TTYError extends Error {\n readonly exitCode = 1;\n\n constructor(message: string) {\n super(message);\n this.name = \"TTYError\";\n }\n}\n\n/**\n * Check if the current environment is a TTY\n *\n * Throws TTYError if stdin or stdout is not a TTY,\n * which means TUI mode cannot be used.\n *\n * @throws {TTYError} If not running in a TTY\n */\nexport function checkTTY(): void {\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n throw new TTYError(\"TUI mode requires a TTY\");\n }\n}\n"],"names":[],"mappings":"AAOO,MAAM,iBAAiB,MAAM;AAAA,EACzB,WAAW;AAAA,EAEpB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAUO,SAAS,WAAiB;AAC/B,MAAI,CAAC,QAAQ,MAAM,SAAS,CAAC,QAAQ,OAAO,OAAO;AACjD,UAAM,IAAI,SAAS,yBAAyB;AAAA,EAC9C;AACF;"}