@a9i5k4/dsh-literature 0.3.1 → 0.3.3

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 (2) hide show
  1. package/lib/index.js +299 -88
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -461,16 +461,21 @@ var init_sse = __esm({
461
461
  // src/node/extract/identifiers.js
462
462
  function trimRight(s) {
463
463
  let out = s;
464
- for (; ; ) {
464
+ while (out.length > 0) {
465
465
  const next = out.replace(TRIM_RIGHT, "");
466
- const last = next[next.length - 1];
467
- if ((last === ")" || last === "]" || last === "}" || last === "\uFF09" || last === "\u3011") && !next.slice(0, -1).includes(last === ")" ? "(" : last === "]" ? "[" : last === "}" ? "{" : last === "\uFF09" ? "\uFF08" : "\u3010")) {
466
+ if (next !== out) {
468
467
  out = next;
469
468
  continue;
470
469
  }
471
- if (next === out) return next;
472
- out = next;
470
+ const last = out[out.length - 1];
471
+ const openFor = CLOSE_TO_OPEN[last];
472
+ if (openFor && !out.slice(0, -1).includes(openFor)) {
473
+ out = out.slice(0, -1);
474
+ continue;
475
+ }
476
+ return out;
473
477
  }
478
+ return out;
474
479
  }
475
480
  function push(list, seen, entry) {
476
481
  const dedupeKey = `${entry.kind}:${entry.value.toLowerCase()}`;
@@ -582,11 +587,12 @@ function extractIdentifiers(text, options = {}) {
582
587
  }
583
588
  return out.sort((a, b) => a.index - b.index);
584
589
  }
585
- var TRIM_RIGHT, CJK_PUNCT, DOI_TAIL, DOI_CORE, DOI_HINT, DOI_LABEL, ARXIV_NEW, ARXIV_OLD, URL_RE, ARXIV_URL, PMID, ISBN, QUOTED, QUOTED_FALLBACK;
590
+ var TRIM_RIGHT, CJK_PUNCT, CLOSE_TO_OPEN, DOI_TAIL, DOI_CORE, DOI_HINT, DOI_LABEL, ARXIV_NEW, ARXIV_OLD, URL_RE, ARXIV_URL, PMID, ISBN, QUOTED, QUOTED_FALLBACK;
586
591
  var init_identifiers = __esm({
587
592
  "src/node/extract/identifiers.js"() {
588
593
  TRIM_RIGHT = /[.,;:!?。、,;:!?…—>'">)》\]]+$/;
589
594
  CJK_PUNCT = "\u3002\u3001\uFF0C\uFF1B\uFF1A\uFF01\uFF1F\uFF08\uFF09\u3010\u3011\u300A\u300B\u3008\u3009\u2026\u2014\uFF5E\xB7";
595
+ CLOSE_TO_OPEN = { ")": "(", "]": "[", "}": "{", "\uFF09": "\uFF08", "\u3011": "\u3010" };
590
596
  DOI_TAIL = `[^\\s"'<>\`|${CJK_PUNCT}]+`;
591
597
  DOI_CORE = new RegExp(`10\\.\\d{4,9}\\/${DOI_TAIL}`, "gi");
592
598
  DOI_HINT = new RegExp(`(?:https?:\\/\\/)?(?:dx\\.)?doi\\.org\\/(10\\.\\d{4,9}\\/${DOI_TAIL})`, "gi");
@@ -2857,8 +2863,8 @@ async function startTask(key, kind) {
2857
2863
  emitTask(task);
2858
2864
  return task;
2859
2865
  }
2860
- async function finishTask(task, state2, message) {
2861
- const next = await putTask({ id: task.id, state: state2, progress: 100, message });
2866
+ async function finishTask(task, state3, message) {
2867
+ const next = await putTask({ id: task.id, state: state3, progress: 100, message });
2862
2868
  emitTask(next);
2863
2869
  return next;
2864
2870
  }
@@ -3111,8 +3117,8 @@ async function saveItem(key, { mode, tags } = {}) {
3111
3117
  if (wantMode === "dir") {
3112
3118
  let buffer = null;
3113
3119
  if (current.pdf?.path) {
3114
- const { readFile: readFile7 } = await import("node:fs/promises");
3115
- buffer = await readFile7(current.pdf.path).catch(() => null);
3120
+ const { readFile: readFile8 } = await import("node:fs/promises");
3121
+ buffer = await readFile8(current.pdf.path).catch(() => null);
3116
3122
  }
3117
3123
  result = await exportToDirectory(current.record, buffer);
3118
3124
  const updated2 = await patchItem(key, { state: "saved", saveMode: "dir", export: result, error: null, updatedAt: Date.now() });
@@ -3122,14 +3128,14 @@ async function saveItem(key, { mode, tags } = {}) {
3122
3128
  }
3123
3129
  let pdfBuffer = null;
3124
3130
  if (current.pdf?.path) {
3125
- const { readFile: readFile7 } = await import("node:fs/promises");
3126
- pdfBuffer = await readFile7(current.pdf.path).catch(() => null);
3131
+ const { readFile: readFile8 } = await import("node:fs/promises");
3132
+ pdfBuffer = await readFile8(current.pdf.path).catch(() => null);
3127
3133
  }
3128
3134
  if (!pdfBuffer) {
3129
3135
  const fetched = await fetchItemPdf(key);
3130
3136
  if (fetched?.pdf?.path) {
3131
- const { readFile: readFile7 } = await import("node:fs/promises");
3132
- pdfBuffer = await readFile7(fetched.pdf.path).catch(() => null);
3137
+ const { readFile: readFile8 } = await import("node:fs/promises");
3138
+ pdfBuffer = await readFile8(fetched.pdf.path).catch(() => null);
3133
3139
  } else {
3134
3140
  const err = fetched?.error ?? failure("fetch_failed", "\u65E0\u6CD5\u83B7\u53D6\u5168\u6587 PDF\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u5230\u6587\u732E\u5E93");
3135
3141
  throw Object.assign(new Error(err.message), { code: err.code ?? "fetch_failed", detail: err.detail });
@@ -5396,8 +5402,8 @@ var init_pdf2 = __esm({
5396
5402
  var getTypedArrayConstructor = function(it) {
5397
5403
  var proto = getPrototypeOf(it);
5398
5404
  if (!isObject(proto)) return;
5399
- var state2 = getInternalState(proto);
5400
- return state2 && hasOwn(state2, TYPED_ARRAY_CONSTRUCTOR) ? state2[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto);
5405
+ var state3 = getInternalState(proto);
5406
+ return state3 && hasOwn(state3, TYPED_ARRAY_CONSTRUCTOR) ? state3[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto);
5401
5407
  };
5402
5408
  var isTypedArray = function(it) {
5403
5409
  if (!isObject(it)) return false;
@@ -6234,11 +6240,11 @@ var init_pdf2 = __esm({
6234
6240
  };
6235
6241
  var getterFor = function(TYPE) {
6236
6242
  return function(it) {
6237
- var state2;
6238
- if (!isObject(it) || (state2 = get(it)).type !== TYPE) {
6243
+ var state3;
6244
+ if (!isObject(it) || (state3 = get(it)).type !== TYPE) {
6239
6245
  throw new TypeError2("Incompatible receiver, " + TYPE + " required");
6240
6246
  }
6241
- return state2;
6247
+ return state3;
6242
6248
  };
6243
6249
  };
6244
6250
  if (NATIVE_WEAK_MAP || shared.state) {
@@ -6363,8 +6369,8 @@ var init_pdf2 = __esm({
6363
6369
  var getInternalState = __webpack_require__2(1181).get;
6364
6370
  module.exports = function isRawJSON(O) {
6365
6371
  if (!isObject(O)) return false;
6366
- var state2 = getInternalState(O);
6367
- return !!state2 && state2.type === "RawJSON";
6372
+ var state3 = getInternalState(O);
6373
+ return !!state3 && state3.type === "RawJSON";
6368
6374
  };
6369
6375
  },
6370
6376
  /***/
@@ -6465,8 +6471,8 @@ var init_pdf2 = __esm({
6465
6471
  },
6466
6472
  /***/
6467
6473
  6859(module) {
6468
- module.exports = function(state2) {
6469
- state2.iterator = state2.next = state2.nextHandler = state2.mapper = state2.predicate = state2.inner = state2.iterables = state2.iters = state2.openIters = state2.padding = state2.finishResults = state2.buffer = null;
6474
+ module.exports = function(state3) {
6475
+ state3.iterator = state3.next = state3.nextHandler = state3.mapper = state3.predicate = state3.inner = state3.iterables = state3.iters = state3.openIters = state3.padding = state3.finishResults = state3.buffer = null;
6470
6476
  };
6471
6477
  },
6472
6478
  /***/
@@ -6535,31 +6541,31 @@ var init_pdf2 = __esm({
6535
6541
  var getInternalState = InternalStateModule.getterFor(IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER);
6536
6542
  return defineBuiltIns(create(IteratorPrototype), {
6537
6543
  next: function next() {
6538
- var state2 = getInternalState(this);
6539
- if (IS_ITERATOR) return state2.nextHandler();
6540
- if (state2.done) return createIterResultObject(void 0, true);
6544
+ var state3 = getInternalState(this);
6545
+ if (IS_ITERATOR) return state3.nextHandler();
6546
+ if (state3.done) return createIterResultObject(void 0, true);
6541
6547
  try {
6542
- var result = state2.nextHandler();
6543
- if (state2.done) cleanupState(state2);
6544
- return state2.returnHandlerResult ? result : createIterResultObject(result, state2.done);
6548
+ var result = state3.nextHandler();
6549
+ if (state3.done) cleanupState(state3);
6550
+ return state3.returnHandlerResult ? result : createIterResultObject(result, state3.done);
6545
6551
  } catch (error2) {
6546
- state2.done = true;
6547
- cleanupState(state2);
6552
+ state3.done = true;
6553
+ cleanupState(state3);
6548
6554
  throw error2;
6549
6555
  }
6550
6556
  },
6551
6557
  "return": function() {
6552
- var state2 = getInternalState(this);
6553
- var iterator = state2.iterator;
6554
- var inner = state2.inner;
6555
- var openIters = state2.openIters;
6556
- var done = state2.done;
6557
- state2.done = true;
6558
+ var state3 = getInternalState(this);
6559
+ var iterator = state3.iterator;
6560
+ var inner = state3.inner;
6561
+ var openIters = state3.openIters;
6562
+ var done = state3.done;
6563
+ state3.done = true;
6558
6564
  if (IS_ITERATOR) {
6559
6565
  var returnMethod = getMethod(iterator, "return");
6560
6566
  return returnMethod ? call2(returnMethod, iterator) : createIterResultObject(void 0, true);
6561
6567
  }
6562
- cleanupState(state2);
6568
+ cleanupState(state3);
6563
6569
  if (done) return createIterResultObject(void 0, true);
6564
6570
  if (inner) try {
6565
6571
  iteratorClose(inner.iterator, NORMAL);
@@ -6581,17 +6587,17 @@ var init_pdf2 = __esm({
6581
6587
  var IteratorHelperPrototype = createIteratorProxyPrototype(false);
6582
6588
  createNonEnumerableProperty(IteratorHelperPrototype, TO_STRING_TAG, "Iterator Helper");
6583
6589
  module.exports = function(nextHandler, IS_ITERATOR, RETURN_HANDLER_RESULT) {
6584
- var IteratorProxy = function Iterator2(record, state2) {
6585
- if (state2) {
6586
- state2.iterator = record.iterator;
6587
- state2.next = record.next;
6588
- } else state2 = record;
6589
- state2.type = IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER;
6590
- state2.returnHandlerResult = !!RETURN_HANDLER_RESULT;
6591
- state2.nextHandler = nextHandler;
6592
- state2.counter = 0;
6593
- state2.done = false;
6594
- setInternalState(this, state2);
6590
+ var IteratorProxy = function Iterator2(record, state3) {
6591
+ if (state3) {
6592
+ state3.iterator = record.iterator;
6593
+ state3.next = record.next;
6594
+ } else state3 = record;
6595
+ state3.type = IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER;
6596
+ state3.returnHandlerResult = !!RETURN_HANDLER_RESULT;
6597
+ state3.nextHandler = nextHandler;
6598
+ state3.counter = 0;
6599
+ state3.done = false;
6600
+ setInternalState(this, state3);
6595
6601
  };
6596
6602
  IteratorProxy.prototype = IS_ITERATOR ? WrapForValidIteratorPrototype : IteratorHelperPrototype;
6597
6603
  return IteratorProxy;
@@ -6695,7 +6701,7 @@ var init_pdf2 = __esm({
6695
6701
  var defineProperty = Object.defineProperty;
6696
6702
  var stringSlice = uncurryThis("".slice);
6697
6703
  var replace = uncurryThis("".replace);
6698
- var join9 = uncurryThis([].join);
6704
+ var join10 = uncurryThis([].join);
6699
6705
  var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
6700
6706
  return defineProperty(function() {
6701
6707
  }, "length", { value: 8 }).length !== 8;
@@ -6720,9 +6726,9 @@ var init_pdf2 = __esm({
6720
6726
  } else if (value.prototype) value.prototype = void 0;
6721
6727
  } catch (error2) {
6722
6728
  }
6723
- var state2 = enforceInternalState(value);
6724
- if (!hasOwn(state2, "source")) {
6725
- state2.source = join9(TEMPLATE, typeof name2 == "string" ? name2 : "");
6729
+ var state3 = enforceInternalState(value);
6730
+ if (!hasOwn(state3, "source")) {
6731
+ state3.source = join10(TEMPLATE, typeof name2 == "string" ? name2 : "");
6726
6732
  }
6727
6733
  return value;
6728
6734
  };
@@ -8864,21 +8870,21 @@ var init_pdf2 = __esm({
8864
8870
  sumPrecise: function sumPrecise(items) {
8865
8871
  var numbers = [];
8866
8872
  var count = 0;
8867
- var state2 = MINUS_ZERO;
8873
+ var state3 = MINUS_ZERO;
8868
8874
  iterate(items, function(n2) {
8869
8875
  if (++count > MAX_SAFE_INTEGER) throw new $RangeError("Maximum allowed index exceeded");
8870
8876
  if (typeof n2 != "number") throw new $TypeError("Value is not a number");
8871
- if (state2 !== NOT_A_NUMBER) {
8872
- if (n2 !== n2) state2 = NOT_A_NUMBER;
8873
- else if (n2 === $Infinity) state2 = state2 === MINUS_INFINITY ? NOT_A_NUMBER : PLUS_INFINITY;
8874
- else if (n2 === -$Infinity) state2 = state2 === PLUS_INFINITY ? NOT_A_NUMBER : MINUS_INFINITY;
8875
- else if ((n2 !== 0 || 1 / n2 === $Infinity) && (state2 === MINUS_ZERO || state2 === FINITE)) {
8876
- state2 = FINITE;
8877
+ if (state3 !== NOT_A_NUMBER) {
8878
+ if (n2 !== n2) state3 = NOT_A_NUMBER;
8879
+ else if (n2 === $Infinity) state3 = state3 === MINUS_INFINITY ? NOT_A_NUMBER : PLUS_INFINITY;
8880
+ else if (n2 === -$Infinity) state3 = state3 === PLUS_INFINITY ? NOT_A_NUMBER : MINUS_INFINITY;
8881
+ else if ((n2 !== 0 || 1 / n2 === $Infinity) && (state3 === MINUS_ZERO || state3 === FINITE)) {
8882
+ state3 = FINITE;
8877
8883
  push2(numbers, n2);
8878
8884
  }
8879
8885
  }
8880
8886
  });
8881
- switch (state2) {
8887
+ switch (state3) {
8882
8888
  case NOT_A_NUMBER:
8883
8889
  return $NaN;
8884
8890
  case MINUS_INFINITY:
@@ -9245,7 +9251,7 @@ var init_pdf2 = __esm({
9245
9251
  var charAt = uncurryThis("".charAt);
9246
9252
  var Uint8Array2 = globalThis2.Uint8Array;
9247
9253
  var $Array = globalThis2.Array;
9248
- var join9 = uncurryThis([].join);
9254
+ var join10 = uncurryThis([].join);
9249
9255
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
9250
9256
  try {
9251
9257
  var target = new Uint8Array2();
@@ -9291,7 +9297,7 @@ var init_pdf2 = __esm({
9291
9297
  result[written++] = "=";
9292
9298
  }
9293
9299
  }
9294
- return join9(result, "");
9300
+ return join10(result, "");
9295
9301
  }
9296
9302
  });
9297
9303
  },
@@ -9303,7 +9309,7 @@ var init_pdf2 = __esm({
9303
9309
  var anUint8Array = __webpack_require__2(4154);
9304
9310
  var notDetached = __webpack_require__2(5169);
9305
9311
  var numberToString = uncurryThis(1.1.toString);
9306
- var join9 = uncurryThis([].join);
9312
+ var join10 = uncurryThis([].join);
9307
9313
  var $Array = Array;
9308
9314
  var Uint8Array2 = globalThis2.Uint8Array;
9309
9315
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
@@ -9323,7 +9329,7 @@ var init_pdf2 = __esm({
9323
9329
  var hex = numberToString(this[i], 16);
9324
9330
  result[i] = hex.length === 1 ? "0" + hex : hex;
9325
9331
  }
9326
- return join9(result, "");
9332
+ return join10(result, "");
9327
9333
  }
9328
9334
  });
9329
9335
  },
@@ -12515,8 +12521,8 @@ var init_pdf2 = __esm({
12515
12521
  editor.show(visible);
12516
12522
  }
12517
12523
  }
12518
- const state2 = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
12519
- if (state2 !== visible) {
12524
+ const state3 = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
12525
+ if (state3 !== visible) {
12520
12526
  this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL, visible]]);
12521
12527
  }
12522
12528
  }
@@ -22362,28 +22368,28 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22362
22368
  const operator = array[0];
22363
22369
  for (let i = 1; i < length; i++) {
22364
22370
  const element = array[i];
22365
- let state2;
22371
+ let state3;
22366
22372
  if (Array.isArray(element)) {
22367
- state2 = this.#evaluateVisibilityExpression(element);
22373
+ state3 = this.#evaluateVisibilityExpression(element);
22368
22374
  } else if (this.#groups.has(element)) {
22369
- state2 = this.#groups.get(element).visible;
22375
+ state3 = this.#groups.get(element).visible;
22370
22376
  } else {
22371
22377
  warn2(`Optional content group not found: ${element}`);
22372
22378
  return true;
22373
22379
  }
22374
22380
  switch (operator) {
22375
22381
  case "And":
22376
- if (!state2) {
22382
+ if (!state3) {
22377
22383
  return false;
22378
22384
  }
22379
22385
  break;
22380
22386
  case "Or":
22381
- if (state2) {
22387
+ if (state3) {
22382
22388
  return true;
22383
22389
  }
22384
22390
  break;
22385
22391
  case "Not":
22386
- return !state2;
22392
+ return !state3;
22387
22393
  default:
22388
22394
  return true;
22389
22395
  }
@@ -22478,11 +22484,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22478
22484
  this.#cachedGetHash = null;
22479
22485
  }
22480
22486
  setOCGState({
22481
- state: state2,
22487
+ state: state3,
22482
22488
  preserveRB
22483
22489
  }) {
22484
22490
  let operator;
22485
- for (const elem of state2) {
22491
+ for (const elem of state3) {
22486
22492
  switch (elem) {
22487
22493
  case "ON":
22488
22494
  case "OFF":
@@ -35902,6 +35908,152 @@ var init_ai = __esm({
35902
35908
  }
35903
35909
  });
35904
35910
 
35911
+ // src/node/profile.js
35912
+ var profile_exports = {};
35913
+ __export(profile_exports, {
35914
+ distillMaterial: () => distillMaterial,
35915
+ profileMarkdown: () => profileMarkdown,
35916
+ recordCite: () => recordCite,
35917
+ recordMethod: () => recordMethod,
35918
+ recordNote: () => recordNote,
35919
+ recordQuery: () => recordQuery,
35920
+ recordTopic: () => recordTopic,
35921
+ saveProfileMarkdown: () => saveProfileMarkdown,
35922
+ setSelfDeclared: () => setSelfDeclared
35923
+ });
35924
+ import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "node:fs/promises";
35925
+ import { join as join7, dirname as dirname4 } from "node:path";
35926
+ async function load2() {
35927
+ if (state2) return state2;
35928
+ try {
35929
+ state2 = { ...structuredClone(EMPTY2), ...JSON.parse(await readFile6(PROFILE_PATH, "utf8")) };
35930
+ } catch {
35931
+ state2 = structuredClone(EMPTY2);
35932
+ }
35933
+ return state2;
35934
+ }
35935
+ async function persist2() {
35936
+ await mkdir5(dirname4(PROFILE_PATH), { recursive: true });
35937
+ await writeFile5(PROFILE_PATH, JSON.stringify(state2, null, 2), "utf8");
35938
+ }
35939
+ function schedulePersist() {
35940
+ if (saveTimer) return;
35941
+ saveTimer = setTimeout(() => {
35942
+ saveTimer = null;
35943
+ persist2().catch(() => {
35944
+ });
35945
+ }, 800);
35946
+ saveTimer.unref?.();
35947
+ }
35948
+ function bump(map, key, by = 1) {
35949
+ if (!key) return;
35950
+ map[key] = (map[key] ?? 0) + by;
35951
+ }
35952
+ async function recordCite(style) {
35953
+ const s = await load2();
35954
+ bump(s.citationStyles, String(style ?? "apa").toLowerCase());
35955
+ s.updatedAt = Date.now();
35956
+ schedulePersist();
35957
+ }
35958
+ async function recordQuery(query) {
35959
+ const s = await load2();
35960
+ s.queries.unshift({ q: String(query ?? "").slice(0, 120), at: Date.now() });
35961
+ if (s.queries.length > 100) s.queries.length = 100;
35962
+ s.updatedAt = Date.now();
35963
+ schedulePersist();
35964
+ }
35965
+ async function recordNote(key, note) {
35966
+ const s = await load2();
35967
+ const text = String(note ?? "");
35968
+ s.pragmatics.noteCount += 1;
35969
+ s.pragmatics.avgNoteLen = Math.round((s.pragmatics.avgNoteLen * (s.pragmatics.noteCount - 1) + text.length) / s.pragmatics.noteCount);
35970
+ s.pragmatics.language = hasCjk(text) ? /[a-zA-Z]{4,}/.test(text) ? "zh-en-mixed" : "zh" : "en";
35971
+ schedulePersist();
35972
+ }
35973
+ async function recordTopic(topic, itemKey) {
35974
+ const s = await load2();
35975
+ const t = String(topic ?? "").trim().slice(0, 60);
35976
+ if (!t) return;
35977
+ const entry = s.topics[t] = s.topics[t] ?? { weight: 0, evidence: [] };
35978
+ entry.weight += 1;
35979
+ if (itemKey && !entry.evidence.includes(itemKey)) entry.evidence.unshift(itemKey);
35980
+ if (entry.evidence.length > 10) entry.evidence.length = 10;
35981
+ s.updatedAt = Date.now();
35982
+ schedulePersist();
35983
+ }
35984
+ async function recordMethod(kind) {
35985
+ const s = await load2();
35986
+ bump(s.methods, String(kind ?? "").toLowerCase());
35987
+ schedulePersist();
35988
+ }
35989
+ async function setSelfDeclared(text) {
35990
+ const s = await load2();
35991
+ s.selfDeclared = String(text ?? "").slice(0, 2e3);
35992
+ s.updatedAt = Date.now();
35993
+ await persist2();
35994
+ }
35995
+ async function distillMaterial() {
35996
+ const s = await load2();
35997
+ const top = Object.entries(s.topics).sort((a, b) => b[1].weight - a[1].weight).slice(0, 12).map(([topic, v]) => `${topic}\uFF08${v.weight} \u6B21 \xB7 \u8BC1\u636E\uFF1A${v.evidence.slice(0, 3).join(", ") || "\u2014"}\uFF09`);
35998
+ const methods = Object.entries(s.methods).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`);
35999
+ const styles = Object.entries(s.citationStyles).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`);
36000
+ const queries = s.queries.slice(0, 20).map((q) => `- ${q.q}`);
36001
+ return [
36002
+ `\u3010\u753B\u50CF\u84B8\u998F\u7D20\u6750\u3011\uFF08\u622A\u81F3 ${new Date(s.updatedAt ?? Date.now()).toISOString().slice(0, 10)}\uFF09`,
36003
+ top.length ? `\u7814\u7A76\u4E3B\u9898\uFF08\u6309\u51FA\u73B0\u9891\u6B21\uFF09\uFF1A
36004
+ ${top.map((t) => "- " + t).join("\n")}` : "\u7814\u7A76\u4E3B\u9898\uFF1A\u6682\u65E0\u8DB3\u591F\u6570\u636E",
36005
+ methods.length ? `\u65B9\u6CD5\u8BBA\u503E\u5411\uFF1A${methods.join(", ")}` : "\u65B9\u6CD5\u8BBA\u503E\u5411\uFF1A\u6682\u65E0\u6570\u636E",
36006
+ styles.length ? `\u5F15\u7528\u683C\u5F0F\u4F7F\u7528\uFF1A${styles.join(", ")}` : "\u5F15\u7528\u683C\u5F0F\u4F7F\u7528\uFF1A\u6682\u65E0\u6570\u636E",
36007
+ `\u8BED\u7528\u89C2\u5BDF\uFF1A\u8BED\u8A00=${s.pragmatics.language || "\u672A\u77E5"}\uFF0C\u7B14\u8BB0\u5747\u957F=${s.pragmatics.avgNoteLen} \u5B57\uFF0C\u7B14\u8BB0\u6570=${s.pragmatics.noteCount}`,
36008
+ queries.length ? `\u8FD1\u671F\u68C0\u7D22\uFF08\u53CD\u6620\u771F\u5B9E\u5173\u6CE8\u70B9\uFF09\uFF1A
36009
+ ${queries.join("\n")}` : "\u8FD1\u671F\u68C0\u7D22\uFF1A\u6682\u65E0",
36010
+ s.selfDeclared ? `\u7528\u6237\u81EA\u8FF0\uFF1A${s.selfDeclared}` : ""
36011
+ ].filter(Boolean).join("\n\n");
36012
+ }
36013
+ async function profileMarkdown() {
36014
+ try {
36015
+ return await readFile6(PROFILE_MD_PATH, "utf8");
36016
+ } catch {
36017
+ return "";
36018
+ }
36019
+ }
36020
+ async function saveProfileMarkdown(md) {
36021
+ await mkdir5(dirname4(PROFILE_MD_PATH), { recursive: true });
36022
+ await writeFile5(PROFILE_MD_PATH, String(md ?? "").slice(0, 8e3), "utf8");
36023
+ }
36024
+ function hasCjk(s) {
36025
+ return /[\u4e00-\u9fff]/.test(String(s ?? ""));
36026
+ }
36027
+ var PROFILE_PATH, PROFILE_MD_PATH, EMPTY2, state2, saveTimer;
36028
+ var init_profile = __esm({
36029
+ "src/node/profile.js"() {
36030
+ init_config();
36031
+ PROFILE_PATH = join7(STORE_DIR, "scholar-profile.json");
36032
+ PROFILE_MD_PATH = join7(STORE_DIR, "scholar-profile.md");
36033
+ EMPTY2 = {
36034
+ version: 1,
36035
+ updatedAt: 0,
36036
+ // topic -> { weight, evidence: [itemKey] } — raised by deepread cards,
36037
+ // saves, notes. Weight is a simple counter; ranking normalises it.
36038
+ topics: {},
36039
+ // methodology affinity: experiment / theory / engineering / review
36040
+ methods: {},
36041
+ // citation format usage counters: apa / gb / mla / chicago / bibtex
36042
+ citationStyles: {},
36043
+ // search query log (capped): what the user asks for, verbatim
36044
+ queries: [],
36045
+ // canonical term -> accepted variants (from notes/deepread language)
36046
+ terminology: {},
36047
+ // pragmatics observed from query & note text
36048
+ pragmatics: { language: "", avgNoteLen: 0, noteCount: 0 },
36049
+ // free-form notes the user explicitly adds about themselves
36050
+ selfDeclared: ""
36051
+ };
36052
+ state2 = null;
36053
+ saveTimer = null;
36054
+ }
36055
+ });
36056
+
35905
36057
  // src/node/courseware/reading-modes.js
35906
36058
  var reading_modes_exports = {};
35907
36059
  __export(reading_modes_exports, {
@@ -36021,12 +36173,12 @@ __export(doctor_selfheal_exports, {
36021
36173
  });
36022
36174
  import { createHash } from "node:crypto";
36023
36175
  import { existsSync as existsSync2, readdirSync as readdirSync2 } from "node:fs";
36024
- import { join as join8 } from "node:path";
36176
+ import { join as join9 } from "node:path";
36025
36177
  import { homedir as homedir4 } from "node:os";
36026
36178
  import { spawn } from "node:child_process";
36027
36179
  import net from "node:net";
36028
36180
  function doctorRoot() {
36029
- return process.env.DSH_DOCTOR_HOME?.trim() || join8(homedir4(), ".dsh-doctor");
36181
+ return process.env.DSH_DOCTOR_HOME?.trim() || join9(homedir4(), ".dsh-doctor");
36030
36182
  }
36031
36183
  function doctorPipeName(root = doctorRoot()) {
36032
36184
  const hash = createHash("sha256").update(root).digest("hex").slice(0, 16);
@@ -36051,7 +36203,7 @@ function pipeAvailable(pipe, timeoutMs = 1500) {
36051
36203
  });
36052
36204
  }
36053
36205
  function findDoctorCli() {
36054
- const profilesDir = join8(homedir4(), ".dsh", "profiles");
36206
+ const profilesDir = join9(homedir4(), ".dsh", "profiles");
36055
36207
  let entries = [];
36056
36208
  try {
36057
36209
  entries = readdirSync2(profilesDir);
@@ -36059,7 +36211,7 @@ function findDoctorCli() {
36059
36211
  return "";
36060
36212
  }
36061
36213
  for (const name2 of entries) {
36062
- const candidate = join8(profilesDir, name2, "node_modules", "@linxin666", "dsh-doctor", "lib", "cli.mjs");
36214
+ const candidate = join9(profilesDir, name2, "node_modules", "@linxin666", "dsh-doctor", "lib", "cli.mjs");
36063
36215
  if (existsSync2(candidate)) return candidate;
36064
36216
  }
36065
36217
  return "";
@@ -36641,9 +36793,10 @@ function snippetFor(item, terms) {
36641
36793
  // src/node/tools.js
36642
36794
  init_normalize();
36643
36795
  init_log();
36644
- import { writeFile as writeFile5, mkdtemp, readFile as readFile6, rm } from "node:fs/promises";
36796
+ init_profile();
36797
+ import { writeFile as writeFile6, mkdtemp, readFile as readFile7, rm } from "node:fs/promises";
36645
36798
  import { tmpdir } from "node:os";
36646
- import { join as join7 } from "node:path";
36799
+ import { join as join8 } from "node:path";
36647
36800
  function textResult(value) {
36648
36801
  return {
36649
36802
  schema: { type: "string" },
@@ -36651,7 +36804,7 @@ function textResult(value) {
36651
36804
  };
36652
36805
  }
36653
36806
  function toolDefs() {
36654
- return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool(), deepreadTool()];
36807
+ return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool(), deepreadTool(), profileTool()];
36655
36808
  }
36656
36809
  function registerTools(ctx2) {
36657
36810
  let mounted = [];
@@ -36743,6 +36896,8 @@ function searchTool() {
36743
36896
  async execute(args) {
36744
36897
  const query = String(args?.query ?? "").trim();
36745
36898
  if (!query) return "\u7F3A\u5C11\u68C0\u7D22\u8BCD\u3002";
36899
+ recordQuery(query).catch(() => {
36900
+ });
36746
36901
  const limit = Math.max(1, Math.min(Number(args?.limit) || 8, 20));
36747
36902
  const items = await listItems();
36748
36903
  const hits = searchItems2(items, query, { limit });
@@ -36815,6 +36970,8 @@ function citeTool() {
36815
36970
  const item = await getItem(key);
36816
36971
  if (!item?.record) return `\u6761\u76EE ${key} \u7F3A\u5C11\u5143\u6570\u636E\uFF0C\u65E0\u6CD5\u751F\u6210\u5F15\u7528\u3002\u8BF7\u5148\u7528 literature_lookup \u89E3\u6790\u5143\u6570\u636E\u3002`;
36817
36972
  const { citeDetailed: citeDetailed2 } = await Promise.resolve().then(() => (init_cite(), cite_exports));
36973
+ recordCite(args?.style ?? "apa").catch(() => {
36974
+ });
36818
36975
  const d = citeDetailed2(item.record, {
36819
36976
  style: args?.style ?? "apa",
36820
36977
  mode: args?.mode ?? "reference",
@@ -36851,6 +37008,8 @@ function noteTool() {
36851
37008
  if (notes.some((n) => (typeof n === "string" ? n : n.text) === note)) return "\u8BE5\u7B14\u8BB0\u5DF2\u5B58\u5728\uFF0C\u672A\u91CD\u590D\u5199\u5165\u3002";
36852
37009
  const entry = { text: note, at: (/* @__PURE__ */ new Date()).toISOString() };
36853
37010
  await patchItem(key, { notes: [...notes, entry] });
37011
+ recordNote(key, note).catch(() => {
37012
+ });
36854
37013
  return `\u5DF2\u8BB0\u5F55\u5230\u6761\u76EE ${key}\uFF08\u5171 ${notes.length + 1} \u6761\u7B14\u8BB0\uFF09\u3002`;
36855
37014
  }
36856
37015
  };
@@ -36922,10 +37081,10 @@ function figureTool() {
36922
37081
  if (!fig || !fig.hasMatplotlib) {
36923
37082
  return "\u793A\u610F\u56FE\u5F15\u64CE\u5C1A\u672A\u5C31\u7EEA\uFF1A\u672C\u673A\u7F3A\u5C11 Python + matplotlib\u3002\u8BF7\u5728\u4FA7\u7A97\u8BBE\u7F6E\u9875\u300C\u793A\u610F\u56FE\u5F15\u64CE\u300D\u4E2D\u70B9\u51FB\u300C\u5B89\u88C5\u4F9D\u8D56\u300D\u540E\u91CD\u8BD5\uFF1B\u671F\u95F4\u53EF\u4EE5\u8BA9\u6211\u8F93\u51FA\u6570\u636E\u8868\u683C\u4EE3\u66FF\u56FE\u8868\u3002";
36924
37083
  }
36925
- const { mkdtemp: _mk, writeFile: _w, readFile: _r, rm: _rm } = { mkdtemp, writeFile: writeFile5, readFile: readFile6, rm };
36926
- const dir = await mkdtemp(join7(tmpdir(), "lit-fig-"));
36927
- const pyFile = join7(dir, "fig.py");
36928
- const pngFile = join7(dir, "fig.png");
37084
+ const { mkdtemp: _mk, writeFile: _w, readFile: _r, rm: _rm } = { mkdtemp, writeFile: writeFile6, readFile: readFile7, rm };
37085
+ const dir = await mkdtemp(join8(tmpdir(), "lit-fig-"));
37086
+ const pyFile = join8(dir, "fig.py");
37087
+ const pngFile = join8(dir, "fig.png");
36929
37088
  const script = [
36930
37089
  "import matplotlib",
36931
37090
  "matplotlib.use('Agg')",
@@ -36962,13 +37121,13 @@ function figureTool() {
36962
37121
  "plt.tight_layout()",
36963
37122
  `plt.savefig(${JSON.stringify(pngFile)})`
36964
37123
  ].join("\n");
36965
- await writeFile5(pyFile, script, "utf8");
37124
+ await writeFile6(pyFile, script, "utf8");
36966
37125
  const { execFile: execFile2 } = await import("node:child_process");
36967
37126
  const run2 = () => new Promise((resolve6) => execFile2(fig.exe, [pyFile], { timeout: 6e4, windowsHide: true }, (err, stdout, stderr) => resolve6({ err, stdout, stderr })));
36968
37127
  const r = await run2();
36969
37128
  let png = null;
36970
37129
  try {
36971
- png = await readFile6(pngFile);
37130
+ png = await readFile7(pngFile);
36972
37131
  } catch {
36973
37132
  }
36974
37133
  await rm(dir, { recursive: true, force: true }).catch(() => {
@@ -37021,6 +37180,8 @@ function deepreadTool() {
37021
37180
  for (const m of text.matchAll(/(?:Fig(?:ure)?|表|Table)\s*\d+[.::][^\n]{5,90}/g)) {
37022
37181
  if (figures.length < 12) figures.push(m[0].trim());
37023
37182
  }
37183
+ recordTopic(title, key).catch(() => {
37184
+ });
37024
37185
  const { buildReadPackage: buildReadPackage2 } = await Promise.resolve().then(() => (init_reading_modes(), reading_modes_exports));
37025
37186
  const pack = buildReadPackage2(mode, { title, text, figures });
37026
37187
  return pack + `
@@ -37029,6 +37190,56 @@ function deepreadTool() {
37029
37190
  }
37030
37191
  };
37031
37192
  }
37193
+ function profileTool() {
37194
+ return {
37195
+ name: "literature_profile",
37196
+ description: "\u5B66\u8005\u753B\u50CF\uFF1A\u67E5\u770B/\u84B8\u998F/\u4FDD\u5B58\u6839\u636E\u7528\u6237\u6587\u732E\u884C\u4E3A\u63A8\u65AD\u7684\u5B66\u672F\u80CC\u666F\u3001\u8BED\u7528\u4E60\u60EF\u4E0E\u504F\u597D\u3002\u7528\u6237\u95EE\u300C\u6211\u7684\u7814\u7A76\u753B\u50CF/\u6211\u5728\u5173\u6CE8\u4EC0\u4E48/\u6839\u636E\u6211\u7684\u4E60\u60EF\u6765\u300D\u65F6\u8C03\u7528\uFF1B\u84B8\u998F\u540E\u628A\u753B\u50CF\u5199\u56DE\uFF08action=save\uFF09\uFF0C\u5E76\u53EF\u5EFA\u8BAE\u7528\u6237\u540C\u6B65\u5230 auto-memory\u3002",
37197
+ parameters: {
37198
+ type: "object",
37199
+ properties: {
37200
+ action: { type: "string", description: "view\uFF08\u9ED8\u8BA4\uFF0C\u770B\u5F53\u524D\u753B\u50CF\uFF09| distill\uFF08\u53D6\u7D20\u6750\u5E76\u84B8\u998F\uFF09| save\uFF08\u4FDD\u5B58\u84B8\u998F\u7ED3\u679C\uFF09| self\uFF08\u767B\u8BB0\u7528\u6237\u81EA\u8FF0\uFF09" },
37201
+ content: { type: "string", description: "action=save \u65F6\u7684\u753B\u50CF Markdown\uFF1Baction=self \u65F6\u7684\u7528\u6237\u81EA\u8FF0" }
37202
+ },
37203
+ required: []
37204
+ },
37205
+ output: textResult(),
37206
+ timeoutMs: 15e3,
37207
+ async execute(args) {
37208
+ const { distillMaterial: distillMaterial2, profileMarkdown: profileMarkdown2, saveProfileMarkdown: saveProfileMarkdown2, setSelfDeclared: setSelfDeclared2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
37209
+ const action = String(args?.action ?? "view");
37210
+ if (action === "save") {
37211
+ const md = String(args?.content ?? "").trim();
37212
+ if (!md) return "\u7F3A\u5C11\u753B\u50CF\u5185\u5BB9\uFF08content\uFF09\u3002";
37213
+ await saveProfileMarkdown2(md);
37214
+ return "\u5B66\u8005\u753B\u50CF\u5DF2\u4FDD\u5B58\u3002\n[\u4E0B\u4E00\u6B65] \u7528\u6237\u5982\u9700\u8DE8\u4F1A\u8BDD\u751F\u6548\uFF0C\u5EFA\u8BAE\u628A\u753B\u50CF\u540C\u6B65\u5230 auto-memory \u7684\u7528\u6237\u7EA7\u8BB0\u5FC6\uFF08memory_user_pre\uFF09\uFF0C\u6216\u7531\u7528\u6237\u5728\u8BB0\u5FC6\u9762\u677F\u786E\u8BA4\u3002";
37215
+ }
37216
+ if (action === "self") {
37217
+ await setSelfDeclared2(args?.content);
37218
+ return "\u5DF2\u767B\u8BB0\u7528\u6237\u81EA\u8FF0\uFF0C\u4E0B\u6B21\u84B8\u998F\u4F1A\u7EB3\u5165\u3002";
37219
+ }
37220
+ if (action === "distill") {
37221
+ const material = await distillMaterial2();
37222
+ const existing = await profileMarkdown2();
37223
+ return [
37224
+ material,
37225
+ "",
37226
+ existing ? "\u3010\u73B0\u6709\u753B\u50CF\u3011\n" + existing : "",
37227
+ "",
37228
+ "\u4EFB\u52A1\uFF1A\u4F9D\u636E\u7D20\u6750\u5199\u4E00\u4EFD\u300C\u5B66\u8005\u753B\u50CF\u300D\uFF08Markdown\uFF0C\u2264600 \u5B57\uFF09\uFF0C\u7ED3\u6784\u56FA\u5B9A\u4E3A\uFF1A",
37229
+ "## \u7814\u7A76\u9886\u57DF\uFF08\u6309\u719F\u6089\u5EA6\u6392\u5E8F\uFF09",
37230
+ "## \u65B9\u6CD5\u8BBA\u504F\u597D\uFF08\u5B9E\u9A8C/\u7406\u8BBA/\u5DE5\u7A0B\uFF09",
37231
+ "## \u672F\u8BED\u4E0E\u8868\u8FBE\u4E60\u60EF\uFF08\u7528\u6237\u5982\u4F55\u79F0\u547C\u6982\u5FF5\u3001\u4E2D\u82F1\u6DF7\u7528\u60C5\u51B5\uFF09",
37232
+ "## \u5F15\u7528\u4E60\u60EF\uFF08\u5E38\u7528\u683C\u5F0F\u3001\u8BED\u6C14\uFF09",
37233
+ "## \u5F53\u524D\u5173\u6CE8\u4E0E\u76EE\u6807",
37234
+ "\u53EA\u4F9D\u636E\u7D20\u6750\uFF0C\u4E0D\u63A8\u65AD\u7D20\u6750\u4E4B\u5916\u7684\u5185\u5BB9\uFF1B\u8BC1\u636E\u4E0D\u8DB3\u7684\u7EF4\u5EA6\u5199\u300C\u6682\u65E0\u8DB3\u591F\u6570\u636E\u300D\u3002",
37235
+ "\u5199\u5B8C\u540E\u8C03\u7528 literature_profile(action=save, content=\u753B\u50CF) \u4FDD\u5B58\u3002"
37236
+ ].join("\n");
37237
+ }
37238
+ const current = await profileMarkdown2();
37239
+ return current ? "\u3010\u5F53\u524D\u5B66\u8005\u753B\u50CF\u3011\n" + current : "\u5C1A\u65E0\u753B\u50CF\u3002\u8C03\u7528 literature_profile(action=distill) \u4F9D\u636E\u884C\u4E3A\u7D20\u6750\u84B8\u998F\u4E00\u4EFD\u3002";
37240
+ }
37241
+ };
37242
+ }
37032
37243
  function saveTool() {
37033
37244
  return {
37034
37245
  name: "literature_save",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a9i5k4/dsh-literature",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "DSH Literature 文献侧窗:在 DeepSeek Harness 侧边栏识别 DOI/arXiv/标题、抓取元数据与全文、写入本地文献库或导出目录,并提供内置 PDF 阅读器(缩放/翻页/目录/搜索/高亮/笔记)。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",