@a9i5k4/dsh-literature 0.3.0 → 0.3.2

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 +469 -83
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -2857,8 +2857,8 @@ async function startTask(key, kind) {
2857
2857
  emitTask(task);
2858
2858
  return task;
2859
2859
  }
2860
- async function finishTask(task, state2, message) {
2861
- const next = await putTask({ id: task.id, state: state2, progress: 100, message });
2860
+ async function finishTask(task, state3, message) {
2861
+ const next = await putTask({ id: task.id, state: state3, progress: 100, message });
2862
2862
  emitTask(next);
2863
2863
  return next;
2864
2864
  }
@@ -3111,8 +3111,8 @@ async function saveItem(key, { mode, tags } = {}) {
3111
3111
  if (wantMode === "dir") {
3112
3112
  let buffer = null;
3113
3113
  if (current.pdf?.path) {
3114
- const { readFile: readFile7 } = await import("node:fs/promises");
3115
- buffer = await readFile7(current.pdf.path).catch(() => null);
3114
+ const { readFile: readFile8 } = await import("node:fs/promises");
3115
+ buffer = await readFile8(current.pdf.path).catch(() => null);
3116
3116
  }
3117
3117
  result = await exportToDirectory(current.record, buffer);
3118
3118
  const updated2 = await patchItem(key, { state: "saved", saveMode: "dir", export: result, error: null, updatedAt: Date.now() });
@@ -3122,14 +3122,14 @@ async function saveItem(key, { mode, tags } = {}) {
3122
3122
  }
3123
3123
  let pdfBuffer = null;
3124
3124
  if (current.pdf?.path) {
3125
- const { readFile: readFile7 } = await import("node:fs/promises");
3126
- pdfBuffer = await readFile7(current.pdf.path).catch(() => null);
3125
+ const { readFile: readFile8 } = await import("node:fs/promises");
3126
+ pdfBuffer = await readFile8(current.pdf.path).catch(() => null);
3127
3127
  }
3128
3128
  if (!pdfBuffer) {
3129
3129
  const fetched = await fetchItemPdf(key);
3130
3130
  if (fetched?.pdf?.path) {
3131
- const { readFile: readFile7 } = await import("node:fs/promises");
3132
- pdfBuffer = await readFile7(fetched.pdf.path).catch(() => null);
3131
+ const { readFile: readFile8 } = await import("node:fs/promises");
3132
+ pdfBuffer = await readFile8(fetched.pdf.path).catch(() => null);
3133
3133
  } else {
3134
3134
  const err = fetched?.error ?? failure("fetch_failed", "\u65E0\u6CD5\u83B7\u53D6\u5168\u6587 PDF\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u5230\u6587\u732E\u5E93");
3135
3135
  throw Object.assign(new Error(err.message), { code: err.code ?? "fetch_failed", detail: err.detail });
@@ -5396,8 +5396,8 @@ var init_pdf2 = __esm({
5396
5396
  var getTypedArrayConstructor = function(it) {
5397
5397
  var proto = getPrototypeOf(it);
5398
5398
  if (!isObject(proto)) return;
5399
- var state2 = getInternalState(proto);
5400
- return state2 && hasOwn(state2, TYPED_ARRAY_CONSTRUCTOR) ? state2[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto);
5399
+ var state3 = getInternalState(proto);
5400
+ return state3 && hasOwn(state3, TYPED_ARRAY_CONSTRUCTOR) ? state3[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto);
5401
5401
  };
5402
5402
  var isTypedArray = function(it) {
5403
5403
  if (!isObject(it)) return false;
@@ -6234,11 +6234,11 @@ var init_pdf2 = __esm({
6234
6234
  };
6235
6235
  var getterFor = function(TYPE) {
6236
6236
  return function(it) {
6237
- var state2;
6238
- if (!isObject(it) || (state2 = get(it)).type !== TYPE) {
6237
+ var state3;
6238
+ if (!isObject(it) || (state3 = get(it)).type !== TYPE) {
6239
6239
  throw new TypeError2("Incompatible receiver, " + TYPE + " required");
6240
6240
  }
6241
- return state2;
6241
+ return state3;
6242
6242
  };
6243
6243
  };
6244
6244
  if (NATIVE_WEAK_MAP || shared.state) {
@@ -6363,8 +6363,8 @@ var init_pdf2 = __esm({
6363
6363
  var getInternalState = __webpack_require__2(1181).get;
6364
6364
  module.exports = function isRawJSON(O) {
6365
6365
  if (!isObject(O)) return false;
6366
- var state2 = getInternalState(O);
6367
- return !!state2 && state2.type === "RawJSON";
6366
+ var state3 = getInternalState(O);
6367
+ return !!state3 && state3.type === "RawJSON";
6368
6368
  };
6369
6369
  },
6370
6370
  /***/
@@ -6465,8 +6465,8 @@ var init_pdf2 = __esm({
6465
6465
  },
6466
6466
  /***/
6467
6467
  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;
6468
+ module.exports = function(state3) {
6469
+ 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
6470
  };
6471
6471
  },
6472
6472
  /***/
@@ -6535,31 +6535,31 @@ var init_pdf2 = __esm({
6535
6535
  var getInternalState = InternalStateModule.getterFor(IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER);
6536
6536
  return defineBuiltIns(create(IteratorPrototype), {
6537
6537
  next: function next() {
6538
- var state2 = getInternalState(this);
6539
- if (IS_ITERATOR) return state2.nextHandler();
6540
- if (state2.done) return createIterResultObject(void 0, true);
6538
+ var state3 = getInternalState(this);
6539
+ if (IS_ITERATOR) return state3.nextHandler();
6540
+ if (state3.done) return createIterResultObject(void 0, true);
6541
6541
  try {
6542
- var result = state2.nextHandler();
6543
- if (state2.done) cleanupState(state2);
6544
- return state2.returnHandlerResult ? result : createIterResultObject(result, state2.done);
6542
+ var result = state3.nextHandler();
6543
+ if (state3.done) cleanupState(state3);
6544
+ return state3.returnHandlerResult ? result : createIterResultObject(result, state3.done);
6545
6545
  } catch (error2) {
6546
- state2.done = true;
6547
- cleanupState(state2);
6546
+ state3.done = true;
6547
+ cleanupState(state3);
6548
6548
  throw error2;
6549
6549
  }
6550
6550
  },
6551
6551
  "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;
6552
+ var state3 = getInternalState(this);
6553
+ var iterator = state3.iterator;
6554
+ var inner = state3.inner;
6555
+ var openIters = state3.openIters;
6556
+ var done = state3.done;
6557
+ state3.done = true;
6558
6558
  if (IS_ITERATOR) {
6559
6559
  var returnMethod = getMethod(iterator, "return");
6560
6560
  return returnMethod ? call2(returnMethod, iterator) : createIterResultObject(void 0, true);
6561
6561
  }
6562
- cleanupState(state2);
6562
+ cleanupState(state3);
6563
6563
  if (done) return createIterResultObject(void 0, true);
6564
6564
  if (inner) try {
6565
6565
  iteratorClose(inner.iterator, NORMAL);
@@ -6581,17 +6581,17 @@ var init_pdf2 = __esm({
6581
6581
  var IteratorHelperPrototype = createIteratorProxyPrototype(false);
6582
6582
  createNonEnumerableProperty(IteratorHelperPrototype, TO_STRING_TAG, "Iterator Helper");
6583
6583
  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);
6584
+ var IteratorProxy = function Iterator2(record, state3) {
6585
+ if (state3) {
6586
+ state3.iterator = record.iterator;
6587
+ state3.next = record.next;
6588
+ } else state3 = record;
6589
+ state3.type = IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER;
6590
+ state3.returnHandlerResult = !!RETURN_HANDLER_RESULT;
6591
+ state3.nextHandler = nextHandler;
6592
+ state3.counter = 0;
6593
+ state3.done = false;
6594
+ setInternalState(this, state3);
6595
6595
  };
6596
6596
  IteratorProxy.prototype = IS_ITERATOR ? WrapForValidIteratorPrototype : IteratorHelperPrototype;
6597
6597
  return IteratorProxy;
@@ -6695,7 +6695,7 @@ var init_pdf2 = __esm({
6695
6695
  var defineProperty = Object.defineProperty;
6696
6696
  var stringSlice = uncurryThis("".slice);
6697
6697
  var replace = uncurryThis("".replace);
6698
- var join9 = uncurryThis([].join);
6698
+ var join10 = uncurryThis([].join);
6699
6699
  var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
6700
6700
  return defineProperty(function() {
6701
6701
  }, "length", { value: 8 }).length !== 8;
@@ -6720,9 +6720,9 @@ var init_pdf2 = __esm({
6720
6720
  } else if (value.prototype) value.prototype = void 0;
6721
6721
  } catch (error2) {
6722
6722
  }
6723
- var state2 = enforceInternalState(value);
6724
- if (!hasOwn(state2, "source")) {
6725
- state2.source = join9(TEMPLATE, typeof name2 == "string" ? name2 : "");
6723
+ var state3 = enforceInternalState(value);
6724
+ if (!hasOwn(state3, "source")) {
6725
+ state3.source = join10(TEMPLATE, typeof name2 == "string" ? name2 : "");
6726
6726
  }
6727
6727
  return value;
6728
6728
  };
@@ -8864,21 +8864,21 @@ var init_pdf2 = __esm({
8864
8864
  sumPrecise: function sumPrecise(items) {
8865
8865
  var numbers = [];
8866
8866
  var count = 0;
8867
- var state2 = MINUS_ZERO;
8867
+ var state3 = MINUS_ZERO;
8868
8868
  iterate(items, function(n2) {
8869
8869
  if (++count > MAX_SAFE_INTEGER) throw new $RangeError("Maximum allowed index exceeded");
8870
8870
  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;
8871
+ if (state3 !== NOT_A_NUMBER) {
8872
+ if (n2 !== n2) state3 = NOT_A_NUMBER;
8873
+ else if (n2 === $Infinity) state3 = state3 === MINUS_INFINITY ? NOT_A_NUMBER : PLUS_INFINITY;
8874
+ else if (n2 === -$Infinity) state3 = state3 === PLUS_INFINITY ? NOT_A_NUMBER : MINUS_INFINITY;
8875
+ else if ((n2 !== 0 || 1 / n2 === $Infinity) && (state3 === MINUS_ZERO || state3 === FINITE)) {
8876
+ state3 = FINITE;
8877
8877
  push2(numbers, n2);
8878
8878
  }
8879
8879
  }
8880
8880
  });
8881
- switch (state2) {
8881
+ switch (state3) {
8882
8882
  case NOT_A_NUMBER:
8883
8883
  return $NaN;
8884
8884
  case MINUS_INFINITY:
@@ -9245,7 +9245,7 @@ var init_pdf2 = __esm({
9245
9245
  var charAt = uncurryThis("".charAt);
9246
9246
  var Uint8Array2 = globalThis2.Uint8Array;
9247
9247
  var $Array = globalThis2.Array;
9248
- var join9 = uncurryThis([].join);
9248
+ var join10 = uncurryThis([].join);
9249
9249
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
9250
9250
  try {
9251
9251
  var target = new Uint8Array2();
@@ -9291,7 +9291,7 @@ var init_pdf2 = __esm({
9291
9291
  result[written++] = "=";
9292
9292
  }
9293
9293
  }
9294
- return join9(result, "");
9294
+ return join10(result, "");
9295
9295
  }
9296
9296
  });
9297
9297
  },
@@ -9303,7 +9303,7 @@ var init_pdf2 = __esm({
9303
9303
  var anUint8Array = __webpack_require__2(4154);
9304
9304
  var notDetached = __webpack_require__2(5169);
9305
9305
  var numberToString = uncurryThis(1.1.toString);
9306
- var join9 = uncurryThis([].join);
9306
+ var join10 = uncurryThis([].join);
9307
9307
  var $Array = Array;
9308
9308
  var Uint8Array2 = globalThis2.Uint8Array;
9309
9309
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
@@ -9323,7 +9323,7 @@ var init_pdf2 = __esm({
9323
9323
  var hex = numberToString(this[i], 16);
9324
9324
  result[i] = hex.length === 1 ? "0" + hex : hex;
9325
9325
  }
9326
- return join9(result, "");
9326
+ return join10(result, "");
9327
9327
  }
9328
9328
  });
9329
9329
  },
@@ -12515,8 +12515,8 @@ var init_pdf2 = __esm({
12515
12515
  editor.show(visible);
12516
12516
  }
12517
12517
  }
12518
- const state2 = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
12519
- if (state2 !== visible) {
12518
+ const state3 = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
12519
+ if (state3 !== visible) {
12520
12520
  this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL, visible]]);
12521
12521
  }
12522
12522
  }
@@ -22362,28 +22362,28 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22362
22362
  const operator = array[0];
22363
22363
  for (let i = 1; i < length; i++) {
22364
22364
  const element = array[i];
22365
- let state2;
22365
+ let state3;
22366
22366
  if (Array.isArray(element)) {
22367
- state2 = this.#evaluateVisibilityExpression(element);
22367
+ state3 = this.#evaluateVisibilityExpression(element);
22368
22368
  } else if (this.#groups.has(element)) {
22369
- state2 = this.#groups.get(element).visible;
22369
+ state3 = this.#groups.get(element).visible;
22370
22370
  } else {
22371
22371
  warn2(`Optional content group not found: ${element}`);
22372
22372
  return true;
22373
22373
  }
22374
22374
  switch (operator) {
22375
22375
  case "And":
22376
- if (!state2) {
22376
+ if (!state3) {
22377
22377
  return false;
22378
22378
  }
22379
22379
  break;
22380
22380
  case "Or":
22381
- if (state2) {
22381
+ if (state3) {
22382
22382
  return true;
22383
22383
  }
22384
22384
  break;
22385
22385
  case "Not":
22386
- return !state2;
22386
+ return !state3;
22387
22387
  default:
22388
22388
  return true;
22389
22389
  }
@@ -22478,11 +22478,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22478
22478
  this.#cachedGetHash = null;
22479
22479
  }
22480
22480
  setOCGState({
22481
- state: state2,
22481
+ state: state3,
22482
22482
  preserveRB
22483
22483
  }) {
22484
22484
  let operator;
22485
- for (const elem of state2) {
22485
+ for (const elem of state3) {
22486
22486
  switch (elem) {
22487
22487
  case "ON":
22488
22488
  case "OFF":
@@ -35708,6 +35708,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
35708
35708
  });
35709
35709
 
35710
35710
  // src/node/pdf-text.js
35711
+ var pdf_text_exports = {};
35712
+ __export(pdf_text_exports, {
35713
+ extractPdfText: () => extractPdfText,
35714
+ forgetPdfText: () => forgetPdfText
35715
+ });
35711
35716
  import { readFile as readFile4 } from "node:fs/promises";
35712
35717
  async function pdfjs() {
35713
35718
  if (!pdfjsPromise) pdfjsPromise = Promise.resolve().then(() => (init_pdf2(), pdf_exports)).catch((e) => {
@@ -35742,6 +35747,9 @@ async function extractPdfText(pdfPath, { maxChars = DEFAULT_MAX_CHARS, force = f
35742
35747
  cache2.set(pdfPath, { text, at: Date.now() });
35743
35748
  return text;
35744
35749
  }
35750
+ function forgetPdfText(pdfPath) {
35751
+ cache2.delete(pdfPath);
35752
+ }
35745
35753
  var DEFAULT_MAX_CHARS, CACHE_TTL_MS, cache2, pdfjsPromise;
35746
35754
  var init_pdf_text = __esm({
35747
35755
  "src/node/pdf-text.js"() {
@@ -35894,6 +35902,261 @@ var init_ai = __esm({
35894
35902
  }
35895
35903
  });
35896
35904
 
35905
+ // src/node/profile.js
35906
+ var profile_exports = {};
35907
+ __export(profile_exports, {
35908
+ distillMaterial: () => distillMaterial,
35909
+ profileMarkdown: () => profileMarkdown,
35910
+ recordCite: () => recordCite,
35911
+ recordMethod: () => recordMethod,
35912
+ recordNote: () => recordNote,
35913
+ recordQuery: () => recordQuery,
35914
+ recordTopic: () => recordTopic,
35915
+ saveProfileMarkdown: () => saveProfileMarkdown,
35916
+ setSelfDeclared: () => setSelfDeclared
35917
+ });
35918
+ import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "node:fs/promises";
35919
+ import { join as join7, dirname as dirname4 } from "node:path";
35920
+ async function load2() {
35921
+ if (state2) return state2;
35922
+ try {
35923
+ state2 = { ...structuredClone(EMPTY2), ...JSON.parse(await readFile6(PROFILE_PATH, "utf8")) };
35924
+ } catch {
35925
+ state2 = structuredClone(EMPTY2);
35926
+ }
35927
+ return state2;
35928
+ }
35929
+ async function persist2() {
35930
+ await mkdir5(dirname4(PROFILE_PATH), { recursive: true });
35931
+ await writeFile5(PROFILE_PATH, JSON.stringify(state2, null, 2), "utf8");
35932
+ }
35933
+ function schedulePersist() {
35934
+ if (saveTimer) return;
35935
+ saveTimer = setTimeout(() => {
35936
+ saveTimer = null;
35937
+ persist2().catch(() => {
35938
+ });
35939
+ }, 800);
35940
+ saveTimer.unref?.();
35941
+ }
35942
+ function bump(map, key, by = 1) {
35943
+ if (!key) return;
35944
+ map[key] = (map[key] ?? 0) + by;
35945
+ }
35946
+ async function recordCite(style) {
35947
+ const s = await load2();
35948
+ bump(s.citationStyles, String(style ?? "apa").toLowerCase());
35949
+ s.updatedAt = Date.now();
35950
+ schedulePersist();
35951
+ }
35952
+ async function recordQuery(query) {
35953
+ const s = await load2();
35954
+ s.queries.unshift({ q: String(query ?? "").slice(0, 120), at: Date.now() });
35955
+ if (s.queries.length > 100) s.queries.length = 100;
35956
+ s.updatedAt = Date.now();
35957
+ schedulePersist();
35958
+ }
35959
+ async function recordNote(key, note) {
35960
+ const s = await load2();
35961
+ const text = String(note ?? "");
35962
+ s.pragmatics.noteCount += 1;
35963
+ s.pragmatics.avgNoteLen = Math.round((s.pragmatics.avgNoteLen * (s.pragmatics.noteCount - 1) + text.length) / s.pragmatics.noteCount);
35964
+ s.pragmatics.language = hasCjk(text) ? /[a-zA-Z]{4,}/.test(text) ? "zh-en-mixed" : "zh" : "en";
35965
+ schedulePersist();
35966
+ }
35967
+ async function recordTopic(topic, itemKey) {
35968
+ const s = await load2();
35969
+ const t = String(topic ?? "").trim().slice(0, 60);
35970
+ if (!t) return;
35971
+ const entry = s.topics[t] = s.topics[t] ?? { weight: 0, evidence: [] };
35972
+ entry.weight += 1;
35973
+ if (itemKey && !entry.evidence.includes(itemKey)) entry.evidence.unshift(itemKey);
35974
+ if (entry.evidence.length > 10) entry.evidence.length = 10;
35975
+ s.updatedAt = Date.now();
35976
+ schedulePersist();
35977
+ }
35978
+ async function recordMethod(kind) {
35979
+ const s = await load2();
35980
+ bump(s.methods, String(kind ?? "").toLowerCase());
35981
+ schedulePersist();
35982
+ }
35983
+ async function setSelfDeclared(text) {
35984
+ const s = await load2();
35985
+ s.selfDeclared = String(text ?? "").slice(0, 2e3);
35986
+ s.updatedAt = Date.now();
35987
+ await persist2();
35988
+ }
35989
+ async function distillMaterial() {
35990
+ const s = await load2();
35991
+ 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`);
35992
+ const methods = Object.entries(s.methods).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`);
35993
+ const styles = Object.entries(s.citationStyles).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`);
35994
+ const queries = s.queries.slice(0, 20).map((q) => `- ${q.q}`);
35995
+ return [
35996
+ `\u3010\u753B\u50CF\u84B8\u998F\u7D20\u6750\u3011\uFF08\u622A\u81F3 ${new Date(s.updatedAt ?? Date.now()).toISOString().slice(0, 10)}\uFF09`,
35997
+ top.length ? `\u7814\u7A76\u4E3B\u9898\uFF08\u6309\u51FA\u73B0\u9891\u6B21\uFF09\uFF1A
35998
+ ${top.map((t) => "- " + t).join("\n")}` : "\u7814\u7A76\u4E3B\u9898\uFF1A\u6682\u65E0\u8DB3\u591F\u6570\u636E",
35999
+ methods.length ? `\u65B9\u6CD5\u8BBA\u503E\u5411\uFF1A${methods.join(", ")}` : "\u65B9\u6CD5\u8BBA\u503E\u5411\uFF1A\u6682\u65E0\u6570\u636E",
36000
+ styles.length ? `\u5F15\u7528\u683C\u5F0F\u4F7F\u7528\uFF1A${styles.join(", ")}` : "\u5F15\u7528\u683C\u5F0F\u4F7F\u7528\uFF1A\u6682\u65E0\u6570\u636E",
36001
+ `\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}`,
36002
+ queries.length ? `\u8FD1\u671F\u68C0\u7D22\uFF08\u53CD\u6620\u771F\u5B9E\u5173\u6CE8\u70B9\uFF09\uFF1A
36003
+ ${queries.join("\n")}` : "\u8FD1\u671F\u68C0\u7D22\uFF1A\u6682\u65E0",
36004
+ s.selfDeclared ? `\u7528\u6237\u81EA\u8FF0\uFF1A${s.selfDeclared}` : ""
36005
+ ].filter(Boolean).join("\n\n");
36006
+ }
36007
+ async function profileMarkdown() {
36008
+ try {
36009
+ return await readFile6(PROFILE_MD_PATH, "utf8");
36010
+ } catch {
36011
+ return "";
36012
+ }
36013
+ }
36014
+ async function saveProfileMarkdown(md) {
36015
+ await mkdir5(dirname4(PROFILE_MD_PATH), { recursive: true });
36016
+ await writeFile5(PROFILE_MD_PATH, String(md ?? "").slice(0, 8e3), "utf8");
36017
+ }
36018
+ function hasCjk(s) {
36019
+ return /[\u4e00-\u9fff]/.test(String(s ?? ""));
36020
+ }
36021
+ var PROFILE_PATH, PROFILE_MD_PATH, EMPTY2, state2, saveTimer;
36022
+ var init_profile = __esm({
36023
+ "src/node/profile.js"() {
36024
+ init_config();
36025
+ PROFILE_PATH = join7(STORE_DIR, "scholar-profile.json");
36026
+ PROFILE_MD_PATH = join7(STORE_DIR, "scholar-profile.md");
36027
+ EMPTY2 = {
36028
+ version: 1,
36029
+ updatedAt: 0,
36030
+ // topic -> { weight, evidence: [itemKey] } — raised by deepread cards,
36031
+ // saves, notes. Weight is a simple counter; ranking normalises it.
36032
+ topics: {},
36033
+ // methodology affinity: experiment / theory / engineering / review
36034
+ methods: {},
36035
+ // citation format usage counters: apa / gb / mla / chicago / bibtex
36036
+ citationStyles: {},
36037
+ // search query log (capped): what the user asks for, verbatim
36038
+ queries: [],
36039
+ // canonical term -> accepted variants (from notes/deepread language)
36040
+ terminology: {},
36041
+ // pragmatics observed from query & note text
36042
+ pragmatics: { language: "", avgNoteLen: 0, noteCount: 0 },
36043
+ // free-form notes the user explicitly adds about themselves
36044
+ selfDeclared: ""
36045
+ };
36046
+ state2 = null;
36047
+ saveTimer = null;
36048
+ }
36049
+ });
36050
+
36051
+ // src/node/courseware/reading-modes.js
36052
+ var reading_modes_exports = {};
36053
+ __export(reading_modes_exports, {
36054
+ READING_MODES: () => READING_MODES,
36055
+ buildReadPackage: () => buildReadPackage,
36056
+ sliceForMode: () => sliceForMode
36057
+ });
36058
+ function sliceForMode(text, mode) {
36059
+ const s = String(text ?? "");
36060
+ const budget = READING_MODES[mode]?.textBudgetChars ?? 45e3;
36061
+ if (s.length <= budget) return s;
36062
+ if (mode === "pass1") {
36063
+ const head = s.slice(0, Math.floor(budget * 0.75));
36064
+ const tail = s.slice(-Math.floor(budget * 0.25));
36065
+ return `${head}
36066
+ \u2026\uFF08\u4E2D\u6BB5\u7701\u7565\uFF09\u2026
36067
+ ${tail}`;
36068
+ }
36069
+ return `${s.slice(0, budget)}
36070
+ \u2026\uFF08\u8D85\u51FA\u9884\u7B97\u622A\u65AD\uFF09\u2026`;
36071
+ }
36072
+ function buildReadPackage(mode, { title, text, figures = [] }) {
36073
+ const m = READING_MODES[mode] ?? READING_MODES.pass1;
36074
+ const lines = [
36075
+ `\u3010\u6587\u732E\u89E3\u8BFB\u4EFB\u52A1 \xB7 ${m.name}\u3011`,
36076
+ `\u8BBA\u6587\uFF1A${title}`,
36077
+ "",
36078
+ "\u4EFB\u52A1\u8981\u6C42\uFF1A",
36079
+ ...m.instructions.map((s, i) => `${i + 1}. ${s}`),
36080
+ "",
36081
+ "\u8F93\u51FA\u6A21\u677F\uFF08\u76F4\u63A5\u6309\u6B64\u7ED3\u6784\u586B\u5199\uFF09\uFF1A",
36082
+ ...m.template,
36083
+ "",
36084
+ figures.length ? "\u53EF\u7528\u56FE\u8868\u6E05\u5355\uFF1A" : "",
36085
+ ...figures.slice(0, 12).map((f) => ` - ${f}`),
36086
+ "",
36087
+ "\u2014 \u4EE5\u4E0B\u4E3A\u8BBA\u6587\u6587\u672C \u2014",
36088
+ sliceForMode(text, mode)
36089
+ ].filter(Boolean);
36090
+ return lines.join("\n");
36091
+ }
36092
+ var READING_MODES;
36093
+ var init_reading_modes = __esm({
36094
+ "src/node/courseware/reading-modes.js"() {
36095
+ READING_MODES = {
36096
+ pass1: {
36097
+ name: "\u901F\u8BFB \xB7 \u5206\u6D41",
36098
+ textBudgetChars: 12e3,
36099
+ instructions: [
36100
+ "\u53EA\u4F9D\u636E\u7ED9\u51FA\u7684\u6587\u672C\uFF08\u901A\u5E38\u662F\u6807\u9898/\u6458\u8981/\u5F15\u8A00/\u7ED3\u8BBA\uFF09\uFF0C\u4E0D\u8981\u8865\u5E38\u8BC6\u3002",
36101
+ "\u6309\u4E0B\u9762\u7684\u3010\u901F\u8BFB\u5361\u3011\u6A21\u677F\u9010\u9879\u586B\u5199\uFF0C\u6BCF\u9879 1-2 \u53E5\uFF0C\u4E0D\u786E\u5B9A\u5C31\u5199\u300C\u6587\u4E2D\u672A\u63D0\u53CA\u300D\u3002",
36102
+ '\u6700\u540E\u7ED9\u4E00\u4E2A\u76F8\u5173\u6027\u5224\u65AD\uFF1A\u4E0E"\u6211\u5173\u6CE8\u7684\u4E3B\u9898"\u76F8\u6BD4\uFF0C\u8FD9\u7BC7\u662F \u9AD8\u76F8\u5173 / \u4E00\u822C / \u4E0D\u76F8\u5173\uFF08\u8BF4\u660E\u7406\u7531\u4E00\u53E5\u8BDD\uFF09\u3002'
36103
+ ],
36104
+ template: [
36105
+ "\u3010\u901F\u8BFB\u5361\u3011",
36106
+ "\u7814\u7A76\u95EE\u9898\uFF1A",
36107
+ "\u6838\u5FC3\u4E3B\u5F20\uFF08\u4E00\u53E5\u8BDD\uFF09\uFF1A",
36108
+ "\u65B9\u6CD5\u6982\u8981\uFF1A",
36109
+ "\u4E3B\u8981\u7ED3\u679C\uFF1A",
36110
+ "\u4E0E\u6211\u7684\u4E3B\u9898\u7684\u5173\u7CFB\uFF1A",
36111
+ "\u76F8\u5173\u6027\uFF1A\u9AD8\u76F8\u5173 / \u4E00\u822C / \u4E0D\u76F8\u5173 \u2014 \u7406\u7531"
36112
+ ]
36113
+ },
36114
+ pass2: {
36115
+ name: "\u6DF1\u8BFB \xB7 \u4E3B\u5F20\u4E0E\u8BC1\u636E",
36116
+ textBudgetChars: 45e3,
36117
+ instructions: [
36118
+ "\u9010\u6761\u62BD\u53D6\u8BBA\u6587\u7684**\u53EF\u6838\u67E5\u4E3B\u5F20**\uFF08claim\uFF09\uFF0C\u6BCF\u6761\u5FC5\u987B\u6807\u6CE8\u6240\u5728\u7AE0\u8282\u6216\u9875\u7801\u3002",
36119
+ "\u5BF9\u6BCF\u6761\u4E3B\u5F20\u505A\u8BC1\u636E\u5BA1\u8BA1\uFF1A\u8BC1\u636E\u7C7B\u578B\uFF08\u5B9E\u9A8C/\u7406\u8BBA/\u6848\u4F8B/\u5F15\u7528\u4ED6\u4EBA\uFF09+ \u5F3A\u5EA6\uFF08\u5F3A/\u4E2D/\u5F31\uFF09+ \u662F\u5426\u6709\u5BF9\u7167\u6216\u6D88\u878D\u3002",
36120
+ "\u5217\u51FA\u65B9\u6CD5\u7684\u8F93\u5165/\u8F93\u51FA/\u5173\u952E\u5047\u8BBE\uFF1B\u5982\u679C\u6362\u4E00\u4E2A\u6570\u636E\u96C6\u6216\u573A\u666F\uFF0C\u54EA\u4E9B\u7ED3\u8BBA\u53EF\u80FD\u4E0D\u6210\u7ACB\uFF08\u65B9\u6CD5\u63A2\u6D4B\uFF09\u3002",
36121
+ "\u660E\u786E\u533A\u5206\uFF1A\u4F5C\u8005\u7684\u5B9E\u8BC1\u7ED3\u679C vs \u4F5C\u8005\u7684\u63A8\u6D4B/\u5C55\u671B\uFF0C\u4E0D\u8981\u6DF7\u5728\u4E00\u8D77\u3002"
36122
+ ],
36123
+ template: [
36124
+ "\u3010\u6DF1\u8BFB\u5361\u3011",
36125
+ "\u4E3B\u5F20\u6E05\u5355\uFF08\u6BCF\u6761\uFF1A\u4E3B\u5F20 | \u51FA\u5904\u7AE0\u8282/\u9875 | \u8BC1\u636E\u7C7B\u578B | \u5F3A\u5EA6 \u5F3A/\u4E2D/\u5F31\uFF09\uFF1A",
36126
+ "1. ",
36127
+ "2. ",
36128
+ "\u65B9\u6CD5\u5256\u6790\uFF1A\u8F93\u5165 \u2192 \u5904\u7406 \u2192 \u8F93\u51FA\uFF1B\u5173\u952E\u5047\u8BBE\uFF1A",
36129
+ "\u65B9\u6CD5\u63A2\u6D4B\uFF1A\u5982\u679C\u6362\u6570\u636E\u96C6/\u573A\u666F\uFF0C\u53EF\u80FD\u5931\u6548\u7684\u662F\uFF1A",
36130
+ "\u5B9E\u8BC1 vs \u63A8\u6D4B\uFF1A",
36131
+ "\u672A\u89E3\u51B3\u7684\u95EE\u9898 / \u5C40\u9650\uFF1A"
36132
+ ]
36133
+ },
36134
+ pass3: {
36135
+ name: "\u7CBE\u8BFB \xB7 \u7B2C\u4E00\u6027\u539F\u7406\u4E0E\u5DE5\u827A",
36136
+ textBudgetChars: 45e3,
36137
+ instructions: [
36138
+ "\u7B2C\u4E00\u6027\u539F\u7406\u5206\u89E3\uFF1A\u4ECE\u56DB\u4E2A\u57FA\u7840\u7EF4\u5EA6\u62C6\u89E3\u8FD9\u7BC7\u5DE5\u4F5C\u2014\u2014\u72B6\u6001\uFF08\u5B83\u7EF4\u62A4\u4EC0\u4E48\u4FE1\u606F\uFF09\u3001\u65F6\u95F4\uFF08\u4F55\u65F6\u8BA1\u7B97/\u66F4\u65B0\uFF09\u3001\u534F\u8C03\uFF08\u6A21\u5757\u95F4\u5982\u4F55\u8854\u63A5\uFF09\u3001\u63A5\u53E3\uFF08\u5BF9\u5916\u66B4\u9732\u4EC0\u4E48\uFF09\u3002\u6BCF\u4E2A\u7EF4\u5EA6 1-2 \u53E5\uFF0C\u4FBF\u4E8E\u8DE8\u8BBA\u6587\u6BD4\u8F83\u3002",
36139
+ "\u865A\u62DF\u91CD\u5B9E\u73B0\uFF1A\u56DE\u7B54\u300C\u5982\u679C\u6211\u4ECE\u96F6\u590D\u73B0\u5B83\uFF0C\u6838\u5FC3\u8BBE\u8BA1\u51B3\u7B56\u6709\u54EA\u51E0\u4E2A\uFF1F\u6700\u96BE\u7684\u662F\u54EA\u4E00\u6B65\uFF1F\u300D",
36140
+ "\u5199\u4F5C\u5DE5\u827A\uFF08\u53EF\u9009\uFF09\uFF1A\u7528\u516D\u6BB5\u516C\u5F0F\u89E3\u5256\u5F15\u8A00\u2014\u2014\u7ACB\u610F(Stakes) \u2192 \u95EE\u9898\u7F3A\u53E3(Problem Gap) \u2192 \u5173\u952E\u62BD\u8C61(Key Abstraction) \u2192 \u8BBE\u8BA1\u76F4\u89C9(Design Intuition) \u2192 \u8D21\u732E(Contributions) \u2192 \u7ED3\u679C\u9884\u89C8(Results Preview)\u3002",
36141
+ "\u56FE\u8868\u6E05\u5355\uFF1A\u5217\u51FA\u91CD\u8981\u56FE\u8868\u4E0E\u5404\u81EA\u652F\u6491\u7684\u8BBA\u70B9\uFF1B\u56FE\u8868\u7F3A\u5931\u6216\u8D28\u91CF\u5DEE\u7684\u6570\u636E\uFF0C\u6807\u6CE8\u51FA\u6765\uFF08\u540E\u7EED\u53EF\u4EE5\u7531\u63D2\u4EF6\u751F\u6210\u793A\u610F\u56FE\uFF09\u3002"
36142
+ ],
36143
+ template: [
36144
+ "\u3010\u7CBE\u8BFB\u5361\u3011",
36145
+ "\u7B2C\u4E00\u6027\u539F\u7406\uFF1A",
36146
+ " \u72B6\u6001\uFF1A",
36147
+ " \u65F6\u95F4\uFF1A",
36148
+ " \u534F\u8C03\uFF1A",
36149
+ " \u63A5\u53E3\uFF1A",
36150
+ "\u865A\u62DF\u91CD\u5B9E\u73B0\uFF1A\u6838\u5FC3\u51B3\u7B56\u4E0E\u6700\u96BE\u6B65\u9AA4\uFF1A",
36151
+ "\u5F15\u8A00\u5DE5\u827A\uFF08\u516D\u6BB5\uFF09\uFF1A",
36152
+ "\u91CD\u8981\u56FE\u8868\uFF08\u56FE\u8868/\u9875\u7801/\u652F\u6491\u7684\u8BBA\u70B9\uFF09\uFF1A",
36153
+ "\u6570\u636E\u7F3A\u5931\u3001\u53EF\u751F\u6210\u793A\u610F\u56FE\u7684\u4F4D\u7F6E\uFF1A"
36154
+ ]
36155
+ }
36156
+ };
36157
+ }
36158
+ });
36159
+
35897
36160
  // src/node/doctor-selfheal.js
35898
36161
  var doctor_selfheal_exports = {};
35899
36162
  __export(doctor_selfheal_exports, {
@@ -35904,12 +36167,12 @@ __export(doctor_selfheal_exports, {
35904
36167
  });
35905
36168
  import { createHash } from "node:crypto";
35906
36169
  import { existsSync as existsSync2, readdirSync as readdirSync2 } from "node:fs";
35907
- import { join as join8 } from "node:path";
36170
+ import { join as join9 } from "node:path";
35908
36171
  import { homedir as homedir4 } from "node:os";
35909
36172
  import { spawn } from "node:child_process";
35910
36173
  import net from "node:net";
35911
36174
  function doctorRoot() {
35912
- return process.env.DSH_DOCTOR_HOME?.trim() || join8(homedir4(), ".dsh-doctor");
36175
+ return process.env.DSH_DOCTOR_HOME?.trim() || join9(homedir4(), ".dsh-doctor");
35913
36176
  }
35914
36177
  function doctorPipeName(root = doctorRoot()) {
35915
36178
  const hash = createHash("sha256").update(root).digest("hex").slice(0, 16);
@@ -35934,7 +36197,7 @@ function pipeAvailable(pipe, timeoutMs = 1500) {
35934
36197
  });
35935
36198
  }
35936
36199
  function findDoctorCli() {
35937
- const profilesDir = join8(homedir4(), ".dsh", "profiles");
36200
+ const profilesDir = join9(homedir4(), ".dsh", "profiles");
35938
36201
  let entries = [];
35939
36202
  try {
35940
36203
  entries = readdirSync2(profilesDir);
@@ -35942,7 +36205,7 @@ function findDoctorCli() {
35942
36205
  return "";
35943
36206
  }
35944
36207
  for (const name2 of entries) {
35945
- const candidate = join8(profilesDir, name2, "node_modules", "@linxin666", "dsh-doctor", "lib", "cli.mjs");
36208
+ const candidate = join9(profilesDir, name2, "node_modules", "@linxin666", "dsh-doctor", "lib", "cli.mjs");
35946
36209
  if (existsSync2(candidate)) return candidate;
35947
36210
  }
35948
36211
  return "";
@@ -36524,9 +36787,10 @@ function snippetFor(item, terms) {
36524
36787
  // src/node/tools.js
36525
36788
  init_normalize();
36526
36789
  init_log();
36527
- import { writeFile as writeFile5, mkdtemp, readFile as readFile6, rm } from "node:fs/promises";
36790
+ init_profile();
36791
+ import { writeFile as writeFile6, mkdtemp, readFile as readFile7, rm } from "node:fs/promises";
36528
36792
  import { tmpdir } from "node:os";
36529
- import { join as join7 } from "node:path";
36793
+ import { join as join8 } from "node:path";
36530
36794
  function textResult(value) {
36531
36795
  return {
36532
36796
  schema: { type: "string" },
@@ -36534,7 +36798,7 @@ function textResult(value) {
36534
36798
  };
36535
36799
  }
36536
36800
  function toolDefs() {
36537
- return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool()];
36801
+ return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool(), deepreadTool(), profileTool()];
36538
36802
  }
36539
36803
  function registerTools(ctx2) {
36540
36804
  let mounted = [];
@@ -36626,6 +36890,8 @@ function searchTool() {
36626
36890
  async execute(args) {
36627
36891
  const query = String(args?.query ?? "").trim();
36628
36892
  if (!query) return "\u7F3A\u5C11\u68C0\u7D22\u8BCD\u3002";
36893
+ recordQuery(query).catch(() => {
36894
+ });
36629
36895
  const limit = Math.max(1, Math.min(Number(args?.limit) || 8, 20));
36630
36896
  const items = await listItems();
36631
36897
  const hits = searchItems2(items, query, { limit });
@@ -36698,6 +36964,8 @@ function citeTool() {
36698
36964
  const item = await getItem(key);
36699
36965
  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`;
36700
36966
  const { citeDetailed: citeDetailed2 } = await Promise.resolve().then(() => (init_cite(), cite_exports));
36967
+ recordCite(args?.style ?? "apa").catch(() => {
36968
+ });
36701
36969
  const d = citeDetailed2(item.record, {
36702
36970
  style: args?.style ?? "apa",
36703
36971
  mode: args?.mode ?? "reference",
@@ -36734,6 +37002,8 @@ function noteTool() {
36734
37002
  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";
36735
37003
  const entry = { text: note, at: (/* @__PURE__ */ new Date()).toISOString() };
36736
37004
  await patchItem(key, { notes: [...notes, entry] });
37005
+ recordNote(key, note).catch(() => {
37006
+ });
36737
37007
  return `\u5DF2\u8BB0\u5F55\u5230\u6761\u76EE ${key}\uFF08\u5171 ${notes.length + 1} \u6761\u7B14\u8BB0\uFF09\u3002`;
36738
37008
  }
36739
37009
  };
@@ -36805,10 +37075,10 @@ function figureTool() {
36805
37075
  if (!fig || !fig.hasMatplotlib) {
36806
37076
  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";
36807
37077
  }
36808
- const { mkdtemp: _mk, writeFile: _w, readFile: _r, rm: _rm } = { mkdtemp, writeFile: writeFile5, readFile: readFile6, rm };
36809
- const dir = await mkdtemp(join7(tmpdir(), "lit-fig-"));
36810
- const pyFile = join7(dir, "fig.py");
36811
- const pngFile = join7(dir, "fig.png");
37078
+ const { mkdtemp: _mk, writeFile: _w, readFile: _r, rm: _rm } = { mkdtemp, writeFile: writeFile6, readFile: readFile7, rm };
37079
+ const dir = await mkdtemp(join8(tmpdir(), "lit-fig-"));
37080
+ const pyFile = join8(dir, "fig.py");
37081
+ const pngFile = join8(dir, "fig.png");
36812
37082
  const script = [
36813
37083
  "import matplotlib",
36814
37084
  "matplotlib.use('Agg')",
@@ -36845,13 +37115,13 @@ function figureTool() {
36845
37115
  "plt.tight_layout()",
36846
37116
  `plt.savefig(${JSON.stringify(pngFile)})`
36847
37117
  ].join("\n");
36848
- await writeFile5(pyFile, script, "utf8");
37118
+ await writeFile6(pyFile, script, "utf8");
36849
37119
  const { execFile: execFile2 } = await import("node:child_process");
36850
37120
  const run2 = () => new Promise((resolve6) => execFile2(fig.exe, [pyFile], { timeout: 6e4, windowsHide: true }, (err, stdout, stderr) => resolve6({ err, stdout, stderr })));
36851
37121
  const r = await run2();
36852
37122
  let png = null;
36853
37123
  try {
36854
- png = await readFile6(pngFile);
37124
+ png = await readFile7(pngFile);
36855
37125
  } catch {
36856
37126
  }
36857
37127
  await rm(dir, { recursive: true, force: true }).catch(() => {
@@ -36869,6 +37139,101 @@ function figureTool() {
36869
37139
  }
36870
37140
  };
36871
37141
  }
37142
+ function deepreadTool() {
37143
+ const MODES = /* @__PURE__ */ new Set(["pass1", "pass2", "pass3"]);
37144
+ return {
37145
+ name: "literature_deepread",
37146
+ description: "\u542F\u52A8\u5BF9\u67D0\u7BC7\u6587\u732E\u7684\u7ED3\u6784\u5316\u89E3\u8BFB\uFF0C\u8FD4\u56DE\u5185\u7F6E\u7684\u89E3\u8BFB\u4EFB\u52A1\u5305\uFF08\u901F\u8BFB\u5206\u6D41 / \u6DF1\u8BFB\u4E3B\u5F20\u4E0E\u8BC1\u636E / \u7CBE\u8BFB\u7B2C\u4E00\u6027\u539F\u7406\uFF09\u3002\u5728\u7528\u6237\u8981\u6C42\u300C\u8BFB\u4E00\u4E0B\u8FD9\u7BC7/\u603B\u7ED3\u8FD9\u7BC7/\u7CBE\u8BFB/\u505A\u6587\u732E\u7B14\u8BB0\u300D\u65F6\u8C03\u7528\u3002\u89E3\u8BFB\u5B8C\u6210\u540E\u7528 literature_note(key, \u4EE5\u3010\u901F\u8BFB\u5361\u3011/\u3010\u6DF1\u8BFB\u5361\u3011/\u3010\u7CBE\u8BFB\u5361\u3011\u5F00\u5934\u7684\u4EA7\u51FA) \u4FDD\u5B58\u7ED3\u679C\u3002",
37147
+ parameters: {
37148
+ type: "object",
37149
+ properties: {
37150
+ key: { type: "string", description: "\u6761\u76EE key" },
37151
+ depth: { type: "string", description: "pass1 \u901F\u8BFB\uFF08\u9ED8\u8BA4\uFF09| pass2 \u6DF1\u8BFB\u4E3B\u5F20\u4E0E\u8BC1\u636E | pass3 \u7CBE\u8BFB\u7B2C\u4E00\u6027\u539F\u7406" }
37152
+ },
37153
+ required: ["key"]
37154
+ },
37155
+ output: textResult(),
37156
+ timeoutMs: 3e4,
37157
+ async execute(args) {
37158
+ const key = String(args?.key ?? "");
37159
+ if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
37160
+ const mode = MODES.has(args?.depth) ? args.depth : "pass1";
37161
+ const item = await getItem(key);
37162
+ if (!item) return `\u672A\u627E\u5230\u6761\u76EE ${key}\u3002\u8BF7\u5148\u7528 literature_search \u83B7\u53D6\u6B63\u786E\u7684 key\u3002`;
37163
+ if (!item.pdf?.path) return `\u8BE5\u6761\u76EE\u8FD8\u6CA1\u6709\u5168\u6587 PDF\u3002\u53EF\u5148 literature_save(action=fetch) \u4E0B\u8F7D\uFF0C\u6216\u5BF9\u6709\u5168\u6587\u7684\u6761\u76EE\u4F7F\u7528\u672C\u5DE5\u5177\u3002`;
37164
+ const { extractPdfText: extractPdfText2 } = await Promise.resolve().then(() => (init_pdf_text(), pdf_text_exports));
37165
+ let text = "";
37166
+ try {
37167
+ text = await extractPdfText2(item.pdf.path);
37168
+ } catch {
37169
+ return "\u65E0\u6CD5\u89E3\u6790\u8BE5 PDF \u7684\u6587\u672C\uFF08\u6587\u4EF6\u53EF\u80FD\u635F\u574F\uFF0C\u6216\u662F\u65E0\u6587\u672C\u5C42\u7684\u626B\u63CF\u4EF6\uFF09\u3002";
37170
+ }
37171
+ if (!text) return "\u8BE5 PDF \u6CA1\u6709\u53EF\u63D0\u53D6\u7684\u6587\u672C\uFF08\u53EF\u80FD\u662F\u626B\u63CF\u4EF6\uFF09\u3002";
37172
+ const title = item.record?.title ?? item.title ?? item.display ?? key;
37173
+ const figures = [];
37174
+ for (const m of text.matchAll(/(?:Fig(?:ure)?|表|Table)\s*\d+[.::][^\n]{5,90}/g)) {
37175
+ if (figures.length < 12) figures.push(m[0].trim());
37176
+ }
37177
+ recordTopic(title, key).catch(() => {
37178
+ });
37179
+ const { buildReadPackage: buildReadPackage2 } = await Promise.resolve().then(() => (init_reading_modes(), reading_modes_exports));
37180
+ const pack = buildReadPackage2(mode, { title, text, figures });
37181
+ return pack + `
37182
+
37183
+ \u2014 \u89E3\u8BFB\u5B8C\u6210\u540E\uFF1Aliterature_note(key, \u4EE5\u3010${mode === "pass1" ? "\u901F\u8BFB\u5361" : mode === "pass2" ? "\u6DF1\u8BFB\u5361" : "\u7CBE\u8BFB\u5361"}\u3011\u5F00\u5934\u7684\u4EA7\u51FA) \u4FDD\u5B58\u3002`;
37184
+ }
37185
+ };
37186
+ }
37187
+ function profileTool() {
37188
+ return {
37189
+ name: "literature_profile",
37190
+ 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",
37191
+ parameters: {
37192
+ type: "object",
37193
+ properties: {
37194
+ 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" },
37195
+ content: { type: "string", description: "action=save \u65F6\u7684\u753B\u50CF Markdown\uFF1Baction=self \u65F6\u7684\u7528\u6237\u81EA\u8FF0" }
37196
+ },
37197
+ required: []
37198
+ },
37199
+ output: textResult(),
37200
+ timeoutMs: 15e3,
37201
+ async execute(args) {
37202
+ const { distillMaterial: distillMaterial2, profileMarkdown: profileMarkdown2, saveProfileMarkdown: saveProfileMarkdown2, setSelfDeclared: setSelfDeclared2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
37203
+ const action = String(args?.action ?? "view");
37204
+ if (action === "save") {
37205
+ const md = String(args?.content ?? "").trim();
37206
+ if (!md) return "\u7F3A\u5C11\u753B\u50CF\u5185\u5BB9\uFF08content\uFF09\u3002";
37207
+ await saveProfileMarkdown2(md);
37208
+ 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";
37209
+ }
37210
+ if (action === "self") {
37211
+ await setSelfDeclared2(args?.content);
37212
+ return "\u5DF2\u767B\u8BB0\u7528\u6237\u81EA\u8FF0\uFF0C\u4E0B\u6B21\u84B8\u998F\u4F1A\u7EB3\u5165\u3002";
37213
+ }
37214
+ if (action === "distill") {
37215
+ const material = await distillMaterial2();
37216
+ const existing = await profileMarkdown2();
37217
+ return [
37218
+ material,
37219
+ "",
37220
+ existing ? "\u3010\u73B0\u6709\u753B\u50CF\u3011\n" + existing : "",
37221
+ "",
37222
+ "\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",
37223
+ "## \u7814\u7A76\u9886\u57DF\uFF08\u6309\u719F\u6089\u5EA6\u6392\u5E8F\uFF09",
37224
+ "## \u65B9\u6CD5\u8BBA\u504F\u597D\uFF08\u5B9E\u9A8C/\u7406\u8BBA/\u5DE5\u7A0B\uFF09",
37225
+ "## \u672F\u8BED\u4E0E\u8868\u8FBE\u4E60\u60EF\uFF08\u7528\u6237\u5982\u4F55\u79F0\u547C\u6982\u5FF5\u3001\u4E2D\u82F1\u6DF7\u7528\u60C5\u51B5\uFF09",
37226
+ "## \u5F15\u7528\u4E60\u60EF\uFF08\u5E38\u7528\u683C\u5F0F\u3001\u8BED\u6C14\uFF09",
37227
+ "## \u5F53\u524D\u5173\u6CE8\u4E0E\u76EE\u6807",
37228
+ "\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",
37229
+ "\u5199\u5B8C\u540E\u8C03\u7528 literature_profile(action=save, content=\u753B\u50CF) \u4FDD\u5B58\u3002"
37230
+ ].join("\n");
37231
+ }
37232
+ const current = await profileMarkdown2();
37233
+ 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";
37234
+ }
37235
+ };
37236
+ }
36872
37237
  function saveTool() {
36873
37238
  return {
36874
37239
  name: "literature_save",
@@ -37121,7 +37486,7 @@ function createActivation({ idleTimeoutMs = IDLE_TIMEOUT_MS } = {}) {
37121
37486
  // src/node/index.js
37122
37487
  init_log();
37123
37488
  var name = "dsh-literature-pre";
37124
- var inject = ["webServer", "tools"];
37489
+ var inject = ["webServer", "tools", "systemPrompt"];
37125
37490
  function apply(ctx2, config) {
37126
37491
  const onUncaught = (e) => error("uncaught exception:", e?.stack ?? e);
37127
37492
  const onUnhandled = (e) => error("unhandled rejection:", e?.stack ?? e);
@@ -37135,9 +37500,30 @@ function apply(ctx2, config) {
37135
37500
  await ensureDirs();
37136
37501
  await init();
37137
37502
  const activation2 = createActivation();
37503
+ activation2.activate("always-on");
37138
37504
  const toolsCtl = registerTools(ctx2);
37505
+ toolsCtl.mount();
37139
37506
  disposers.push(activation2.onTransition(({ active }) => active ? toolsCtl.mount() : toolsCtl.unmount()));
37140
37507
  disposers.push(() => activation2.dispose());
37508
+ try {
37509
+ disposers.push(
37510
+ ctx2.systemPrompt.section({
37511
+ name: "dsh:dsh-literature-capabilities",
37512
+ order: 9900,
37513
+ text: () => [
37514
+ "\u672C\u673A\u5DF2\u5B89\u88C5\u6587\u732E\u63D2\u4EF6\uFF08dsh-literature\uFF09\uFF1A\u5185\u7F6E\u6587\u732E\u5E93 + PDF/\u8BFE\u4EF6\u9605\u8BFB + \u89C4\u8303\u5F15\u7528\u751F\u6210\u3002",
37515
+ "\u7528\u6237\u63D0\u5230\u300C\u6587\u732E/\u8BBA\u6587/DOI/arXiv/\u5F15\u7528/\u53C2\u8003\u6587\u732E/\u7EFC\u8FF0/\u7EC4\u4F1A\u300D\u6216\u9700\u8981\u5B66\u672F\u652F\u6491\u65F6\uFF1A",
37516
+ "- \u627E\u5E93\u91CC\u5DF2\u6709\u7684 \u2192 literature_search\uFF08\u5148\u67E5\u518D\u7B54\uFF0C\u4E0D\u8981\u51ED\u7A7A\u7F16\u9020\u6761\u76EE\uFF09",
37517
+ "- \u770B\u8BE6\u60C5 \u2192 literature_get\uFF1B\u7ED3\u6784\u5316\u89E3\u8BFB \u2192 literature_deepread\uFF08\u901F\u8BFB/\u6DF1\u8BFB/\u7CBE\u8BFB\u4E09\u6863\uFF0C\u4EA7\u51FA\u540E\u7528 literature_note \u4FDD\u5B58\uFF09",
37518
+ "- \u5199\u4F5C\u5F15\u7528 \u2192 literature_cite\uFF08APA/GB/MLA/Chicago/BibTeX\uFF0C\u52FF\u624B\u5DE5\u62FC\u88C5\uFF09",
37519
+ "- \u8BB0\u5F55\u6587\u732E\u4E0E\u5F53\u524D\u5DE5\u4F5C\u7684\u5173\u7CFB \u2192 literature_note\uFF1B\u7528\u6237\u660E\u786E\u8981\u6C42\u753B\u56FE\u65F6 \u2192 literature_figure",
37520
+ "\u7EAA\u5F8B\uFF1A\u5148 search \u518D get\uFF1B\u672A\u627E\u5230\u65F6\u5982\u5B9E\u8BF4\u300C\u5E93\u91CC\u6CA1\u6709\u300D\uFF1B\u7F16\u7801\u4EFB\u52A1\u4E2D\u4E0D\u8981\u4E3B\u52A8\u4F7F\u7528\u8FD9\u4E9B\u5DE5\u5177\u3002"
37521
+ ].join("\n")
37522
+ })
37523
+ );
37524
+ } catch (e) {
37525
+ error("systemPrompt unavailable:", e.message);
37526
+ }
37141
37527
  disposers.push(...registerRoutes(ctx2, { activation: activation2 }));
37142
37528
  try {
37143
37529
  disposers.push(...registerSessionHook(ctx2, { activation: activation2, detectIntent }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a9i5k4/dsh-literature",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "DSH Literature 文献侧窗:在 DeepSeek Harness 侧边栏识别 DOI/arXiv/标题、抓取元数据与全文、写入本地文献库或导出目录,并提供内置 PDF 阅读器(缩放/翻页/目录/搜索/高亮/笔记)。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",