@ncukondo/reference-manager 0.31.0 → 0.33.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 (69) hide show
  1. package/README.md +20 -0
  2. package/dist/chunks/{SearchableMultiSelect-BFgiGVkF.js → SearchableMultiSelect-B8QVnO_p.js} +2 -2
  3. package/dist/chunks/{SearchableMultiSelect-BFgiGVkF.js.map → SearchableMultiSelect-B8QVnO_p.js.map} +1 -1
  4. package/dist/chunks/{action-menu-D5s90TfM.js → action-menu-i1v02Qig.js} +3 -3
  5. package/dist/chunks/{action-menu-D5s90TfM.js.map → action-menu-i1v02Qig.js.map} +1 -1
  6. package/dist/chunks/{checker-DMyZFCaP.js → checker-CnWQe7v2.js} +4 -4
  7. package/dist/chunks/{checker-DMyZFCaP.js.map → checker-CnWQe7v2.js.map} +1 -1
  8. package/dist/chunks/{crossref-client-CaFCAASM.js → crossref-client-Dxwv2A5D.js} +2 -2
  9. package/dist/chunks/{crossref-client-CaFCAASM.js.map → crossref-client-Dxwv2A5D.js.map} +1 -1
  10. package/dist/chunks/{fix-interaction-h15RI_Ae.js → fix-interaction-D_zhtL9k.js} +5 -5
  11. package/dist/chunks/{fix-interaction-h15RI_Ae.js.map → fix-interaction-D_zhtL9k.js.map} +1 -1
  12. package/dist/chunks/{index-BG3Ef4Pd.js → index-DMShdNwY.js} +4 -4
  13. package/dist/chunks/{index-BG3Ef4Pd.js.map → index-DMShdNwY.js.map} +1 -1
  14. package/dist/chunks/{index-Cqss7VR_.js → index-DpZ-Ma7M.js} +3 -3
  15. package/dist/chunks/index-DpZ-Ma7M.js.map +1 -0
  16. package/dist/chunks/{index-DCBYzNj-.js → index-PkCQJBdt.js} +196 -59
  17. package/dist/chunks/index-PkCQJBdt.js.map +1 -0
  18. package/dist/chunks/{index-CS8S6gE4.js → index-a52FHX03.js} +672 -16
  19. package/dist/chunks/index-a52FHX03.js.map +1 -0
  20. package/dist/chunks/{loader-BG2eomDC.js → loader-CMu82BI5.js} +42 -1
  21. package/dist/chunks/loader-CMu82BI5.js.map +1 -0
  22. package/dist/chunks/{pubmed-client-vbreWUxK.js → pubmed-client-CPFYI4kR.js} +2 -2
  23. package/dist/chunks/{pubmed-client-vbreWUxK.js.map → pubmed-client-CPFYI4kR.js.map} +1 -1
  24. package/dist/chunks/{reference-select-CNWexQGu.js → reference-select-aEB3-5rp.js} +3 -3
  25. package/dist/chunks/{reference-select-CNWexQGu.js.map → reference-select-aEB3-5rp.js.map} +1 -1
  26. package/dist/chunks/{style-select-D8beMum_.js → style-select-CQ4BBBZJ.js} +3 -3
  27. package/dist/chunks/{style-select-D8beMum_.js.map → style-select-CQ4BBBZJ.js.map} +1 -1
  28. package/dist/cli/commands/add.d.ts +9 -1
  29. package/dist/cli/commands/add.d.ts.map +1 -1
  30. package/dist/cli/commands/install/install.d.ts +11 -0
  31. package/dist/cli/commands/install/install.d.ts.map +1 -0
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli.js +2 -2
  34. package/dist/config/defaults.d.ts.map +1 -1
  35. package/dist/config/key-parser.d.ts.map +1 -1
  36. package/dist/config/loader.d.ts.map +1 -1
  37. package/dist/config/schema.d.ts +42 -0
  38. package/dist/config/schema.d.ts.map +1 -1
  39. package/dist/features/attachments/types.d.ts +5 -1
  40. package/dist/features/attachments/types.d.ts.map +1 -1
  41. package/dist/features/import/browser.d.ts +16 -0
  42. package/dist/features/import/browser.d.ts.map +1 -0
  43. package/dist/features/import/detector.d.ts +11 -2
  44. package/dist/features/import/detector.d.ts.map +1 -1
  45. package/dist/features/import/importer.d.ts +17 -0
  46. package/dist/features/import/importer.d.ts.map +1 -1
  47. package/dist/features/import/url-archive.d.ts +18 -0
  48. package/dist/features/import/url-archive.d.ts.map +1 -0
  49. package/dist/features/import/url-fetcher.d.ts +35 -0
  50. package/dist/features/import/url-fetcher.d.ts.map +1 -0
  51. package/dist/features/import/url-fulltext.d.ts +10 -0
  52. package/dist/features/import/url-fulltext.d.ts.map +1 -0
  53. package/dist/features/import/url-metadata.d.ts +34 -0
  54. package/dist/features/import/url-metadata.d.ts.map +1 -0
  55. package/dist/features/install/index.d.ts +6 -0
  56. package/dist/features/install/index.d.ts.map +1 -0
  57. package/dist/features/install/write-skills.d.ts +21 -0
  58. package/dist/features/install/write-skills.d.ts.map +1 -0
  59. package/dist/features/operations/add.d.ts +11 -0
  60. package/dist/features/operations/add.d.ts.map +1 -1
  61. package/dist/features/operations/json-output.d.ts +1 -0
  62. package/dist/features/operations/json-output.d.ts.map +1 -1
  63. package/dist/index.js +1 -1
  64. package/dist/server.js +1 -1
  65. package/package.json +8 -1
  66. package/dist/chunks/index-CS8S6gE4.js.map +0 -1
  67. package/dist/chunks/index-Cqss7VR_.js.map +0 -1
  68. package/dist/chunks/index-DCBYzNj-.js.map +0 -1
  69. package/dist/chunks/loader-BG2eomDC.js.map +0 -1
@@ -1,13 +1,14 @@
1
1
  import { Command, Option } from "commander";
2
- import { n as normalizePathForOutput, d as deleteDirectoryIfEmpty, p as parseFilename, i as isReservedRole, e as ensureDirectory, a as addAttachment, R as RESERVED_ROLES, b as generateFilename, c as findFulltextFiles, h as findFulltextFile, j as extensionToFormat, k as fulltextAttach, l as fulltextDiscover, m as fulltextFetch, o as fulltextConvert, q as fulltextGet, r as getExtension, s as getDefaultExportFromCjs, B as BUILTIN_STYLES, t as packageJson, u as getFulltextAttachmentTypes, v as startServerWithFileWatcher, w as BUILTIN_CONVERTER_NAMES, x as BUILTIN_CONVERTER_INFO } from "./index-CS8S6gE4.js";
2
+ import { n as normalizePathForOutput, d as deleteDirectoryIfEmpty, p as parseFilename, i as isReservedRole, e as ensureDirectory, a as addAttachment, R as RESERVED_ROLES, b as generateFilename, c as findFulltextFiles, h as findFulltextFile, j as extensionToFormat, k as fulltextAttach, l as fulltextDiscover, m as fulltextFetch, o as fulltextConvert, q as fulltextGet, r as getExtension, s as getDefaultExportFromCjs, B as BUILTIN_STYLES, t as packageJson, u as getFulltextAttachmentTypes, v as startServerWithFileWatcher, w as BUILTIN_CONVERTER_NAMES, x as BUILTIN_CONVERTER_INFO } from "./index-a52FHX03.js";
3
3
  import { i as isEqual, M as MANAGED_CUSTOM_FIELDS, w as writeFileAtomic, L as Library, h as CslItemSchema, p as pickDefined, a as sortOrderSchema, z as paginationOptionsSchema, F as FileWatcher, b as sortFieldSchema, y as searchSortFieldSchema } from "./file-watcher-CWHg1yol.js";
4
4
  import * as fs from "node:fs";
5
- import { promises, readFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
5
+ import { promises, readFileSync, existsSync, mkdirSync, writeFileSync, lstatSync, unlinkSync, rmSync, symlinkSync } from "node:fs";
6
6
  import * as os from "node:os";
7
+ import { homedir } from "node:os";
7
8
  import * as path from "node:path";
8
- import path__default, { join, basename, dirname } from "node:path";
9
+ import path__default, { join, basename, dirname, relative } from "node:path";
9
10
  import { readFile, unlink, stat, readdir, rename } from "node:fs/promises";
10
- import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-BG2eomDC.js";
11
+ import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-CMu82BI5.js";
11
12
  import { spawn, spawnSync } from "node:child_process";
12
13
  import process$1, { stdin, stdout } from "node:process";
13
14
  import * as readline from "node:readline";
@@ -163,6 +164,9 @@ function formatAddJsonOutput(result, options) {
163
164
  output.idChanged = true;
164
165
  output.originalId = item.originalId;
165
166
  }
167
+ if (item.warnings && item.warnings.length > 0) {
168
+ output.warnings = item.warnings;
169
+ }
166
170
  if (full) {
167
171
  const cslItem = items2.get(item.id);
168
172
  if (cslItem) {
@@ -348,12 +352,30 @@ async function executeAdd(options, context) {
348
352
  if (stdinContent !== void 0) {
349
353
  importOptions.stdinContent = stdinContent;
350
354
  }
355
+ if (options.urlConfig !== void 0) {
356
+ importOptions.urlConfig = options.urlConfig;
357
+ }
358
+ if (options.archiveFormat !== void 0) {
359
+ importOptions.archiveFormat = options.archiveFormat;
360
+ }
361
+ if (options.noArchive !== void 0) {
362
+ importOptions.noArchive = options.noArchive;
363
+ }
364
+ if (options.attachmentsDirectory !== void 0) {
365
+ importOptions.attachmentsDirectory = options.attachmentsDirectory;
366
+ }
351
367
  return context.library.import(inputs, importOptions);
352
368
  }
353
369
  function formatAddedItem(item) {
354
370
  const idPart = item.idChanged ? `${item.id} (was: ${item.originalId})` : item.id;
355
371
  const title2 = item.title ?? "(no title)";
356
- return ` - ${idPart}: "${title2}"`;
372
+ const lines = [` - ${idPart}: "${title2}"`];
373
+ if (item.warnings && item.warnings.length > 0) {
374
+ for (const warning of item.warnings) {
375
+ lines.push(` Warning: ${warning}`);
376
+ }
377
+ }
378
+ return lines.join("\n");
357
379
  }
358
380
  function formatFailedItem(item, verbose) {
359
381
  let error = item.error;
@@ -893,15 +915,15 @@ class OperationsLibrary {
893
915
  }
894
916
  // High-level operations
895
917
  async search(options) {
896
- const { searchReferences } = await import("./index-CS8S6gE4.js").then((n) => n.H);
918
+ const { searchReferences } = await import("./index-a52FHX03.js").then((n) => n.H);
897
919
  return searchReferences(this.library, options);
898
920
  }
899
921
  async list(options) {
900
- const { listReferences } = await import("./index-CS8S6gE4.js").then((n) => n.G);
922
+ const { listReferences } = await import("./index-a52FHX03.js").then((n) => n.G);
901
923
  return listReferences(this.library, options ?? {});
902
924
  }
903
925
  async cite(options) {
904
- const { citeReferences } = await import("./index-CS8S6gE4.js").then((n) => n.F);
926
+ const { citeReferences } = await import("./index-a52FHX03.js").then((n) => n.F);
905
927
  const defaultStyle = options.defaultStyle ?? this.citationConfig?.defaultStyle;
906
928
  const cslDirectory = options.cslDirectory ?? this.citationConfig?.cslDirectory;
907
929
  const mergedOptions = {
@@ -912,36 +934,36 @@ class OperationsLibrary {
912
934
  return citeReferences(this.library, mergedOptions);
913
935
  }
914
936
  async import(inputs, options) {
915
- const { addReferences } = await import("./index-CS8S6gE4.js").then((n) => n.D);
937
+ const { addReferences } = await import("./index-a52FHX03.js").then((n) => n.D);
916
938
  return addReferences(inputs, this.library, options ?? {});
917
939
  }
918
940
  async check(options) {
919
- const { checkReferences } = await import("./index-CS8S6gE4.js").then((n) => n.E);
941
+ const { checkReferences } = await import("./index-a52FHX03.js").then((n) => n.E);
920
942
  return checkReferences(this.library, options);
921
943
  }
922
944
  // Attachment operations
923
945
  async attachAdd(options) {
924
- const { addAttachment: addAttachment2 } = await import("./index-Cqss7VR_.js");
946
+ const { addAttachment: addAttachment2 } = await import("./index-DpZ-Ma7M.js");
925
947
  return addAttachment2(this.library, options);
926
948
  }
927
949
  async attachList(options) {
928
- const { listAttachments: listAttachments2 } = await import("./index-Cqss7VR_.js");
950
+ const { listAttachments: listAttachments2 } = await import("./index-DpZ-Ma7M.js");
929
951
  return listAttachments2(this.library, options);
930
952
  }
931
953
  async attachGet(options) {
932
- const { getAttachment: getAttachment2 } = await import("./index-Cqss7VR_.js");
954
+ const { getAttachment: getAttachment2 } = await import("./index-DpZ-Ma7M.js");
933
955
  return getAttachment2(this.library, options);
934
956
  }
935
957
  async attachDetach(options) {
936
- const { detachAttachment: detachAttachment2 } = await import("./index-Cqss7VR_.js");
958
+ const { detachAttachment: detachAttachment2 } = await import("./index-DpZ-Ma7M.js");
937
959
  return detachAttachment2(this.library, options);
938
960
  }
939
961
  async attachSync(options) {
940
- const { syncAttachments: syncAttachments2 } = await import("./index-Cqss7VR_.js");
962
+ const { syncAttachments: syncAttachments2 } = await import("./index-DpZ-Ma7M.js");
941
963
  return syncAttachments2(this.library, options);
942
964
  }
943
965
  async attachOpen(options) {
944
- const { openAttachment: openAttachment2 } = await import("./index-Cqss7VR_.js");
966
+ const { openAttachment: openAttachment2 } = await import("./index-DpZ-Ma7M.js");
945
967
  return openAttachment2(this.library, options);
946
968
  }
947
969
  }
@@ -1806,7 +1828,7 @@ function getAttachExitCode(result) {
1806
1828
  }
1807
1829
  async function executeInteractiveSelect$3(context, config2) {
1808
1830
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
1809
- const { selectReferencesOrExit } = await import("./reference-select-CNWexQGu.js");
1831
+ const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
1810
1832
  const allReferences = await context.library.getAll();
1811
1833
  const identifiers = await withAlternateScreen2(
1812
1834
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -2471,7 +2493,7 @@ async function handleCheckAction(identifiers, options, globalOpts) {
2471
2493
  const jsonOptions = buildJsonOptionsFromRefs(options, outputFormat, result, allRefs);
2472
2494
  outputCheckResult(result, outputFormat, jsonOptions);
2473
2495
  if (options.fix && result.summary.warnings > 0 && allRefs) {
2474
- const { runFixInteraction } = await import("./fix-interaction-h15RI_Ae.js");
2496
+ const { runFixInteraction } = await import("./fix-interaction-D_zhtL9k.js");
2475
2497
  const findItem = (id2) => allRefs.find((item) => item.id === id2);
2476
2498
  const fixResult = await runFixInteraction(result.results, context.library, findItem);
2477
2499
  const removedSuffix = fixResult.removed.length > 0 ? `, ${fixResult.removed.length} removed` : "";
@@ -2539,7 +2561,7 @@ function outputCheckError(error, format2) {
2539
2561
  }
2540
2562
  async function selectReferencesInteractively(context, config2) {
2541
2563
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
2542
- const { selectReferenceItemsOrExit } = await import("./reference-select-CNWexQGu.js");
2564
+ const { selectReferenceItemsOrExit } = await import("./reference-select-aEB3-5rp.js");
2543
2565
  const allReferences = await context.library.getAll();
2544
2566
  if (allReferences.length === 0) {
2545
2567
  process.stderr.write("No references in library.\n");
@@ -2607,8 +2629,8 @@ function getCiteExitCode(result) {
2607
2629
  }
2608
2630
  async function executeInteractiveCite(options, context, config2) {
2609
2631
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
2610
- const { runCiteFlow } = await import("./index-BG3Ef4Pd.js");
2611
- const { buildStyleChoices, listCustomStyles } = await import("./style-select-D8beMum_.js");
2632
+ const { runCiteFlow } = await import("./index-DMShdNwY.js");
2633
+ const { buildStyleChoices, listCustomStyles } = await import("./style-select-CQ4BBBZJ.js");
2612
2634
  const { search } = await import("./file-watcher-CWHg1yol.js").then((n) => n.B);
2613
2635
  const { tokenize } = await import("./file-watcher-CWHg1yol.js").then((n) => n.A);
2614
2636
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
@@ -2823,6 +2845,15 @@ const CONFIG_KEY_REGISTRY = [
2823
2845
  },
2824
2846
  // attachments section
2825
2847
  { key: "attachments.directory", type: "string", description: "Attachments storage directory" },
2848
+ // url section
2849
+ {
2850
+ key: "url.archive_format",
2851
+ type: "enum",
2852
+ description: "Default archive format for URL import",
2853
+ enumValues: ["mhtml", "html"]
2854
+ },
2855
+ { key: "url.browser_path", type: "string", description: "Browser executable path" },
2856
+ { key: "url.timeout", type: "integer", description: "Navigation timeout (seconds)" },
2826
2857
  // cli section
2827
2858
  {
2828
2859
  key: "cli.default_limit",
@@ -7291,7 +7322,7 @@ function formatEditOutput(result) {
7291
7322
  }
7292
7323
  async function executeInteractiveEdit(options, context, config2) {
7293
7324
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
7294
- const { selectReferencesOrExit } = await import("./reference-select-CNWexQGu.js");
7325
+ const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
7295
7326
  const allReferences = await context.library.getAll();
7296
7327
  const identifiers = await withAlternateScreen2(
7297
7328
  () => selectReferencesOrExit(allReferences, { multiSelect: true }, config2.cli.tui)
@@ -10867,7 +10898,7 @@ function getFulltextExitCode(result) {
10867
10898
  }
10868
10899
  async function executeInteractiveSelect$2(context, config2, multiSelect = false) {
10869
10900
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
10870
- const { selectReferencesOrExit } = await import("./reference-select-CNWexQGu.js");
10901
+ const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
10871
10902
  const allReferences = await context.library.getAll();
10872
10903
  const identifiers = await withAlternateScreen2(
10873
10904
  () => selectReferencesOrExit(allReferences, { multiSelect }, config2.cli.tui)
@@ -11290,6 +11321,79 @@ const fulltext = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
11290
11321
  handleFulltextGetAction,
11291
11322
  handleFulltextOpenAction
11292
11323
  }, Symbol.toStringTag, { value: "Module" }));
11324
+ const skillMd = '---\nname: ref\ndescription: Manage academic references in CSL-JSON format. Add papers by DOI/PMID/ISBN/arXiv, search and list references, generate citations, manage full-text PDFs, and check for retractions.\nallowed-tools:\n - Bash\n - Read\n - Write\n - Edit\n - Glob\n - Grep\n---\n\n# ref — Reference Manager\n\nA CLI tool for managing academic references using CSL-JSON as the single source of truth.\n\n## Quick Reference\n\n| Task | Command |\n|------|---------|\n| Add by DOI | `ref add 10.1234/example` |\n| Add by PMID | `ref add 12345678` |\n| Add by ISBN | `ref add 978-0-123456-78-9` |\n| Add by arXiv | `ref add 2301.12345` |\n| Add from BibTeX | `ref add references.bib` |\n| Add from RIS | `ref add references.ris` |\n| Search | `ref search "query"` |\n| List all | `ref list` |\n| Show details | `ref show <id>` |\n| Generate citation | `ref cite <id>` |\n| Export | `ref export <id> --output bibtex` |\n| Attach full-text | `ref fulltext attach <id> paper.pdf` |\n| Fetch full-text | `ref fulltext fetch <id>` |\n| Check retractions | `ref check <id>` |\n| Remove | `ref remove <id>` |\n| Update fields | `ref update <id> --set "title=New Title"` |\n| Configure | `ref config set <key> <value>` |\n\n## Search Syntax\n\n- Simple text: `ref search "machine learning"`\n- By author: `ref search "author:Smith"`\n- By year: `ref search "year:2024"`\n- By type: `ref search "type:article-journal"`\n- By tag: `ref search "tag:review"`\n- Combined: `ref search "author:Smith year:2024"`\n- Case-sensitive: prefix with `C/` (e.g., `ref search "C/RNA"`)\n\n## Output Formats\n\nMost commands support `--output` or `--json` flags:\n\n- `--json` — JSON output for programmatic use\n- `--output bibtex` — BibTeX format\n- `--output yaml` — YAML format\n\n## Full Help\n\nRun `ref --help` for all commands and options.\nRun `ref <command> --help` for command-specific help.\n';
11325
+ const fulltextMd = '---\nname: ref/fulltext\ndescription: Guide for managing full-text PDFs and Markdown files. Covers fetching, attaching, converting, and organizing full-text content.\n---\n\n# Full-Text Management\n\nGuide for working with full-text files (PDFs and Markdown) using `ref`.\n\n## Attach Files\n\n```bash\n# Attach a PDF\nref fulltext attach <id> paper.pdf\n\n# Attach Markdown\nref fulltext attach <id> paper.md\n```\n\n## Fetch Open Access\n\n```bash\n# Auto-discover and download OA full text\nref fulltext fetch <id>\n\n# Fetch with auto-attach on add\nref add 10.1234/example --fetch-fulltext\n```\n\n## Convert Formats\n\n```bash\n# Convert PDF to Markdown (requires external converter)\nref fulltext convert <id>\n\n# Supported converters: marker, docling, mineru, pymupdf\n# Configure custom converter:\nref config set fulltext.pdfConverter.command "marker"\nref config set fulltext.pdfConverter.args "{input} --output {output_dir}"\n```\n\n## Retrieve Full Text\n\n```bash\n# Get file path\nref fulltext get <id>\n\n# Get Markdown content to stdout\nref fulltext get <id> --stdout\n\n# Prefer specific format\nref fulltext get <id> --markdown\nref fulltext get <id> --pdf\n\n# Open in default system viewer\nref fulltext open <id>\n```\n\n## Check Availability\n\n```bash\n# Discover OA sources without downloading\nref fulltext discover <id>\n```\n\n## Detach\n\n```bash\n# Remove full-text association (file remains on disk)\nref fulltext detach <id>\n```\n\n## Tips\n\n- Use `ref fulltext get <id> --stdout` to pipe content to other tools\n- Full-text files are stored in the attachments directory (see `ref config get attachments.directory`)\n- Use `ref show <id>` to see full-text status alongside metadata\n- Markdown is preferred for AI-readable content; use `ref fulltext convert` after attaching PDF\n';
11326
+ const manuscriptWritingMd = "---\nname: ref/manuscript-writing\ndescription: Workflow for managing references while writing academic manuscripts. Covers citation generation, bibliography export, and reference verification.\n---\n\n# Manuscript Writing Workflow\n\nGuide for managing references during academic manuscript writing with `ref`.\n\n## 1. Find and Cite\n\n```bash\n# Search your library\nref search \"Smith 2024\"\n\n# Generate an inline citation\nref cite <id>\n\n# Generate citation in specific style\nref cite <id> --style apa\nref cite <id> --style vancouver\n\n# Get Pandoc/LaTeX citation key\nref cite <id> --key\n```\n\n## 2. Build Bibliography\n\n```bash\n# Export all cited references as BibTeX\nref export <id1> <id2> <id3> --output bibtex > references.bib\n\n# Export by search query\nref search \"tag:cited\" --output bibtex > references.bib\n\n# Export all references\nref export --all --output bibtex > library.bib\n```\n\n## 3. Add New References During Writing\n\n```bash\n# Quick add by DOI from a paper you're reading\nref add 10.1234/example\n\n# Add from clipboard BibTeX (pipe from stdin)\necho '<bibtex>' | ref add -\n\n# Add and immediately get citation key\nref add 10.1234/example --json | jq -r '.added[0].id'\n```\n\n## 4. Verify Before Submission\n\n```bash\n# Check all cited references for retractions\nref check <id1> <id2> <id3>\n\n# Verify metadata accuracy\nref check <id> --metadata\n\n# Show full details for final review\nref show <id>\n```\n\n## 5. Full-Text Management\n\n```bash\n# Attach supplementary files\nref fulltext attach <id> paper.pdf\nref fulltext attach <id> supplement.pdf\n\n# Get full-text path for reading\nref fulltext get <id>\n\n# Open in default viewer\nref fulltext open <id>\n```\n\n## Tips\n\n- Use `ref cite <id> --key` to get `@AuthorYear` keys for Pandoc\n- Use `ref show <id> --output yaml` for quick metadata overview\n- Use `ref url <id>` to get DOI/PubMed URLs for linking\n- Tag references with `ref update <id> --set \"tags=cited\"` to track what's in the manuscript\n";
11327
+ const systematicReviewMd = '---\nname: ref/systematic-review\ndescription: Workflow for conducting systematic literature reviews using reference-manager. Covers search strategy, screening, and evidence synthesis.\n---\n\n# Systematic Review Workflow\n\nGuide for conducting systematic literature reviews with `ref`.\n\n## 1. Build Search Set\n\nAdd references from multiple sources:\n\n```bash\n# From DOIs (e.g., exported from database search)\nref add 10.1234/study1 10.1234/study2 10.1234/study3\n\n# From BibTeX exported by PubMed/Scopus/Web of Science\nref add pubmed-results.bib\nref add scopus-results.ris\n\n# By PMID list\nref add 12345678 23456789 34567890\n```\n\n## 2. Tag and Organize\n\nUse tags to track screening stages:\n\n```bash\n# Tag references for screening\nref update <id> --set "tags=screening"\n\n# After title/abstract screening\nref update <id> --set "tags=included"\nref update <id> --set "tags=excluded"\n\n# After full-text review\nref update <id> --set "tags=final-included"\n```\n\n## 3. Full-Text Collection\n\n```bash\n# Auto-fetch open access full texts\nref fulltext fetch <id>\n\n# Attach manually obtained PDFs\nref fulltext attach <id> path/to/paper.pdf\n\n# Convert PDF to Markdown for text analysis\nref fulltext convert <id>\n```\n\n## 4. Quality Check\n\n```bash\n# Check for retractions or corrections\nref check <id>\n\n# Verify metadata against upstream sources\nref check <id> --metadata\n```\n\n## 5. Export for Analysis\n\n```bash\n# Export included studies as BibTeX\nref search "tag:final-included" --output bibtex > included.bib\n\n# Export as JSON for custom analysis\nref search "tag:final-included" --json > included.json\n```\n\n## Tips\n\n- Use `ref list --sort date-desc` to review chronologically\n- Use `ref search "tag:screening"` to find unprocessed references\n- Use `ref show <id>` to inspect full metadata before decisions\n- Duplicates are auto-detected on `ref add` — review skip messages\n';
11328
+ const SKILL_FILES = [
11329
+ ["SKILL.md", skillMd],
11330
+ ["references/systematic-review.md", systematicReviewMd],
11331
+ ["references/manuscript-writing.md", manuscriptWritingMd],
11332
+ ["references/fulltext.md", fulltextMd]
11333
+ ];
11334
+ async function writeSkills(options) {
11335
+ const { targetDir, force = false, user = false } = options;
11336
+ const baseDir = user ? homedir() : targetDir;
11337
+ const agentsDir = join(baseDir, ".agents", "skills", "ref");
11338
+ const claudeDir = join(baseDir, ".claude", "skills");
11339
+ const claudeLink = join(claudeDir, "ref");
11340
+ const written = [];
11341
+ const skipped = [];
11342
+ mkdirSync(join(agentsDir, "references"), { recursive: true });
11343
+ for (const [relativePath, content] of SKILL_FILES) {
11344
+ const filePath = join(agentsDir, relativePath);
11345
+ if (existsSync(filePath) && !force) {
11346
+ skipped.push(relativePath);
11347
+ continue;
11348
+ }
11349
+ writeFileSync(filePath, content, "utf-8");
11350
+ written.push(relativePath);
11351
+ }
11352
+ let linkCreated = false;
11353
+ mkdirSync(claudeDir, { recursive: true });
11354
+ if (force && existsSync(claudeLink)) {
11355
+ const stat2 = lstatSync(claudeLink);
11356
+ if (stat2.isSymbolicLink()) {
11357
+ unlinkSync(claudeLink);
11358
+ } else if (stat2.isDirectory()) {
11359
+ rmSync(claudeLink, { recursive: true, force: true });
11360
+ }
11361
+ }
11362
+ if (!existsSync(claudeLink)) {
11363
+ const linkTarget = relative(claudeDir, agentsDir);
11364
+ symlinkSync(linkTarget, claudeLink, "junction");
11365
+ linkCreated = true;
11366
+ }
11367
+ return { written, skipped, linkCreated };
11368
+ }
11369
+ async function executeInstallSkills(options) {
11370
+ return writeSkills({
11371
+ targetDir: process.cwd(),
11372
+ force: options.force,
11373
+ ...options.user != null && { user: options.user }
11374
+ });
11375
+ }
11376
+ function formatInstallSkillsOutput(result) {
11377
+ const lines = [];
11378
+ if (result.written.length === 0 && result.skipped.length > 0) {
11379
+ lines.push("Skills already up-to-date. Use --force to overwrite.");
11380
+ lines.push(` ${result.skipped.length} files skipped`);
11381
+ return lines.join("\n");
11382
+ }
11383
+ if (result.written.length > 0) {
11384
+ lines.push(`Installed ${result.written.length} skill files to .agents/skills/ref/`);
11385
+ for (const file of result.written) {
11386
+ lines.push(` + ${file}`);
11387
+ }
11388
+ }
11389
+ if (result.skipped.length > 0) {
11390
+ lines.push(` ${result.skipped.length} files skipped (already exist)`);
11391
+ }
11392
+ if (result.linkCreated) {
11393
+ lines.push("Created symlink: .claude/skills/ref -> .agents/skills/ref");
11394
+ }
11395
+ return lines.join("\n");
11396
+ }
11293
11397
  function buildResourceIndicators(item) {
11294
11398
  const labels = [];
11295
11399
  const attachments = item.custom?.attachments;
@@ -26836,49 +26940,49 @@ function requireFastUri() {
26836
26940
  schemelessOptions.skipEscape = true;
26837
26941
  return serialize2(resolved, schemelessOptions);
26838
26942
  }
26839
- function resolveComponent(base, relative, options, skipNormalization) {
26943
+ function resolveComponent(base, relative2, options, skipNormalization) {
26840
26944
  const target = {};
26841
26945
  if (!skipNormalization) {
26842
26946
  base = parse2(serialize2(base, options), options);
26843
- relative = parse2(serialize2(relative, options), options);
26947
+ relative2 = parse2(serialize2(relative2, options), options);
26844
26948
  }
26845
26949
  options = options || {};
26846
- if (!options.tolerant && relative.scheme) {
26847
- target.scheme = relative.scheme;
26848
- target.userinfo = relative.userinfo;
26849
- target.host = relative.host;
26850
- target.port = relative.port;
26851
- target.path = removeDotSegments(relative.path || "");
26852
- target.query = relative.query;
26950
+ if (!options.tolerant && relative2.scheme) {
26951
+ target.scheme = relative2.scheme;
26952
+ target.userinfo = relative2.userinfo;
26953
+ target.host = relative2.host;
26954
+ target.port = relative2.port;
26955
+ target.path = removeDotSegments(relative2.path || "");
26956
+ target.query = relative2.query;
26853
26957
  } else {
26854
- if (relative.userinfo !== void 0 || relative.host !== void 0 || relative.port !== void 0) {
26855
- target.userinfo = relative.userinfo;
26856
- target.host = relative.host;
26857
- target.port = relative.port;
26858
- target.path = removeDotSegments(relative.path || "");
26859
- target.query = relative.query;
26958
+ if (relative2.userinfo !== void 0 || relative2.host !== void 0 || relative2.port !== void 0) {
26959
+ target.userinfo = relative2.userinfo;
26960
+ target.host = relative2.host;
26961
+ target.port = relative2.port;
26962
+ target.path = removeDotSegments(relative2.path || "");
26963
+ target.query = relative2.query;
26860
26964
  } else {
26861
- if (!relative.path) {
26965
+ if (!relative2.path) {
26862
26966
  target.path = base.path;
26863
- if (relative.query !== void 0) {
26864
- target.query = relative.query;
26967
+ if (relative2.query !== void 0) {
26968
+ target.query = relative2.query;
26865
26969
  } else {
26866
26970
  target.query = base.query;
26867
26971
  }
26868
26972
  } else {
26869
- if (relative.path[0] === "/") {
26870
- target.path = removeDotSegments(relative.path);
26973
+ if (relative2.path[0] === "/") {
26974
+ target.path = removeDotSegments(relative2.path);
26871
26975
  } else {
26872
26976
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
26873
- target.path = "/" + relative.path;
26977
+ target.path = "/" + relative2.path;
26874
26978
  } else if (!base.path) {
26875
- target.path = relative.path;
26979
+ target.path = relative2.path;
26876
26980
  } else {
26877
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
26981
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative2.path;
26878
26982
  }
26879
26983
  target.path = removeDotSegments(target.path);
26880
26984
  }
26881
- target.query = relative.query;
26985
+ target.query = relative2.query;
26882
26986
  }
26883
26987
  target.userinfo = base.userinfo;
26884
26988
  target.host = base.host;
@@ -26886,7 +26990,7 @@ function requireFastUri() {
26886
26990
  }
26887
26991
  target.scheme = base.scheme;
26888
26992
  }
26889
- target.fragment = relative.fragment;
26993
+ target.fragment = relative2.fragment;
26890
26994
  return target;
26891
26995
  }
26892
26996
  function equal2(uriA, uriB, options) {
@@ -32451,7 +32555,7 @@ async function mcpStart(options) {
32451
32555
  async function executeRemove(options, context) {
32452
32556
  const { identifier, idType = "id", fulltextDirectory, deleteFulltext = false } = options;
32453
32557
  if (context.mode === "local" && deleteFulltext && fulltextDirectory) {
32454
- const { removeReference } = await import("./index-CS8S6gE4.js").then((n) => n.A);
32558
+ const { removeReference } = await import("./index-a52FHX03.js").then((n) => n.A);
32455
32559
  return removeReference(context.library, {
32456
32560
  identifier,
32457
32561
  idType,
@@ -32506,7 +32610,7 @@ Continue?`;
32506
32610
  }
32507
32611
  async function executeInteractiveRemove(context, config2) {
32508
32612
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
32509
- const { selectReferenceItemsOrExit } = await import("./reference-select-CNWexQGu.js");
32613
+ const { selectReferenceItemsOrExit } = await import("./reference-select-aEB3-5rp.js");
32510
32614
  const allReferences = await context.library.getAll();
32511
32615
  const selectedItems = await withAlternateScreen2(
32512
32616
  () => selectReferenceItemsOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -32731,7 +32835,7 @@ async function executeInteractiveSearch(options, context, config2) {
32731
32835
  validateInteractiveOptions(options);
32732
32836
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
32733
32837
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
32734
- const { runSearchFlow } = await import("./index-BG3Ef4Pd.js");
32838
+ const { runSearchFlow } = await import("./index-DMShdNwY.js");
32735
32839
  const { search } = await import("./file-watcher-CWHg1yol.js").then((n) => n.B);
32736
32840
  const { tokenize } = await import("./file-watcher-CWHg1yol.js").then((n) => n.A);
32737
32841
  checkTTY();
@@ -32750,7 +32854,7 @@ async function executeInteractiveSearch(options, context, config2) {
32750
32854
  })
32751
32855
  );
32752
32856
  if (result.selectedItems && !result.cancelled) {
32753
- const { isSideEffectAction } = await import("./action-menu-D5s90TfM.js");
32857
+ const { isSideEffectAction } = await import("./action-menu-i1v02Qig.js");
32754
32858
  if (isSideEffectAction(result.action)) {
32755
32859
  await executeSideEffectAction(result.action, result.selectedItems, context, config2);
32756
32860
  return { output: "", cancelled: false, action: result.action };
@@ -32766,7 +32870,7 @@ async function executeSideEffectAction(action, items2, context, config2) {
32766
32870
  switch (action) {
32767
32871
  case "open-url": {
32768
32872
  const { resolveDefaultUrl: resolveDefaultUrl2 } = await Promise.resolve().then(() => url);
32769
- const { openWithSystemApp: openWithSystemApp2 } = await import("./loader-BG2eomDC.js").then((n) => n.j);
32873
+ const { openWithSystemApp: openWithSystemApp2 } = await import("./loader-CMu82BI5.js").then((n) => n.j);
32770
32874
  const item = items2[0];
32771
32875
  if (!item) return;
32772
32876
  const url$1 = resolveDefaultUrl2(item);
@@ -33048,7 +33152,7 @@ function formatShowOutput(item, options, attachmentsDirectory) {
33048
33152
  }
33049
33153
  async function executeInteractiveSelect$1(context, config2) {
33050
33154
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
33051
- const { selectReferencesOrExit } = await import("./reference-select-CNWexQGu.js");
33155
+ const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
33052
33156
  const allReferences = await context.library.getAll();
33053
33157
  const identifiers = await withAlternateScreen2(
33054
33158
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -33297,7 +33401,7 @@ function formatUpdateOutput(result, identifier) {
33297
33401
  }
33298
33402
  async function executeInteractiveUpdate(context, config2) {
33299
33403
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
33300
- const { selectReferencesOrExit } = await import("./reference-select-CNWexQGu.js");
33404
+ const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
33301
33405
  const allReferences = await context.library.getAll();
33302
33406
  const identifiers = await withAlternateScreen2(
33303
33407
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -33592,7 +33696,7 @@ function getUrlExitCode(result) {
33592
33696
  }
33593
33697
  async function executeInteractiveSelect(context, config2) {
33594
33698
  const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
33595
- const { selectReferencesOrExit } = await import("./reference-select-CNWexQGu.js");
33699
+ const { selectReferencesOrExit } = await import("./reference-select-aEB3-5rp.js");
33596
33700
  const allReferences = await context.library.getAll();
33597
33701
  const identifiers = await withAlternateScreen2(
33598
33702
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
@@ -34040,6 +34144,7 @@ function createProgram() {
34040
34144
  registerAttachCommand(program);
34041
34145
  registerMcpCommand(program);
34042
34146
  registerUrlCommand(program);
34147
+ registerInstallCommand(program);
34043
34148
  registerConfigCommand(program);
34044
34149
  registerCompletionCommand(program);
34045
34150
  return program;
@@ -34180,6 +34285,14 @@ function buildAddOptions(inputs, options, config2, stdinContent) {
34180
34285
  if (Object.keys(pubmedConfig).length > 0) {
34181
34286
  addOptions.pubmedConfig = pubmedConfig;
34182
34287
  }
34288
+ addOptions.urlConfig = config2.url;
34289
+ if (options.archiveFormat !== void 0) {
34290
+ addOptions.archiveFormat = options.archiveFormat;
34291
+ }
34292
+ if (options.archive === false) {
34293
+ addOptions.noArchive = true;
34294
+ }
34295
+ addOptions.attachmentsDirectory = config2.attachments.directory;
34183
34296
  return addOptions;
34184
34297
  }
34185
34298
  async function outputAddResultJson(result, context, full) {
@@ -34204,7 +34317,7 @@ function shouldAutoFetch(cliFlag, configEnabled) {
34204
34317
  return configEnabled;
34205
34318
  }
34206
34319
  async function performAutoFetch(addedItems, context, config2) {
34207
- const { fulltextFetch: fulltextFetch2 } = await import("./index-CS8S6gE4.js").then((n) => n.z);
34320
+ const { fulltextFetch: fulltextFetch2 } = await import("./index-a52FHX03.js").then((n) => n.z);
34208
34321
  const fetchResults = await autoFetchFulltext(addedItems, context, {
34209
34322
  fulltextConfig: config2.fulltext,
34210
34323
  fulltextDirectory: config2.attachments.directory,
@@ -34266,7 +34379,12 @@ function registerAddCommand(program) {
34266
34379
  "-i, --input <format>",
34267
34380
  "Input format: json|bibtex|ris|pmid|doi|isbn|arxiv|auto",
34268
34381
  "auto"
34269
- ).option("--verbose", "Show detailed error information").option("-o, --output <format>", "Output format: json|text", "text").option("--full", "Include full CSL-JSON data in JSON output").option("--fetch-fulltext", "Auto-fetch OA fulltext after adding").option("--no-fetch-fulltext", "Disable auto-fetch fulltext (overrides config)").action(async (inputs, options) => {
34382
+ ).option("--verbose", "Show detailed error information").option("-o, --output <format>", "Output format: json|text", "text").option("--full", "Include full CSL-JSON data in JSON output").option("--fetch-fulltext", "Auto-fetch OA fulltext after adding").option("--no-fetch-fulltext", "Disable auto-fetch fulltext (overrides config)").addOption(
34383
+ new Option("--archive-format <format>", "Archive format for URL import").choices([
34384
+ "mhtml",
34385
+ "html"
34386
+ ])
34387
+ ).option("--no-archive", "Skip archive creation for URL import").action(async (inputs, options) => {
34270
34388
  await handleAddAction(inputs, options, program);
34271
34389
  });
34272
34390
  }
@@ -34470,6 +34588,25 @@ function registerUrlCommand(program) {
34470
34588
  await handleUrlAction(identifiers.length > 0 ? identifiers : void 0, options, globalOpts);
34471
34589
  });
34472
34590
  }
34591
+ function registerInstallCommand(program) {
34592
+ const installCmd = program.command("install").description("Install tools and integrations");
34593
+ installCmd.command("skills").description("Install Agent Skills (SKILL.md) for AI coding agents").option("-f, --force", "Overwrite existing files").option("-u, --user", "Install to user-level directory (~/.agents/skills/)").action(async (options) => {
34594
+ try {
34595
+ const result = await executeInstallSkills({
34596
+ force: options.force ?? false,
34597
+ ...options.user != null && { user: options.user }
34598
+ });
34599
+ const output = formatInstallSkillsOutput(result);
34600
+ process.stdout.write(`${output}
34601
+ `);
34602
+ setExitCode(ExitCode.SUCCESS);
34603
+ } catch (error) {
34604
+ process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
34605
+ `);
34606
+ setExitCode(ExitCode.INTERNAL_ERROR);
34607
+ }
34608
+ });
34609
+ }
34473
34610
  async function main(argv) {
34474
34611
  const program = createProgram();
34475
34612
  if (process.env.COMP_LINE) {
@@ -34499,4 +34636,4 @@ export {
34499
34636
  restoreStdinAfterInk as r,
34500
34637
  syncAttachments as s
34501
34638
  };
34502
- //# sourceMappingURL=index-DCBYzNj-.js.map
34639
+ //# sourceMappingURL=index-PkCQJBdt.js.map