@ncukondo/reference-manager 0.16.0 → 0.17.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 (84) hide show
  1. package/dist/chunks/{file-watcher-B_WpVHSV.js → file-watcher-CrsNHUpz.js} +81 -29
  2. package/dist/chunks/file-watcher-CrsNHUpz.js.map +1 -0
  3. package/dist/chunks/format-CduFas9k.js +934 -0
  4. package/dist/chunks/format-CduFas9k.js.map +1 -0
  5. package/dist/chunks/{index-DHgeuWGP.js → index-B4gr0P83.js} +16 -20
  6. package/dist/chunks/{index-DHgeuWGP.js.map → index-B4gr0P83.js.map} +1 -1
  7. package/dist/chunks/{index-CEYp8OSj.js → index-CfuE2EuX.js} +6 -80
  8. package/dist/chunks/index-CfuE2EuX.js.map +1 -0
  9. package/dist/chunks/{index-4SVOiraD.js → index-CqrsgD_G.js} +1026 -177
  10. package/dist/chunks/index-CqrsgD_G.js.map +1 -0
  11. package/dist/chunks/{index-Bzl4_3Ki.js → index-D_UafVdu.js} +2 -2
  12. package/dist/chunks/index-D_UafVdu.js.map +1 -0
  13. package/dist/chunks/{loader-DuhmXjiI.js → loader-BN5sS7lg.js} +2 -2
  14. package/dist/chunks/{loader-DuhmXjiI.js.map → loader-BN5sS7lg.js.map} +1 -1
  15. package/dist/chunks/{reference-select-CgM-RBIa.js → reference-select-DbnF3oWs.js} +4 -16
  16. package/dist/chunks/reference-select-DbnF3oWs.js.map +1 -0
  17. package/dist/chunks/{style-select-tmKOHx_B.js → style-select-CbV5k3AV.js} +3 -3
  18. package/dist/chunks/{style-select-tmKOHx_B.js.map → style-select-CbV5k3AV.js.map} +1 -1
  19. package/dist/cli/commands/edit.d.ts +24 -3
  20. package/dist/cli/commands/edit.d.ts.map +1 -1
  21. package/dist/cli/commands/update.d.ts +1 -1
  22. package/dist/cli/commands/update.d.ts.map +1 -1
  23. package/dist/cli.js +2 -2
  24. package/dist/core/csl-json/types.d.ts +0 -12
  25. package/dist/core/csl-json/types.d.ts.map +1 -1
  26. package/dist/core/library-interface.d.ts +14 -2
  27. package/dist/core/library-interface.d.ts.map +1 -1
  28. package/dist/core/library.d.ts +10 -1
  29. package/dist/core/library.d.ts.map +1 -1
  30. package/dist/features/edit/edit-session.d.ts +4 -0
  31. package/dist/features/edit/edit-session.d.ts.map +1 -1
  32. package/dist/features/edit/edit-validator.d.ts +19 -0
  33. package/dist/features/edit/edit-validator.d.ts.map +1 -0
  34. package/dist/features/edit/field-transformer.d.ts +4 -0
  35. package/dist/features/edit/field-transformer.d.ts.map +1 -1
  36. package/dist/features/edit/index.d.ts +2 -1
  37. package/dist/features/edit/index.d.ts.map +1 -1
  38. package/dist/features/edit/json-serializer.d.ts +9 -0
  39. package/dist/features/edit/json-serializer.d.ts.map +1 -1
  40. package/dist/features/edit/validation-prompt.d.ts +17 -0
  41. package/dist/features/edit/validation-prompt.d.ts.map +1 -0
  42. package/dist/features/edit/yaml-serializer.d.ts +10 -0
  43. package/dist/features/edit/yaml-serializer.d.ts.map +1 -1
  44. package/dist/features/fulltext/index.d.ts +0 -1
  45. package/dist/features/fulltext/index.d.ts.map +1 -1
  46. package/dist/features/interactive/apps/runCiteFlow.d.ts +1 -1
  47. package/dist/features/interactive/apps/runCiteFlow.d.ts.map +1 -1
  48. package/dist/features/interactive/apps/runSearchFlow.d.ts.map +1 -1
  49. package/dist/features/interactive/components/SearchableMultiSelect.d.ts.map +1 -1
  50. package/dist/features/interactive/components/index.d.ts +1 -0
  51. package/dist/features/interactive/components/index.d.ts.map +1 -1
  52. package/dist/features/interactive/components/layout.d.ts +23 -0
  53. package/dist/features/interactive/components/layout.d.ts.map +1 -0
  54. package/dist/features/interactive/search-prompt.d.ts +2 -15
  55. package/dist/features/interactive/search-prompt.d.ts.map +1 -1
  56. package/dist/features/operations/change-details.d.ts +27 -0
  57. package/dist/features/operations/change-details.d.ts.map +1 -0
  58. package/dist/features/operations/json-output.d.ts +2 -0
  59. package/dist/features/operations/json-output.d.ts.map +1 -1
  60. package/dist/features/operations/remove.d.ts +0 -1
  61. package/dist/features/operations/remove.d.ts.map +1 -1
  62. package/dist/features/operations/update.d.ts +4 -2
  63. package/dist/features/operations/update.d.ts.map +1 -1
  64. package/dist/index.js +16 -15
  65. package/dist/index.js.map +1 -1
  66. package/dist/server.js +2 -2
  67. package/dist/utils/index.d.ts +1 -1
  68. package/dist/utils/index.d.ts.map +1 -1
  69. package/dist/utils/object.d.ts +5 -0
  70. package/dist/utils/object.d.ts.map +1 -1
  71. package/package.json +1 -1
  72. package/dist/chunks/alternate-screen-DcxkOKfW.js +0 -19
  73. package/dist/chunks/alternate-screen-DcxkOKfW.js.map +0 -1
  74. package/dist/chunks/file-watcher-B_WpVHSV.js.map +0 -1
  75. package/dist/chunks/format-C6FA-7hE.js +0 -397
  76. package/dist/chunks/format-C6FA-7hE.js.map +0 -1
  77. package/dist/chunks/index-4SVOiraD.js.map +0 -1
  78. package/dist/chunks/index-Bzl4_3Ki.js.map +0 -1
  79. package/dist/chunks/index-CEYp8OSj.js.map +0 -1
  80. package/dist/chunks/jsx-runtime-Q5cUjSur.js +0 -322
  81. package/dist/chunks/jsx-runtime-Q5cUjSur.js.map +0 -1
  82. package/dist/chunks/reference-select-CgM-RBIa.js.map +0 -1
  83. package/dist/features/fulltext/manager.d.ts +0 -109
  84. package/dist/features/fulltext/manager.d.ts.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { Command } from "commander";
2
- import { L as Library, p as pickDefined, a as sortOrderSchema, v as paginationOptionsSchema, F as FileWatcher, b as sortFieldSchema, u as searchSortFieldSchema } from "./file-watcher-B_WpVHSV.js";
2
+ import { i as isEqual, M as MANAGED_CUSTOM_FIELDS, L as Library, g as CslItemSchema, p as pickDefined, a as sortOrderSchema, x as paginationOptionsSchema, F as FileWatcher, b as sortFieldSchema, v as searchSortFieldSchema } from "./file-watcher-CrsNHUpz.js";
3
3
  import * as fs from "node:fs";
4
4
  import { promises, readFileSync, existsSync, writeFileSync, mkdirSync, mkdtempSync } from "node:fs";
5
5
  import * as os from "node:os";
@@ -7,24 +7,158 @@ import { tmpdir } from "node:os";
7
7
  import * as path from "node:path";
8
8
  import path__default, { extname, join, basename, dirname } from "node:path";
9
9
  import fs__default, { stat, rename, copyFile, readFile, unlink, readdir, mkdir, rm } from "node:fs/promises";
10
- import { g as getExtension, i as isValidFulltextFiles, a as isReservedRole, F as FULLTEXT_ROLE, b as formatToExtension, c as findFulltextFiles, d as findFulltextFile, e as extensionToFormat, B as BUILTIN_STYLES, h as getFulltextAttachmentTypes, s as startServerWithFileWatcher } from "./index-DHgeuWGP.js";
11
- import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-DuhmXjiI.js";
10
+ import { g as getExtension, i as isValidFulltextFiles, a as isReservedRole, F as FULLTEXT_ROLE, b as formatToExtension, c as findFulltextFiles, d as findFulltextFile, e as extensionToFormat, B as BUILTIN_STYLES, h as getFulltextAttachmentTypes, s as startServerWithFileWatcher } from "./index-B4gr0P83.js";
11
+ import { o as openWithSystemApp, l as loadConfig, e as getDefaultCurrentDirConfigFilename, h as getDefaultUserConfigPath } from "./loader-BN5sS7lg.js";
12
12
  import { spawn, spawnSync } from "node:child_process";
13
13
  import process$1, { stdin, stdout } from "node:process";
14
14
  import * as readline from "node:readline";
15
15
  import { parse as parse$2, stringify as stringify$2 } from "@iarna/toml";
16
+ import { useFocus, useInput, Box, Text, render, useApp } from "ink";
17
+ import require$$0, { useState, createElement } from "react";
16
18
  import "@citation-js/core";
17
19
  import "@citation-js/plugin-csl";
18
20
  import { ZodOptional as ZodOptional$2, z } from "zod";
19
21
  import { serve } from "@hono/node-server";
20
22
  const name = "@ncukondo/reference-manager";
21
- const version$1 = "0.16.0";
23
+ const version$1 = "0.17.0";
22
24
  const description$1 = "A local reference management tool using CSL-JSON as the single source of truth";
23
25
  const packageJson = {
24
26
  name,
25
27
  version: version$1,
26
28
  description: description$1
27
29
  };
30
+ const ISO_DATE_REGEX$1 = /^\d{4}(-\d{2})?(-\d{2})?$/;
31
+ function datePartsToIso(dateParts) {
32
+ if (!dateParts || dateParts.length === 0 || !dateParts[0]) {
33
+ return "";
34
+ }
35
+ const firstPart = dateParts[0];
36
+ const year = firstPart[0];
37
+ const month = firstPart[1];
38
+ const day = firstPart[2];
39
+ const parts = [String(year)];
40
+ if (month !== void 0) {
41
+ parts.push(String(month).padStart(2, "0"));
42
+ }
43
+ if (day !== void 0) {
44
+ parts.push(String(day).padStart(2, "0"));
45
+ }
46
+ return parts.join("-");
47
+ }
48
+ function isoToDateParts(isoDate) {
49
+ const parts = isoDate.split("-").map(Number);
50
+ return [parts];
51
+ }
52
+ function transformDateToEdit(date2) {
53
+ if (!date2 || !date2["date-parts"]) {
54
+ return void 0;
55
+ }
56
+ return datePartsToIso(date2["date-parts"]);
57
+ }
58
+ function transformDateFromEdit(isoDate) {
59
+ return {
60
+ "date-parts": isoToDateParts(isoDate)
61
+ };
62
+ }
63
+ const DATE_FIELDS$1 = /* @__PURE__ */ new Set(["issued", "accessed"]);
64
+ const MAX_DISPLAY_LENGTH = 40;
65
+ function getChangedCustomFields(oldCustom, newCustom) {
66
+ const changed = [];
67
+ const customKeys = /* @__PURE__ */ new Set([...Object.keys(oldCustom), ...Object.keys(newCustom)]);
68
+ for (const ck of customKeys) {
69
+ if (MANAGED_CUSTOM_FIELDS.has(ck)) continue;
70
+ if (!isEqual(oldCustom[ck], newCustom[ck])) {
71
+ changed.push(`custom.${ck}`);
72
+ }
73
+ }
74
+ return changed;
75
+ }
76
+ function getChangedFields(oldItem, newItem) {
77
+ const changed = [];
78
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(oldItem), ...Object.keys(newItem)]);
79
+ for (const key of allKeys) {
80
+ if (key === "custom") {
81
+ const oldCustom = oldItem.custom ?? {};
82
+ const newCustom = newItem.custom ?? {};
83
+ changed.push(...getChangedCustomFields(oldCustom, newCustom));
84
+ continue;
85
+ }
86
+ const oldVal = oldItem[key];
87
+ const newVal = newItem[key];
88
+ if (!isEqual(oldVal, newVal)) {
89
+ changed.push(key);
90
+ }
91
+ }
92
+ return changed;
93
+ }
94
+ function truncate(s) {
95
+ if (s.length <= MAX_DISPLAY_LENGTH) return s;
96
+ return `${s.slice(0, MAX_DISPLAY_LENGTH - 1)}…`;
97
+ }
98
+ function pluralEntry(n) {
99
+ return Math.abs(n) === 1 ? "entry" : "entries";
100
+ }
101
+ function formatArrayChange(field, oldValue, newValue) {
102
+ const oldLen = Array.isArray(oldValue) ? oldValue.length : 0;
103
+ const newLen = Array.isArray(newValue) ? newValue.length : 0;
104
+ const diff = newLen - oldLen;
105
+ if (diff !== 0) {
106
+ const sign = diff > 0 ? "+" : "";
107
+ return `${field}: ${sign}${diff} ${pluralEntry(diff)}`;
108
+ }
109
+ return `${field}: modified`;
110
+ }
111
+ function formatScalarChange(field, oldValue, newValue) {
112
+ const oldStr = oldValue != null ? String(oldValue) : void 0;
113
+ const newStr = newValue != null ? String(newValue) : void 0;
114
+ if (oldStr == null && newStr != null) {
115
+ return `${field}: → "${truncate(newStr)}"`;
116
+ }
117
+ if (oldStr != null && newStr == null) {
118
+ return `${field}: "${truncate(oldStr)}" → (removed)`;
119
+ }
120
+ return `${field}: "${truncate(oldStr ?? "")}" → "${truncate(newStr ?? "")}"`;
121
+ }
122
+ function formatDateValue(value) {
123
+ if (value == null) return void 0;
124
+ const isoDate = transformDateToEdit(value);
125
+ return isoDate ?? JSON.stringify(value);
126
+ }
127
+ function formatDateChange(field, oldValue, newValue) {
128
+ const oldStr = formatDateValue(oldValue);
129
+ const newStr = formatDateValue(newValue);
130
+ if (oldStr == null && newStr != null) {
131
+ return `${field}: → "${newStr}"`;
132
+ }
133
+ if (oldStr != null && newStr == null) {
134
+ return `${field}: "${oldStr}" → (removed)`;
135
+ }
136
+ return `${field}: "${oldStr ?? ""}" → "${newStr ?? ""}"`;
137
+ }
138
+ function formatFieldChange(field, oldValue, newValue) {
139
+ if (DATE_FIELDS$1.has(field)) {
140
+ return formatDateChange(field, oldValue, newValue);
141
+ }
142
+ if (Array.isArray(oldValue) || Array.isArray(newValue)) {
143
+ return formatArrayChange(field, oldValue, newValue);
144
+ }
145
+ return formatScalarChange(field, oldValue, newValue);
146
+ }
147
+ function getFieldValue(item, field) {
148
+ if (field.startsWith("custom.")) {
149
+ const customKey = field.slice("custom.".length);
150
+ return item.custom?.[customKey];
151
+ }
152
+ return item[field];
153
+ }
154
+ function formatChangeDetails(oldItem, newItem) {
155
+ const changedFields = getChangedFields(oldItem, newItem);
156
+ return changedFields.map((field) => {
157
+ const oldVal = getFieldValue(oldItem, field);
158
+ const newVal = getFieldValue(newItem, field);
159
+ return ` ${formatFieldChange(field, oldVal, newVal)}`;
160
+ });
161
+ }
28
162
  function formatAddJsonOutput(result, options) {
29
163
  const { full = false, items: items2 = /* @__PURE__ */ new Map() } = options;
30
164
  const added = result.added.map((item) => {
@@ -90,43 +224,61 @@ function formatRemoveJsonOutput(result, id2, options) {
90
224
  }
91
225
  return output;
92
226
  }
93
- function formatUpdateJsonOutput(result, originalId, options) {
94
- const { full = false, before } = options;
95
- if (!result.updated || !result.item) {
96
- if (result.idCollision) {
97
- return {
98
- success: false,
99
- id: originalId,
100
- error: "ID collision: target ID already exists"
101
- };
102
- }
103
- return {
104
- success: false,
105
- id: originalId,
106
- error: `Reference not found: ${originalId}`
107
- };
227
+ function formatUpdateErrorJson(originalId, errorType) {
228
+ if (errorType === "id_collision") {
229
+ return { success: false, id: originalId, error: "ID collision: target ID already exists" };
108
230
  }
109
- const item = result.item;
110
- const uuid2 = item.custom?.uuid;
111
- const finalId = result.idChanged && result.newId ? result.newId : item.id ?? originalId;
112
- const output = {
231
+ return { success: false, id: originalId, error: `Reference not found: ${originalId}` };
232
+ }
233
+ function addFullOutputFields(output, item, before) {
234
+ if (before) output.before = before;
235
+ output.after = item;
236
+ }
237
+ function buildUpdateSuccessOutput(item, id2) {
238
+ return {
113
239
  success: true,
114
- id: finalId,
115
- ...uuid2 && { uuid: uuid2 },
240
+ id: id2,
241
+ ...item.custom?.uuid && { uuid: item.custom.uuid },
116
242
  title: typeof item.title === "string" ? item.title : ""
117
243
  };
244
+ }
245
+ function formatUnchangedJson(result, originalId, options) {
246
+ const item = result.item;
247
+ const output = buildUpdateSuccessOutput(item, item.id ?? originalId);
248
+ output.unchanged = true;
118
249
  if (result.idChanged && result.newId) {
119
250
  output.idChanged = true;
120
251
  output.previousId = originalId;
121
252
  }
122
- if (full) {
123
- if (before) {
124
- output.before = before;
253
+ if (options.full) addFullOutputFields(output, item, options.before);
254
+ return output;
255
+ }
256
+ function formatUpdateSuccessJson(result, originalId, options) {
257
+ const item = result.item;
258
+ const finalId = result.idChanged && result.newId ? result.newId : item.id ?? originalId;
259
+ const output = buildUpdateSuccessOutput(item, finalId);
260
+ if (result.oldItem) {
261
+ const changes = getChangedFields(result.oldItem, item);
262
+ if (changes.length > 0) {
263
+ output.changes = changes;
125
264
  }
126
- output.after = item;
127
265
  }
266
+ if (result.idChanged && result.newId) {
267
+ output.idChanged = true;
268
+ output.previousId = originalId;
269
+ }
270
+ if (options.full) addFullOutputFields(output, item, options.before);
128
271
  return output;
129
272
  }
273
+ function formatUpdateJsonOutput(result, originalId, options) {
274
+ if (!result.updated && !result.item) {
275
+ return formatUpdateErrorJson(originalId, result.errorType);
276
+ }
277
+ if (!result.updated && result.item) {
278
+ return formatUnchangedJson(result, originalId, options);
279
+ }
280
+ return formatUpdateSuccessJson(result, originalId, options);
281
+ }
130
282
  const jsonOutput = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
131
283
  __proto__: null,
132
284
  formatAddJsonOutput,
@@ -880,15 +1032,15 @@ class OperationsLibrary {
880
1032
  }
881
1033
  // High-level operations
882
1034
  async search(options) {
883
- const { searchReferences } = await import("./index-DHgeuWGP.js").then((n) => n.n);
1035
+ const { searchReferences } = await import("./index-B4gr0P83.js").then((n) => n.n);
884
1036
  return searchReferences(this.library, options);
885
1037
  }
886
1038
  async list(options) {
887
- const { listReferences } = await import("./index-DHgeuWGP.js").then((n) => n.m);
1039
+ const { listReferences } = await import("./index-B4gr0P83.js").then((n) => n.m);
888
1040
  return listReferences(this.library, options ?? {});
889
1041
  }
890
1042
  async cite(options) {
891
- const { citeReferences } = await import("./index-DHgeuWGP.js").then((n) => n.l);
1043
+ const { citeReferences } = await import("./index-B4gr0P83.js").then((n) => n.l);
892
1044
  const defaultStyle = options.defaultStyle ?? this.citationConfig?.defaultStyle;
893
1045
  const cslDirectory = options.cslDirectory ?? this.citationConfig?.cslDirectory;
894
1046
  const mergedOptions = {
@@ -899,32 +1051,32 @@ class OperationsLibrary {
899
1051
  return citeReferences(this.library, mergedOptions);
900
1052
  }
901
1053
  async import(inputs, options) {
902
- const { addReferences } = await import("./index-DHgeuWGP.js").then((n) => n.k);
1054
+ const { addReferences } = await import("./index-B4gr0P83.js").then((n) => n.k);
903
1055
  return addReferences(inputs, this.library, options ?? {});
904
1056
  }
905
1057
  // Attachment operations
906
1058
  async attachAdd(options) {
907
- const { addAttachment: addAttachment2 } = await import("./index-Bzl4_3Ki.js");
1059
+ const { addAttachment: addAttachment2 } = await import("./index-D_UafVdu.js");
908
1060
  return addAttachment2(this.library, options);
909
1061
  }
910
1062
  async attachList(options) {
911
- const { listAttachments: listAttachments2 } = await import("./index-Bzl4_3Ki.js");
1063
+ const { listAttachments: listAttachments2 } = await import("./index-D_UafVdu.js");
912
1064
  return listAttachments2(this.library, options);
913
1065
  }
914
1066
  async attachGet(options) {
915
- const { getAttachment: getAttachment2 } = await import("./index-Bzl4_3Ki.js");
1067
+ const { getAttachment: getAttachment2 } = await import("./index-D_UafVdu.js");
916
1068
  return getAttachment2(this.library, options);
917
1069
  }
918
1070
  async attachDetach(options) {
919
- const { detachAttachment: detachAttachment2 } = await import("./index-Bzl4_3Ki.js");
1071
+ const { detachAttachment: detachAttachment2 } = await import("./index-D_UafVdu.js");
920
1072
  return detachAttachment2(this.library, options);
921
1073
  }
922
1074
  async attachSync(options) {
923
- const { syncAttachments: syncAttachments2 } = await import("./index-Bzl4_3Ki.js");
1075
+ const { syncAttachments: syncAttachments2 } = await import("./index-D_UafVdu.js");
924
1076
  return syncAttachments2(this.library, options);
925
1077
  }
926
1078
  async attachOpen(options) {
927
- const { openAttachment: openAttachment2 } = await import("./index-Bzl4_3Ki.js");
1079
+ const { openAttachment: openAttachment2 } = await import("./index-D_UafVdu.js");
928
1080
  return openAttachment2(this.library, options);
929
1081
  }
930
1082
  }
@@ -1006,7 +1158,7 @@ class ServerClient {
1006
1158
  const result = await response.json();
1007
1159
  const updateResult = { updated: result.updated };
1008
1160
  if (result.item !== void 0) updateResult.item = result.item;
1009
- if (result.idCollision !== void 0) updateResult.idCollision = result.idCollision;
1161
+ if (result.errorType !== void 0) updateResult.errorType = result.errorType;
1010
1162
  if (result.idChanged !== void 0) updateResult.idChanged = result.idChanged;
1011
1163
  if (result.newId !== void 0) updateResult.newId = result.newId;
1012
1164
  return updateResult;
@@ -1605,10 +1757,10 @@ function getAttachExitCode(result) {
1605
1757
  return result.success ? 0 : 1;
1606
1758
  }
1607
1759
  async function executeInteractiveSelect$1(context, config2) {
1608
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
1609
- const { selectReferencesOrExit } = await import("./reference-select-CgM-RBIa.js");
1760
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
1761
+ const { selectReferencesOrExit } = await import("./reference-select-DbnF3oWs.js");
1610
1762
  const allReferences = await context.library.getAll();
1611
- const identifiers = await withAlternateScreen(
1763
+ const identifiers = await withAlternateScreen2(
1612
1764
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
1613
1765
  );
1614
1766
  return identifiers[0];
@@ -1978,11 +2130,11 @@ function getCiteExitCode(result) {
1978
2130
  return 0;
1979
2131
  }
1980
2132
  async function executeInteractiveCite(options, context, config2) {
1981
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
1982
- const { runCiteFlow } = await import("./index-CEYp8OSj.js");
1983
- const { buildStyleChoices, listCustomStyles } = await import("./style-select-tmKOHx_B.js");
1984
- const { search } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.y);
1985
- const { tokenize } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.x);
2133
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
2134
+ const { runCiteFlow } = await import("./index-CfuE2EuX.js");
2135
+ const { buildStyleChoices, listCustomStyles } = await import("./style-select-CbV5k3AV.js");
2136
+ const { search } = await import("./file-watcher-CrsNHUpz.js").then((n) => n.z);
2137
+ const { tokenize } = await import("./file-watcher-CrsNHUpz.js").then((n) => n.y);
1986
2138
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
1987
2139
  checkTTY();
1988
2140
  const allReferences = await context.library.getAll();
@@ -1998,7 +2150,7 @@ async function executeInteractiveCite(options, context, config2) {
1998
2150
  const showStyleSelect = !options.style && !options.cslFile;
1999
2151
  const customStyles = listCustomStyles(config2.citation.cslDirectory);
2000
2152
  const styleOptions = buildStyleChoices(customStyles, config2.citation.defaultStyle);
2001
- const result = await withAlternateScreen(
2153
+ const result = await withAlternateScreen2(
2002
2154
  () => runCiteFlow({
2003
2155
  allReferences,
2004
2156
  searchFn,
@@ -2734,6 +2886,9 @@ function openEditor(editor, filePath) {
2734
2886
  function readTempFile(filePath) {
2735
2887
  return fs.readFileSync(filePath, "utf-8");
2736
2888
  }
2889
+ function writeTempFile(filePath, content) {
2890
+ fs.writeFileSync(filePath, content, "utf-8");
2891
+ }
2737
2892
  function deleteTempFile(filePath) {
2738
2893
  try {
2739
2894
  fs.unlinkSync(filePath);
@@ -2896,55 +3051,70 @@ function registerConfigCommand(program) {
2896
3051
  }
2897
3052
  });
2898
3053
  }
2899
- function datePartsToIso(dateParts) {
2900
- if (!dateParts || dateParts.length === 0 || !dateParts[0]) {
2901
- return "";
2902
- }
2903
- const firstPart = dateParts[0];
2904
- const year = firstPart[0];
2905
- const month = firstPart[1];
2906
- const day = firstPart[2];
2907
- const parts = [String(year)];
2908
- if (month !== void 0) {
2909
- parts.push(String(month).padStart(2, "0"));
2910
- }
2911
- if (day !== void 0) {
2912
- parts.push(String(day).padStart(2, "0"));
3054
+ const DATE_FIELDS = ["issued", "accessed"];
3055
+ const DATE_ERROR_MESSAGE = "Invalid date format (use YYYY, YYYY-MM, or YYYY-MM-DD)";
3056
+ function validateEditFormat(items2) {
3057
+ const errors2 = /* @__PURE__ */ new Map();
3058
+ for (let i = 0; i < items2.length; i++) {
3059
+ const item = items2[i];
3060
+ const itemErrors = [];
3061
+ for (const field of DATE_FIELDS) {
3062
+ const value = item[field];
3063
+ if (typeof value === "string" && !ISO_DATE_REGEX$1.test(value)) {
3064
+ itemErrors.push({ field, message: DATE_ERROR_MESSAGE });
3065
+ }
3066
+ }
3067
+ if (itemErrors.length > 0) {
3068
+ errors2.set(i, itemErrors);
3069
+ }
2913
3070
  }
2914
- return parts.join("-");
3071
+ return { valid: errors2.size === 0, errors: errors2 };
2915
3072
  }
2916
- function isoToDateParts(isoDate) {
2917
- const parts = isoDate.split("-").map(Number);
2918
- return [parts];
3073
+ function validateCslItems(items2) {
3074
+ const errors2 = /* @__PURE__ */ new Map();
3075
+ for (let i = 0; i < items2.length; i++) {
3076
+ const item = items2[i];
3077
+ const transformed = transformDatesForValidation(item);
3078
+ const parseResult = CslItemSchema.safeParse(transformed);
3079
+ if (!parseResult.success) {
3080
+ const itemErrors = parseResult.error.issues.map((issue2) => ({
3081
+ field: issue2.path.join(".") || issue2.code,
3082
+ message: issue2.message
3083
+ }));
3084
+ errors2.set(i, itemErrors);
3085
+ }
3086
+ }
3087
+ return { valid: errors2.size === 0, errors: errors2 };
2919
3088
  }
2920
- function transformDateToEdit(date2) {
2921
- if (!date2 || !date2["date-parts"]) {
2922
- return void 0;
3089
+ function validateEditedItems(items2) {
3090
+ const stage1 = validateEditFormat(items2);
3091
+ if (!stage1.valid) {
3092
+ return stage1;
2923
3093
  }
2924
- return datePartsToIso(date2["date-parts"]);
3094
+ return validateCslItems(items2);
2925
3095
  }
2926
- function transformDateFromEdit(isoDate) {
2927
- return {
2928
- "date-parts": isoToDateParts(isoDate)
2929
- };
3096
+ function transformDatesForValidation(item) {
3097
+ const result = { ...item };
3098
+ for (const field of DATE_FIELDS) {
3099
+ const value = result[field];
3100
+ if (typeof value === "string" && ISO_DATE_REGEX$1.test(value)) {
3101
+ result[field] = transformDateFromEdit(value);
3102
+ }
3103
+ }
3104
+ return result;
2930
3105
  }
2931
- const PROTECTED_FIELDS$3 = ["uuid", "created_at", "timestamp", "fulltext"];
2932
- const ISO_DATE_REGEX$1 = /^\d{4}(-\d{2})?(-\d{2})?$/;
2933
3106
  function extractProtectedFields(custom2) {
2934
3107
  if (!custom2) return {};
2935
3108
  const result = {};
2936
3109
  if (custom2.uuid) result.uuid = custom2.uuid;
2937
3110
  if (custom2.created_at) result.created_at = custom2.created_at;
2938
3111
  if (custom2.timestamp) result.timestamp = custom2.timestamp;
2939
- if (custom2.fulltext) {
2940
- result.fulltext = custom2.fulltext;
2941
- }
2942
3112
  return result;
2943
3113
  }
2944
3114
  function filterCustomFields$1(custom2) {
2945
3115
  const filtered = {};
2946
3116
  for (const [key, value] of Object.entries(custom2)) {
2947
- if (!PROTECTED_FIELDS$3.includes(key)) {
3117
+ if (!MANAGED_CUSTOM_FIELDS.has(key)) {
2948
3118
  filtered[key] = value;
2949
3119
  }
2950
3120
  }
@@ -2978,6 +3148,35 @@ function serializeToJson(items2) {
2978
3148
  const transformed = items2.map(transformItemForJson);
2979
3149
  return JSON.stringify(transformed, null, 2);
2980
3150
  }
3151
+ function stripInternalFields$1(item) {
3152
+ const result = {};
3153
+ for (const [key, value] of Object.entries(item)) {
3154
+ if (!key.startsWith("_")) {
3155
+ result[key] = value;
3156
+ }
3157
+ }
3158
+ return result;
3159
+ }
3160
+ function serializeToJsonWithErrors(editedItems, errors2, originalItems) {
3161
+ const transformed = editedItems.map((editedItem, index) => {
3162
+ const originalItem = originalItems?.[index];
3163
+ const protectedFields = originalItem ? extractProtectedFields(originalItem.custom) : {};
3164
+ const itemErrors = errors2.get(index);
3165
+ const result = {};
3166
+ if (itemErrors) {
3167
+ result._errors = itemErrors.map((e) => `${e.field}: ${e.message}`);
3168
+ }
3169
+ if (Object.keys(protectedFields).length > 0) {
3170
+ result._protected = protectedFields;
3171
+ }
3172
+ const cleanItem = stripInternalFields$1(editedItem);
3173
+ for (const [key, value] of Object.entries(cleanItem)) {
3174
+ result[key] = value;
3175
+ }
3176
+ return result;
3177
+ });
3178
+ return JSON.stringify(transformed, null, 2);
3179
+ }
2981
3180
  function transformDateFields$1(item) {
2982
3181
  const result = { ...item };
2983
3182
  for (const dateField of ["issued", "accessed"]) {
@@ -2996,7 +3195,7 @@ function deserializeFromJson(jsonContent) {
2996
3195
  return parsed.map((item) => {
2997
3196
  const protectedData = item._protected;
2998
3197
  const uuid2 = protectedData?.uuid;
2999
- const { _protected, ...rest } = item;
3198
+ const { _protected, _errors, ...rest } = item;
3000
3199
  const transformed = transformDateFields$1(rest);
3001
3200
  if (uuid2) {
3002
3201
  transformed._extractedUuid = uuid2;
@@ -3004,6 +3203,471 @@ function deserializeFromJson(jsonContent) {
3004
3203
  return transformed;
3005
3204
  });
3006
3205
  }
3206
+ const ENTER_ALT_SCREEN = "\x1B[?1049h";
3207
+ const EXIT_ALT_SCREEN = "\x1B[?1049l";
3208
+ async function withAlternateScreen(fn) {
3209
+ process.stdout.write(ENTER_ALT_SCREEN);
3210
+ try {
3211
+ return await fn();
3212
+ } finally {
3213
+ process.stdout.write(EXIT_ALT_SCREEN);
3214
+ }
3215
+ }
3216
+ function restoreStdinAfterInk() {
3217
+ setTimeout(() => {
3218
+ }, 100);
3219
+ }
3220
+ const alternateScreen = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3221
+ __proto__: null,
3222
+ restoreStdinAfterInk,
3223
+ withAlternateScreen
3224
+ }, Symbol.toStringTag, { value: "Module" }));
3225
+ function getDefaultExportFromCjs(x) {
3226
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
3227
+ }
3228
+ var jsxRuntime = { exports: {} };
3229
+ var reactJsxRuntime_production = {};
3230
+ /**
3231
+ * @license React
3232
+ * react-jsx-runtime.production.js
3233
+ *
3234
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3235
+ *
3236
+ * This source code is licensed under the MIT license found in the
3237
+ * LICENSE file in the root directory of this source tree.
3238
+ */
3239
+ var hasRequiredReactJsxRuntime_production;
3240
+ function requireReactJsxRuntime_production() {
3241
+ if (hasRequiredReactJsxRuntime_production) return reactJsxRuntime_production;
3242
+ hasRequiredReactJsxRuntime_production = 1;
3243
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
3244
+ function jsxProd(type2, config2, maybeKey) {
3245
+ var key = null;
3246
+ void 0 !== maybeKey && (key = "" + maybeKey);
3247
+ void 0 !== config2.key && (key = "" + config2.key);
3248
+ if ("key" in config2) {
3249
+ maybeKey = {};
3250
+ for (var propName in config2)
3251
+ "key" !== propName && (maybeKey[propName] = config2[propName]);
3252
+ } else maybeKey = config2;
3253
+ config2 = maybeKey.ref;
3254
+ return {
3255
+ $$typeof: REACT_ELEMENT_TYPE,
3256
+ type: type2,
3257
+ key,
3258
+ ref: void 0 !== config2 ? config2 : null,
3259
+ props: maybeKey
3260
+ };
3261
+ }
3262
+ reactJsxRuntime_production.Fragment = REACT_FRAGMENT_TYPE;
3263
+ reactJsxRuntime_production.jsx = jsxProd;
3264
+ reactJsxRuntime_production.jsxs = jsxProd;
3265
+ return reactJsxRuntime_production;
3266
+ }
3267
+ var reactJsxRuntime_development = {};
3268
+ /**
3269
+ * @license React
3270
+ * react-jsx-runtime.development.js
3271
+ *
3272
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3273
+ *
3274
+ * This source code is licensed under the MIT license found in the
3275
+ * LICENSE file in the root directory of this source tree.
3276
+ */
3277
+ var hasRequiredReactJsxRuntime_development;
3278
+ function requireReactJsxRuntime_development() {
3279
+ if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
3280
+ hasRequiredReactJsxRuntime_development = 1;
3281
+ "production" !== process.env.NODE_ENV && (function() {
3282
+ function getComponentNameFromType(type2) {
3283
+ if (null == type2) return null;
3284
+ if ("function" === typeof type2)
3285
+ return type2.$$typeof === REACT_CLIENT_REFERENCE ? null : type2.displayName || type2.name || null;
3286
+ if ("string" === typeof type2) return type2;
3287
+ switch (type2) {
3288
+ case REACT_FRAGMENT_TYPE:
3289
+ return "Fragment";
3290
+ case REACT_PROFILER_TYPE:
3291
+ return "Profiler";
3292
+ case REACT_STRICT_MODE_TYPE:
3293
+ return "StrictMode";
3294
+ case REACT_SUSPENSE_TYPE:
3295
+ return "Suspense";
3296
+ case REACT_SUSPENSE_LIST_TYPE:
3297
+ return "SuspenseList";
3298
+ case REACT_ACTIVITY_TYPE:
3299
+ return "Activity";
3300
+ }
3301
+ if ("object" === typeof type2)
3302
+ switch ("number" === typeof type2.tag && console.error(
3303
+ "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
3304
+ ), type2.$$typeof) {
3305
+ case REACT_PORTAL_TYPE:
3306
+ return "Portal";
3307
+ case REACT_CONTEXT_TYPE:
3308
+ return type2.displayName || "Context";
3309
+ case REACT_CONSUMER_TYPE:
3310
+ return (type2._context.displayName || "Context") + ".Consumer";
3311
+ case REACT_FORWARD_REF_TYPE:
3312
+ var innerType = type2.render;
3313
+ type2 = type2.displayName;
3314
+ type2 || (type2 = innerType.displayName || innerType.name || "", type2 = "" !== type2 ? "ForwardRef(" + type2 + ")" : "ForwardRef");
3315
+ return type2;
3316
+ case REACT_MEMO_TYPE:
3317
+ return innerType = type2.displayName || null, null !== innerType ? innerType : getComponentNameFromType(type2.type) || "Memo";
3318
+ case REACT_LAZY_TYPE:
3319
+ innerType = type2._payload;
3320
+ type2 = type2._init;
3321
+ try {
3322
+ return getComponentNameFromType(type2(innerType));
3323
+ } catch (x) {
3324
+ }
3325
+ }
3326
+ return null;
3327
+ }
3328
+ function testStringCoercion(value) {
3329
+ return "" + value;
3330
+ }
3331
+ function checkKeyStringCoercion(value) {
3332
+ try {
3333
+ testStringCoercion(value);
3334
+ var JSCompiler_inline_result = false;
3335
+ } catch (e) {
3336
+ JSCompiler_inline_result = true;
3337
+ }
3338
+ if (JSCompiler_inline_result) {
3339
+ JSCompiler_inline_result = console;
3340
+ var JSCompiler_temp_const = JSCompiler_inline_result.error;
3341
+ var JSCompiler_inline_result$jscomp$0 = "function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
3342
+ JSCompiler_temp_const.call(
3343
+ JSCompiler_inline_result,
3344
+ "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
3345
+ JSCompiler_inline_result$jscomp$0
3346
+ );
3347
+ return testStringCoercion(value);
3348
+ }
3349
+ }
3350
+ function getTaskName(type2) {
3351
+ if (type2 === REACT_FRAGMENT_TYPE) return "<>";
3352
+ if ("object" === typeof type2 && null !== type2 && type2.$$typeof === REACT_LAZY_TYPE)
3353
+ return "<...>";
3354
+ try {
3355
+ var name2 = getComponentNameFromType(type2);
3356
+ return name2 ? "<" + name2 + ">" : "<...>";
3357
+ } catch (x) {
3358
+ return "<...>";
3359
+ }
3360
+ }
3361
+ function getOwner() {
3362
+ var dispatcher = ReactSharedInternals.A;
3363
+ return null === dispatcher ? null : dispatcher.getOwner();
3364
+ }
3365
+ function UnknownOwner() {
3366
+ return Error("react-stack-top-frame");
3367
+ }
3368
+ function hasValidKey(config2) {
3369
+ if (hasOwnProperty.call(config2, "key")) {
3370
+ var getter = Object.getOwnPropertyDescriptor(config2, "key").get;
3371
+ if (getter && getter.isReactWarning) return false;
3372
+ }
3373
+ return void 0 !== config2.key;
3374
+ }
3375
+ function defineKeyPropWarningGetter(props, displayName) {
3376
+ function warnAboutAccessingKey() {
3377
+ specialPropKeyWarningShown || (specialPropKeyWarningShown = true, console.error(
3378
+ "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
3379
+ displayName
3380
+ ));
3381
+ }
3382
+ warnAboutAccessingKey.isReactWarning = true;
3383
+ Object.defineProperty(props, "key", {
3384
+ get: warnAboutAccessingKey,
3385
+ configurable: true
3386
+ });
3387
+ }
3388
+ function elementRefGetterWithDeprecationWarning() {
3389
+ var componentName = getComponentNameFromType(this.type);
3390
+ didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = true, console.error(
3391
+ "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
3392
+ ));
3393
+ componentName = this.props.ref;
3394
+ return void 0 !== componentName ? componentName : null;
3395
+ }
3396
+ function ReactElement(type2, key, props, owner, debugStack, debugTask) {
3397
+ var refProp = props.ref;
3398
+ type2 = {
3399
+ $$typeof: REACT_ELEMENT_TYPE,
3400
+ type: type2,
3401
+ key,
3402
+ props,
3403
+ _owner: owner
3404
+ };
3405
+ null !== (void 0 !== refProp ? refProp : null) ? Object.defineProperty(type2, "ref", {
3406
+ enumerable: false,
3407
+ get: elementRefGetterWithDeprecationWarning
3408
+ }) : Object.defineProperty(type2, "ref", { enumerable: false, value: null });
3409
+ type2._store = {};
3410
+ Object.defineProperty(type2._store, "validated", {
3411
+ configurable: false,
3412
+ enumerable: false,
3413
+ writable: true,
3414
+ value: 0
3415
+ });
3416
+ Object.defineProperty(type2, "_debugInfo", {
3417
+ configurable: false,
3418
+ enumerable: false,
3419
+ writable: true,
3420
+ value: null
3421
+ });
3422
+ Object.defineProperty(type2, "_debugStack", {
3423
+ configurable: false,
3424
+ enumerable: false,
3425
+ writable: true,
3426
+ value: debugStack
3427
+ });
3428
+ Object.defineProperty(type2, "_debugTask", {
3429
+ configurable: false,
3430
+ enumerable: false,
3431
+ writable: true,
3432
+ value: debugTask
3433
+ });
3434
+ Object.freeze && (Object.freeze(type2.props), Object.freeze(type2));
3435
+ return type2;
3436
+ }
3437
+ function jsxDEVImpl(type2, config2, maybeKey, isStaticChildren, debugStack, debugTask) {
3438
+ var children = config2.children;
3439
+ if (void 0 !== children)
3440
+ if (isStaticChildren)
3441
+ if (isArrayImpl(children)) {
3442
+ for (isStaticChildren = 0; isStaticChildren < children.length; isStaticChildren++)
3443
+ validateChildKeys(children[isStaticChildren]);
3444
+ Object.freeze && Object.freeze(children);
3445
+ } else
3446
+ console.error(
3447
+ "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
3448
+ );
3449
+ else validateChildKeys(children);
3450
+ if (hasOwnProperty.call(config2, "key")) {
3451
+ children = getComponentNameFromType(type2);
3452
+ var keys = Object.keys(config2).filter(function(k) {
3453
+ return "key" !== k;
3454
+ });
3455
+ isStaticChildren = 0 < keys.length ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" : "{key: someKey}";
3456
+ didWarnAboutKeySpread[children + isStaticChildren] || (keys = 0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}", console.error(
3457
+ 'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',
3458
+ isStaticChildren,
3459
+ children,
3460
+ keys,
3461
+ children
3462
+ ), didWarnAboutKeySpread[children + isStaticChildren] = true);
3463
+ }
3464
+ children = null;
3465
+ void 0 !== maybeKey && (checkKeyStringCoercion(maybeKey), children = "" + maybeKey);
3466
+ hasValidKey(config2) && (checkKeyStringCoercion(config2.key), children = "" + config2.key);
3467
+ if ("key" in config2) {
3468
+ maybeKey = {};
3469
+ for (var propName in config2)
3470
+ "key" !== propName && (maybeKey[propName] = config2[propName]);
3471
+ } else maybeKey = config2;
3472
+ children && defineKeyPropWarningGetter(
3473
+ maybeKey,
3474
+ "function" === typeof type2 ? type2.displayName || type2.name || "Unknown" : type2
3475
+ );
3476
+ return ReactElement(
3477
+ type2,
3478
+ children,
3479
+ maybeKey,
3480
+ getOwner(),
3481
+ debugStack,
3482
+ debugTask
3483
+ );
3484
+ }
3485
+ function validateChildKeys(node) {
3486
+ isValidElement(node) ? node._store && (node._store.validated = 1) : "object" === typeof node && null !== node && node.$$typeof === REACT_LAZY_TYPE && ("fulfilled" === node._payload.status ? isValidElement(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1));
3487
+ }
3488
+ function isValidElement(object2) {
3489
+ return "object" === typeof object2 && null !== object2 && object2.$$typeof === REACT_ELEMENT_TYPE;
3490
+ }
3491
+ var React = require$$0, REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
3492
+ return null;
3493
+ };
3494
+ React = {
3495
+ react_stack_bottom_frame: function(callStackForError) {
3496
+ return callStackForError();
3497
+ }
3498
+ };
3499
+ var specialPropKeyWarningShown;
3500
+ var didWarnAboutElementRef = {};
3501
+ var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(
3502
+ React,
3503
+ UnknownOwner
3504
+ )();
3505
+ var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
3506
+ var didWarnAboutKeySpread = {};
3507
+ reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
3508
+ reactJsxRuntime_development.jsx = function(type2, config2, maybeKey) {
3509
+ var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
3510
+ return jsxDEVImpl(
3511
+ type2,
3512
+ config2,
3513
+ maybeKey,
3514
+ false,
3515
+ trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack,
3516
+ trackActualOwner ? createTask(getTaskName(type2)) : unknownOwnerDebugTask
3517
+ );
3518
+ };
3519
+ reactJsxRuntime_development.jsxs = function(type2, config2, maybeKey) {
3520
+ var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
3521
+ return jsxDEVImpl(
3522
+ type2,
3523
+ config2,
3524
+ maybeKey,
3525
+ true,
3526
+ trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack,
3527
+ trackActualOwner ? createTask(getTaskName(type2)) : unknownOwnerDebugTask
3528
+ );
3529
+ };
3530
+ })();
3531
+ return reactJsxRuntime_development;
3532
+ }
3533
+ var hasRequiredJsxRuntime;
3534
+ function requireJsxRuntime() {
3535
+ if (hasRequiredJsxRuntime) return jsxRuntime.exports;
3536
+ hasRequiredJsxRuntime = 1;
3537
+ if (process.env.NODE_ENV === "production") {
3538
+ jsxRuntime.exports = requireReactJsxRuntime_production();
3539
+ } else {
3540
+ jsxRuntime.exports = requireReactJsxRuntime_development();
3541
+ }
3542
+ return jsxRuntime.exports;
3543
+ }
3544
+ var jsxRuntimeExports = requireJsxRuntime();
3545
+ function Select({
3546
+ options,
3547
+ message,
3548
+ onSelect,
3549
+ onCancel,
3550
+ initialIndex = 0
3551
+ }) {
3552
+ const [focusIndex, setFocusIndex] = useState(initialIndex);
3553
+ const { isFocused } = useFocus({ autoFocus: true });
3554
+ useInput(
3555
+ (input, key) => {
3556
+ if (key.escape) {
3557
+ onCancel();
3558
+ return;
3559
+ }
3560
+ if (key.return) {
3561
+ const selected = options[focusIndex];
3562
+ if (selected) {
3563
+ onSelect(selected.value);
3564
+ }
3565
+ return;
3566
+ }
3567
+ if (key.upArrow || input === "k") {
3568
+ setFocusIndex((prev) => Math.max(0, prev - 1));
3569
+ return;
3570
+ }
3571
+ if (key.downArrow || input === "j") {
3572
+ setFocusIndex((prev) => Math.min(options.length - 1, prev + 1));
3573
+ return;
3574
+ }
3575
+ },
3576
+ { isActive: isFocused }
3577
+ );
3578
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { flexDirection: "column", children: [
3579
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { bold: true, color: "cyan", children: message }) }),
3580
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { flexDirection: "column", children: options.map((option, index) => {
3581
+ const isFocusedItem = index === focusIndex;
3582
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { flexDirection: "row", children: [
3583
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { width: 2, children: isFocusedItem ? /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { color: "cyan", children: "❯" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { children: " " }) }),
3584
+ isFocusedItem ? /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { color: "cyan", bold: true, children: option.label }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { children: option.label }),
3585
+ option.hint && /* @__PURE__ */ jsxRuntimeExports.jsxs(Text, { dimColor: true, children: [
3586
+ " (",
3587
+ option.hint,
3588
+ ")"
3589
+ ] })
3590
+ ] }, `${option.label}-${index}`);
3591
+ }) }),
3592
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { dimColor: true, children: "(↑↓: navigate, Enter: select, Esc: cancel)" }) })
3593
+ ] });
3594
+ }
3595
+ function ValidationPromptApp({
3596
+ message,
3597
+ options,
3598
+ onSelect,
3599
+ onCancel
3600
+ }) {
3601
+ const { exit } = useApp();
3602
+ const handleSelect = (value) => {
3603
+ onSelect(value);
3604
+ exit();
3605
+ };
3606
+ const handleCancel = () => {
3607
+ onCancel();
3608
+ exit();
3609
+ };
3610
+ return createElement(Select, {
3611
+ options,
3612
+ message,
3613
+ onSelect: handleSelect,
3614
+ onCancel: handleCancel
3615
+ });
3616
+ }
3617
+ const PROMPT_OPTIONS = [
3618
+ { label: "Re-edit (errors shown in file)", value: "re-edit" },
3619
+ { label: "Restore original (discard changes)", value: "restore" },
3620
+ { label: "Abort (exit without saving)", value: "abort" }
3621
+ ];
3622
+ function formatErrorSummary(errors2, items2) {
3623
+ const lines = [];
3624
+ const errorCount = errors2.size;
3625
+ const totalCount = items2.length;
3626
+ lines.push(`Validation errors (${errorCount} of ${totalCount} entries):`);
3627
+ for (const [index, itemErrors] of errors2) {
3628
+ const item = items2[index];
3629
+ const id2 = item?.id ?? `Entry ${index + 1}`;
3630
+ const fields = itemErrors.map((e) => e.field).join(", ");
3631
+ lines.push(` Entry ${index + 1} (${id2}): ${fields}`);
3632
+ }
3633
+ return lines.join("\n");
3634
+ }
3635
+ function displayErrorSummary(errors2, items2) {
3636
+ const summary = formatErrorSummary(errors2, items2);
3637
+ process.stderr.write(`
3638
+ ${summary}
3639
+
3640
+ `);
3641
+ }
3642
+ async function runValidationPrompt(validationResult, items2) {
3643
+ displayErrorSummary(validationResult.errors, items2);
3644
+ return new Promise((resolve2) => {
3645
+ let result = "abort";
3646
+ const handleSelect = (value) => {
3647
+ result = value;
3648
+ };
3649
+ const handleCancel = () => {
3650
+ result = "abort";
3651
+ };
3652
+ const { waitUntilExit, clear } = render(
3653
+ createElement(ValidationPromptApp, {
3654
+ message: "What would you like to do?",
3655
+ options: PROMPT_OPTIONS,
3656
+ onSelect: handleSelect,
3657
+ onCancel: handleCancel
3658
+ })
3659
+ );
3660
+ waitUntilExit().then(() => {
3661
+ clear();
3662
+ restoreStdinAfterInk();
3663
+ resolve2(result);
3664
+ }).catch(() => {
3665
+ clear();
3666
+ restoreStdinAfterInk();
3667
+ resolve2("abort");
3668
+ });
3669
+ });
3670
+ }
3007
3671
  /*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
3008
3672
  function isNothing(subject) {
3009
3673
  return typeof subject === "undefined" || subject === null;
@@ -5602,7 +6266,6 @@ function deserializeFromYaml(yamlContent) {
5602
6266
  }
5603
6267
  return results;
5604
6268
  }
5605
- const PROTECTED_FIELDS$2 = ["uuid", "created_at", "timestamp", "fulltext"];
5606
6269
  function createProtectedComment(item) {
5607
6270
  const custom2 = item.custom;
5608
6271
  if (!custom2) {
@@ -5618,22 +6281,13 @@ function createProtectedComment(item) {
5618
6281
  if (custom2.timestamp) {
5619
6282
  lines.push(`# timestamp: ${custom2.timestamp}`);
5620
6283
  }
5621
- if (custom2.fulltext) {
5622
- lines.push("# fulltext:");
5623
- if (custom2.fulltext.pdf) {
5624
- lines.push(`# pdf: ${custom2.fulltext.pdf}`);
5625
- }
5626
- if (custom2.fulltext.markdown) {
5627
- lines.push(`# markdown: ${custom2.fulltext.markdown}`);
5628
- }
5629
- }
5630
6284
  lines.push("# ========================================");
5631
6285
  return lines.join("\n");
5632
6286
  }
5633
6287
  function filterCustomFields(customValue) {
5634
6288
  const filteredCustom = {};
5635
6289
  for (const [customKey, customVal] of Object.entries(customValue)) {
5636
- if (!PROTECTED_FIELDS$2.includes(customKey)) {
6290
+ if (!MANAGED_CUSTOM_FIELDS.has(customKey)) {
5637
6291
  filteredCustom[customKey] = customVal;
5638
6292
  }
5639
6293
  }
@@ -5680,46 +6334,134 @@ ${yamlContent}`);
5680
6334
  }
5681
6335
  return sections.join("\n---\n\n");
5682
6336
  }
6337
+ function stripInternalFields(item) {
6338
+ const result = {};
6339
+ for (const [key, value] of Object.entries(item)) {
6340
+ if (!key.startsWith("_")) {
6341
+ result[key] = value;
6342
+ }
6343
+ }
6344
+ return result;
6345
+ }
6346
+ function serializeToYamlWithErrors(editedItems, errors2, originalItems) {
6347
+ const errorCount = errors2.size;
6348
+ const totalCount = editedItems.length;
6349
+ const summaryLines = [
6350
+ `# ⚠ Validation Errors (${errorCount} of ${totalCount} entries)`,
6351
+ "# ─────────────────────────────────────"
6352
+ ];
6353
+ for (const [index, itemErrors] of errors2) {
6354
+ const item = editedItems[index];
6355
+ const id2 = item?.id ?? `Entry ${index + 1}`;
6356
+ const fields = itemErrors.map((e) => e.field).join(", ");
6357
+ summaryLines.push(`# ${id2}: ${fields}`);
6358
+ }
6359
+ summaryLines.push("# ─────────────────────────────────────");
6360
+ const sections = [];
6361
+ for (let i = 0; i < editedItems.length; i++) {
6362
+ const editedItem = editedItems[i] ?? {};
6363
+ const originalItem = originalItems?.[i];
6364
+ const itemErrors = errors2.get(i);
6365
+ let errorBlock = "";
6366
+ if (itemErrors) {
6367
+ const errorLines = ["# ⚠ Errors:"];
6368
+ for (const err of itemErrors) {
6369
+ errorLines.push(`# ${err.field}: ${err.message}`);
6370
+ }
6371
+ errorLines.push("#");
6372
+ errorBlock = `${errorLines.join("\n")}
6373
+ `;
6374
+ }
6375
+ const protectedComment = originalItem ? createProtectedComment(originalItem) : "";
6376
+ const cleanItem = stripInternalFields(editedItem);
6377
+ const yamlContent = dump([cleanItem], {
6378
+ lineWidth: -1,
6379
+ quotingType: '"',
6380
+ forceQuotes: false
6381
+ });
6382
+ const parts = [errorBlock, protectedComment ? `${protectedComment}
6383
+ ` : "", yamlContent].filter(Boolean).join("\n");
6384
+ sections.push(parts);
6385
+ }
6386
+ return `${summaryLines.join("\n")}
6387
+ ---
6388
+ ${sections.join("---\n")}`;
6389
+ }
5683
6390
  function serialize(items2, format2) {
5684
6391
  return format2 === "yaml" ? serializeToYaml(items2) : serializeToJson(items2);
5685
6392
  }
5686
6393
  function deserialize(content, format2) {
5687
6394
  return format2 === "yaml" ? deserializeFromYaml(content) : deserializeFromJson(content);
5688
6395
  }
6396
+ function serializeWithErrors(editedItems, errors2, format2, originalItems) {
6397
+ return format2 === "yaml" ? serializeToYamlWithErrors(editedItems, errors2, originalItems) : serializeToJsonWithErrors(editedItems, errors2, originalItems);
6398
+ }
5689
6399
  async function executeEdit(items2, options) {
5690
6400
  const { format: format2, editor } = options;
5691
6401
  let tempFilePath;
5692
6402
  try {
5693
6403
  const serialized = serialize(items2, format2);
5694
6404
  tempFilePath = createTempFile(serialized, format2);
5695
- const exitCode = openEditor(editor, tempFilePath);
5696
- if (exitCode !== 0) {
5697
- return {
5698
- success: false,
5699
- editedItems: [],
5700
- error: `Editor exited with code ${exitCode}`
5701
- };
6405
+ while (true) {
6406
+ const exitCode = openEditor(editor, tempFilePath);
6407
+ if (exitCode !== 0) {
6408
+ return {
6409
+ success: false,
6410
+ editedItems: [],
6411
+ error: `Editor exited with code ${exitCode}`
6412
+ };
6413
+ }
6414
+ const editedContent = readTempFile(tempFilePath);
6415
+ let editedItems;
6416
+ try {
6417
+ editedItems = deserialize(editedContent, format2);
6418
+ } catch (error) {
6419
+ const message = error instanceof Error ? error.message : String(error);
6420
+ return {
6421
+ success: false,
6422
+ editedItems: [],
6423
+ error: `Parse error: ${message}`
6424
+ };
6425
+ }
6426
+ const validationResult = validateEditedItems(editedItems);
6427
+ if (validationResult.valid) {
6428
+ return {
6429
+ success: true,
6430
+ editedItems
6431
+ };
6432
+ }
6433
+ const choice = await runValidationPrompt(validationResult, items2);
6434
+ switch (choice) {
6435
+ case "re-edit": {
6436
+ const annotated = serializeWithErrors(
6437
+ editedItems,
6438
+ validationResult.errors,
6439
+ format2,
6440
+ items2
6441
+ // Pass original items for protected fields
6442
+ );
6443
+ writeTempFile(tempFilePath, annotated);
6444
+ break;
6445
+ }
6446
+ case "restore": {
6447
+ const original = serialize(items2, format2);
6448
+ writeTempFile(tempFilePath, original);
6449
+ break;
6450
+ }
6451
+ case "abort":
6452
+ return {
6453
+ success: false,
6454
+ editedItems: [],
6455
+ aborted: true
6456
+ };
6457
+ }
5702
6458
  }
5703
- const editedContent = readTempFile(tempFilePath);
5704
- const editedItems = deserialize(editedContent, format2);
5705
- return {
5706
- success: true,
5707
- editedItems
5708
- };
5709
- } catch (error) {
5710
- const message = error instanceof Error ? error.message : String(error);
5711
- return {
5712
- success: false,
5713
- editedItems: [],
5714
- error: `Parse error: ${message}`
5715
- };
5716
6459
  } finally {
5717
6460
  if (tempFilePath) {
5718
6461
  deleteTempFile(tempFilePath);
5719
6462
  }
5720
6463
  }
5721
6464
  }
5722
- const PROTECTED_FIELDS$1 = /* @__PURE__ */ new Set(["uuid", "created_at", "timestamp", "fulltext"]);
5723
6465
  function mergeWithProtectedFields(original, edited) {
5724
6466
  const { _extractedUuid, ...rest } = edited;
5725
6467
  const result = { ...rest };
@@ -5727,7 +6469,7 @@ function mergeWithProtectedFields(original, edited) {
5727
6469
  const editedCustom = result.custom;
5728
6470
  if (originalCustom) {
5729
6471
  const mergedCustom = { ...editedCustom || {} };
5730
- for (const field of PROTECTED_FIELDS$1) {
6472
+ for (const field of MANAGED_CUSTOM_FIELDS) {
5731
6473
  if (field in originalCustom) {
5732
6474
  mergedCustom[field] = originalCustom[field];
5733
6475
  }
@@ -5755,25 +6497,72 @@ async function resolveIdentifiers(identifiers, idType, context) {
5755
6497
  }
5756
6498
  return { items: items2, uuidToOriginal };
5757
6499
  }
6500
+ function toEditItemResult(editedId, result, oldItem) {
6501
+ if (!result.updated && result.item) {
6502
+ const editResult = {
6503
+ id: editedId,
6504
+ state: "unchanged",
6505
+ item: result.item,
6506
+ oldItem
6507
+ };
6508
+ if (result.idChanged && result.newId) {
6509
+ editResult.idChanged = true;
6510
+ editResult.newId = result.newId;
6511
+ }
6512
+ return editResult;
6513
+ }
6514
+ if (!result.updated) {
6515
+ return {
6516
+ id: editedId,
6517
+ state: result.errorType === "id_collision" ? "id_collision" : "not_found",
6518
+ oldItem
6519
+ };
6520
+ }
6521
+ if (result.item) {
6522
+ const editResult = {
6523
+ id: editedId,
6524
+ state: "updated",
6525
+ item: result.item,
6526
+ oldItem
6527
+ };
6528
+ if (result.idChanged && result.newId) {
6529
+ editResult.idChanged = true;
6530
+ editResult.newId = result.newId;
6531
+ }
6532
+ return editResult;
6533
+ }
6534
+ return { id: editedId, state: "updated", oldItem };
6535
+ }
5758
6536
  async function updateEditedItem(editedItem, items2, uuidToOriginal, context) {
5759
6537
  const extractedUuid = editedItem._extractedUuid;
6538
+ const editedId = editedItem.id;
5760
6539
  const original = extractedUuid ? uuidToOriginal.get(extractedUuid) : void 0;
5761
6540
  if (original && extractedUuid) {
5762
- const updates = mergeWithProtectedFields(original, editedItem);
5763
- await context.library.update(extractedUuid, updates, { idType: "uuid" });
5764
- return editedItem.id;
6541
+ const updates2 = mergeWithProtectedFields(original, editedItem);
6542
+ const result2 = await context.library.update(extractedUuid, updates2, {
6543
+ idType: "uuid",
6544
+ onIdCollision: "suffix"
6545
+ });
6546
+ return toEditItemResult(editedId, result2, original);
5765
6547
  }
5766
- const matchedOriginal = items2.find((item) => item.id === editedItem.id);
6548
+ const matchedOriginal = items2.find((item) => item.id === editedId);
5767
6549
  if (!matchedOriginal) {
5768
- return void 0;
6550
+ return { id: editedId, state: "not_found" };
5769
6551
  }
5770
6552
  const matchedUuid = getUuidFromItem(matchedOriginal);
6553
+ const updates = mergeWithProtectedFields(matchedOriginal, editedItem);
5771
6554
  if (matchedUuid) {
5772
- const updates = mergeWithProtectedFields(matchedOriginal, editedItem);
5773
- await context.library.update(matchedUuid, updates, { idType: "uuid" });
5774
- return editedItem.id;
6555
+ const result2 = await context.library.update(matchedUuid, updates, {
6556
+ idType: "uuid",
6557
+ onIdCollision: "suffix"
6558
+ });
6559
+ return toEditItemResult(editedId, result2, matchedOriginal);
5775
6560
  }
5776
- return void 0;
6561
+ const result = await context.library.update(editedId, updates, {
6562
+ idType: "id",
6563
+ onIdCollision: "suffix"
6564
+ });
6565
+ return toEditItemResult(editedId, result, matchedOriginal);
5777
6566
  }
5778
6567
  async function executeEditCommand(options, context) {
5779
6568
  const { identifiers, format: format2, useUuid = false, editor: customEditor } = options;
@@ -5784,6 +6573,7 @@ async function executeEditCommand(options, context) {
5784
6573
  success: false,
5785
6574
  updatedCount: 0,
5786
6575
  updatedIds: [],
6576
+ results: [],
5787
6577
  error: resolved.error
5788
6578
  };
5789
6579
  }
@@ -5795,14 +6585,17 @@ async function executeEditCommand(options, context) {
5795
6585
  success: false,
5796
6586
  updatedCount: 0,
5797
6587
  updatedIds: [],
6588
+ results: [],
5798
6589
  error: editResult.error ?? "Edit failed"
5799
6590
  };
5800
6591
  }
5801
6592
  const updatedIds = [];
6593
+ const results = [];
5802
6594
  for (const editedItem of editResult.editedItems) {
5803
- const updatedId = await updateEditedItem(editedItem, items2, uuidToOriginal, context);
5804
- if (updatedId) {
5805
- updatedIds.push(updatedId);
6595
+ const updateResult = await updateEditedItem(editedItem, items2, uuidToOriginal, context);
6596
+ results.push(updateResult);
6597
+ if (updateResult.state === "updated") {
6598
+ updatedIds.push(updateResult.newId ?? updateResult.id);
5806
6599
  }
5807
6600
  }
5808
6601
  if (updatedIds.length > 0) {
@@ -5811,32 +6604,78 @@ async function executeEditCommand(options, context) {
5811
6604
  return {
5812
6605
  success: true,
5813
6606
  updatedCount: updatedIds.length,
5814
- updatedIds
6607
+ updatedIds,
6608
+ results
5815
6609
  };
5816
6610
  }
5817
- function formatEditOutput(result) {
5818
- if (result.aborted) {
5819
- return "Edit aborted.";
6611
+ function formatItemList(lines, header, items2) {
6612
+ if (items2.length === 0) return;
6613
+ if (header) lines.push(header);
6614
+ for (const item of items2) {
6615
+ lines.push(` - ${item}`);
5820
6616
  }
5821
- if (!result.success) {
5822
- return `Error: ${result.error || "Unknown error"}`;
6617
+ }
6618
+ function formatFailedItems(lines, failed) {
6619
+ if (failed.length === 0) return;
6620
+ lines.push(`Failed: ${failed.length}`);
6621
+ for (const r of failed) {
6622
+ const reason = r.state === "id_collision" ? "ID collision" : "Not found";
6623
+ lines.push(` - ${r.id} (${reason})`);
5823
6624
  }
5824
- const count = result.updatedCount;
5825
- const refWord = count === 1 ? "reference" : "references";
5826
- if (count === 0) {
5827
- return "No references were updated.";
6625
+ }
6626
+ function formatSummaryHeader(updatedCount, totalCount) {
6627
+ if (totalCount === 0 || updatedCount === totalCount) {
6628
+ const refWord = updatedCount === 1 ? "reference" : "references";
6629
+ return `Updated ${updatedCount} ${refWord}:`;
5828
6630
  }
5829
- const lines = [`Updated ${count} ${refWord}:`];
5830
- for (const id2 of result.updatedIds) {
5831
- lines.push(` - ${id2}`);
6631
+ return `Updated ${updatedCount} of ${totalCount} references:`;
6632
+ }
6633
+ function formatUpdatedItems(lines, updatedResults, updatedIds) {
6634
+ if (updatedResults.length > 0) {
6635
+ for (const r of updatedResults) {
6636
+ const displayId = r.idChanged && r.newId ? `${r.newId} (ID collision resolved: ${r.id} → ${r.newId})` : r.id;
6637
+ lines.push(` - ${displayId}`);
6638
+ if (r.oldItem && r.item) {
6639
+ lines.push(...formatChangeDetails(r.oldItem, r.item).map((l) => ` ${l}`));
6640
+ }
6641
+ }
6642
+ } else {
6643
+ formatItemList(lines, "", updatedIds);
6644
+ }
6645
+ }
6646
+ function formatEditOutput(result) {
6647
+ if (result.aborted) return "Edit aborted.";
6648
+ if (!result.success) return `Error: ${result.error || "Unknown error"}`;
6649
+ const totalCount = result.results.length;
6650
+ const { updatedCount, updatedIds } = result;
6651
+ if (totalCount === 0 && updatedCount === 0) return "No references were updated.";
6652
+ const lines = [formatSummaryHeader(updatedCount, totalCount)];
6653
+ const updatedResults = result.results.filter((r) => r.state === "updated");
6654
+ formatUpdatedItems(lines, updatedResults, updatedIds);
6655
+ if (totalCount > 0) {
6656
+ const unchanged = result.results.filter((r) => r.state === "unchanged");
6657
+ const failed = result.results.filter(
6658
+ (r) => r.state === "not_found" || r.state === "id_collision"
6659
+ );
6660
+ formatItemList(
6661
+ lines,
6662
+ `No changes: ${unchanged.length}`,
6663
+ unchanged.map((r) => {
6664
+ if (r.idChanged && r.newId) {
6665
+ return `${r.id} (ID collision resolved: requested ID already exists → kept ${r.newId})`;
6666
+ }
6667
+ return r.id;
6668
+ })
6669
+ );
6670
+ formatFailedItems(lines, failed);
5832
6671
  }
5833
6672
  return lines.join("\n");
5834
6673
  }
5835
6674
  async function executeInteractiveEdit(options, context, config2) {
5836
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
5837
- const { selectReferencesOrExit } = await import("./reference-select-CgM-RBIa.js");
6675
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
6676
+ const { selectReferencesOrExit } = await import("./reference-select-DbnF3oWs.js");
5838
6677
  const allReferences = await context.library.getAll();
5839
- const identifiers = await withAlternateScreen(
6678
+ const identifiers = await withAlternateScreen2(
5840
6679
  () => selectReferencesOrExit(allReferences, { multiSelect: true }, config2.cli.tui)
5841
6680
  );
5842
6681
  const format2 = options.format ?? config2.cli.edit.defaultFormat;
@@ -9481,10 +10320,10 @@ function getFulltextExitCode(result) {
9481
10320
  return result.success ? 0 : 1;
9482
10321
  }
9483
10322
  async function executeInteractiveSelect(context, config2) {
9484
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
9485
- const { selectReferencesOrExit } = await import("./reference-select-CgM-RBIa.js");
10323
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
10324
+ const { selectReferencesOrExit } = await import("./reference-select-DbnF3oWs.js");
9486
10325
  const allReferences = await context.library.getAll();
9487
- const identifiers = await withAlternateScreen(
10326
+ const identifiers = await withAlternateScreen2(
9488
10327
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
9489
10328
  );
9490
10329
  return identifiers[0];
@@ -21616,9 +22455,6 @@ function mergeCapabilities(base, additional) {
21616
22455
  }
21617
22456
  return result;
21618
22457
  }
21619
- function getDefaultExportFromCjs(x) {
21620
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
21621
- }
21622
22458
  var ajv = { exports: {} };
21623
22459
  var core$1 = {};
21624
22460
  var validate = {};
@@ -30489,7 +31325,7 @@ async function mcpStart(options) {
30489
31325
  async function executeRemove(options, context) {
30490
31326
  const { identifier, idType = "id", fulltextDirectory, deleteFulltext = false } = options;
30491
31327
  if (context.mode === "local" && deleteFulltext && fulltextDirectory) {
30492
- const { removeReference } = await import("./index-DHgeuWGP.js").then((n) => n.r);
31328
+ const { removeReference } = await import("./index-B4gr0P83.js").then((n) => n.r);
30493
31329
  return removeReference(context.library, {
30494
31330
  identifier,
30495
31331
  idType,
@@ -30543,10 +31379,10 @@ Continue?`;
30543
31379
  return readConfirmation(confirmMsg);
30544
31380
  }
30545
31381
  async function executeInteractiveRemove(context, config2) {
30546
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
30547
- const { selectReferenceItemsOrExit } = await import("./reference-select-CgM-RBIa.js");
31382
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
31383
+ const { selectReferenceItemsOrExit } = await import("./reference-select-DbnF3oWs.js");
30548
31384
  const allReferences = await context.library.getAll();
30549
- const selectedItems = await withAlternateScreen(
31385
+ const selectedItems = await withAlternateScreen2(
30550
31386
  () => selectReferenceItemsOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
30551
31387
  );
30552
31388
  const selectedItem = selectedItems[0];
@@ -30747,10 +31583,10 @@ function validateInteractiveOptions(options) {
30747
31583
  async function executeInteractiveSearch(options, context, config2) {
30748
31584
  validateInteractiveOptions(options);
30749
31585
  const { checkTTY } = await import("./tty-BMyaEOhX.js");
30750
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
30751
- const { runSearchFlow } = await import("./index-CEYp8OSj.js");
30752
- const { search } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.y);
30753
- const { tokenize } = await import("./file-watcher-B_WpVHSV.js").then((n) => n.x);
31586
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
31587
+ const { runSearchFlow } = await import("./index-CfuE2EuX.js");
31588
+ const { search } = await import("./file-watcher-CrsNHUpz.js").then((n) => n.z);
31589
+ const { tokenize } = await import("./file-watcher-CrsNHUpz.js").then((n) => n.y);
30754
31590
  checkTTY();
30755
31591
  const allReferences = await context.library.getAll();
30756
31592
  const searchFn = (query) => {
@@ -30758,7 +31594,7 @@ async function executeInteractiveSearch(options, context, config2) {
30758
31594
  return search(allReferences, tokens);
30759
31595
  };
30760
31596
  const tuiConfig = config2.cli.tui;
30761
- const result = await withAlternateScreen(
31597
+ const result = await withAlternateScreen2(
30762
31598
  () => runSearchFlow(allReferences, searchFn, {
30763
31599
  limit: tuiConfig.limit,
30764
31600
  debounceMs: tuiConfig.debounceMs
@@ -30866,12 +31702,7 @@ function parseSetOption(input) {
30866
31702
  value: match[3]
30867
31703
  };
30868
31704
  }
30869
- const PROTECTED_FIELDS = /* @__PURE__ */ new Set([
30870
- "custom.uuid",
30871
- "custom.created_at",
30872
- "custom.timestamp",
30873
- "custom.fulltext"
30874
- ]);
31705
+ const PROTECTED_FIELDS = new Set([...MANAGED_CUSTOM_FIELDS].map((f) => `custom.${f}`));
30875
31706
  const STRING_FIELDS = /* @__PURE__ */ new Set([
30876
31707
  "title",
30877
31708
  "abstract",
@@ -31023,18 +31854,32 @@ async function executeUpdate(options, context) {
31023
31854
  existingItem
31024
31855
  );
31025
31856
  }
31026
- const result = await context.library.update(identifier, updates, { idType });
31857
+ const result = await context.library.update(identifier, updates, {
31858
+ idType,
31859
+ onIdCollision: "suffix"
31860
+ });
31027
31861
  if (result.updated) {
31028
31862
  await context.library.save();
31029
31863
  }
31030
31864
  return result;
31031
31865
  }
31866
+ function formatNotUpdated(result, identifier) {
31867
+ if (result.errorType === "id_collision") {
31868
+ return `Update failed: ID collision for ${identifier}`;
31869
+ }
31870
+ if (result.item) {
31871
+ const noChangeMsg = `No changes: [${result.item.id}] ${result.item.title || "(no title)"}`;
31872
+ if (result.idChanged && result.newId) {
31873
+ return `${noChangeMsg}
31874
+ ID collision resolved: requested ID already exists → kept ${result.newId}`;
31875
+ }
31876
+ return noChangeMsg;
31877
+ }
31878
+ return `Reference not found: ${identifier}`;
31879
+ }
31032
31880
  function formatUpdateOutput(result, identifier) {
31033
31881
  if (!result.updated) {
31034
- if (result.idCollision) {
31035
- return `Update failed: ID collision for ${identifier}`;
31036
- }
31037
- return `Reference not found: ${identifier}`;
31882
+ return formatNotUpdated(result, identifier);
31038
31883
  }
31039
31884
  const item = result.item;
31040
31885
  const parts = [];
@@ -31044,15 +31889,18 @@ function formatUpdateOutput(result, identifier) {
31044
31889
  parts.push(`Updated reference: ${identifier}`);
31045
31890
  }
31046
31891
  if (result.idChanged && result.newId) {
31047
- parts.push(`ID changed to: ${result.newId}`);
31892
+ parts.push(`ID collision resolved: ${identifier} → ${result.newId}`);
31893
+ }
31894
+ if (result.oldItem && item) {
31895
+ parts.push(...formatChangeDetails(result.oldItem, item));
31048
31896
  }
31049
31897
  return parts.join("\n");
31050
31898
  }
31051
31899
  async function executeInteractiveUpdate(context, config2) {
31052
- const { withAlternateScreen } = await import("./alternate-screen-DcxkOKfW.js");
31053
- const { selectReferencesOrExit } = await import("./reference-select-CgM-RBIa.js");
31900
+ const { withAlternateScreen: withAlternateScreen2 } = await Promise.resolve().then(() => alternateScreen);
31901
+ const { selectReferencesOrExit } = await import("./reference-select-DbnF3oWs.js");
31054
31902
  const allReferences = await context.library.getAll();
31055
- const identifiers = await withAlternateScreen(
31903
+ const identifiers = await withAlternateScreen2(
31056
31904
  () => selectReferencesOrExit(allReferences, { multiSelect: false }, config2.cli.tui)
31057
31905
  );
31058
31906
  return identifiers[0];
@@ -31138,8 +31986,6 @@ async function handleUpdateAction(identifierArg, file, options, globalOpts) {
31138
31986
  const context = await createExecutionContext(config2, Library.load);
31139
31987
  const identifier = await resolveUpdateIdentifier(identifierArg, hasSetOptions, context, config2);
31140
31988
  const validatedUpdates = await parseUpdateInput(options.set, file);
31141
- const idType = options.uuid ? "uuid" : "id";
31142
- const beforeItem = options.full ? await context.library.find(identifier, { idType }) : void 0;
31143
31989
  const updateOptions = {
31144
31990
  identifier,
31145
31991
  updates: validatedUpdates,
@@ -31149,7 +31995,7 @@ async function handleUpdateAction(identifierArg, file, options, globalOpts) {
31149
31995
  if (outputFormat === "json") {
31150
31996
  const jsonOptions = {
31151
31997
  ...options.full && { full: true },
31152
- ...beforeItem && { before: beforeItem }
31998
+ ...result.oldItem && { before: result.oldItem }
31153
31999
  };
31154
32000
  const jsonOutput2 = formatUpdateJsonOutput2(result, identifier, jsonOptions);
31155
32001
  process.stdout.write(`${JSON.stringify(jsonOutput2)}
@@ -31814,14 +32660,17 @@ async function main(argv) {
31814
32660
  await program.parseAsync(argv);
31815
32661
  }
31816
32662
  export {
32663
+ Select as S,
31817
32664
  addAttachment as a,
31818
32665
  createProgram as c,
31819
32666
  detachAttachment as d,
31820
32667
  formatBibtex as f,
31821
32668
  getAttachment as g,
32669
+ jsxRuntimeExports as j,
31822
32670
  listAttachments as l,
31823
32671
  main as m,
31824
32672
  openAttachment as o,
32673
+ restoreStdinAfterInk as r,
31825
32674
  syncAttachments as s
31826
32675
  };
31827
- //# sourceMappingURL=index-4SVOiraD.js.map
32676
+ //# sourceMappingURL=index-CqrsgD_G.js.map