@a9i5k4/dsh-literature 0.3.0 → 0.3.1

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 +183 -2
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -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,115 @@ var init_ai = __esm({
35894
35902
  }
35895
35903
  });
35896
35904
 
35905
+ // src/node/courseware/reading-modes.js
35906
+ var reading_modes_exports = {};
35907
+ __export(reading_modes_exports, {
35908
+ READING_MODES: () => READING_MODES,
35909
+ buildReadPackage: () => buildReadPackage,
35910
+ sliceForMode: () => sliceForMode
35911
+ });
35912
+ function sliceForMode(text, mode) {
35913
+ const s = String(text ?? "");
35914
+ const budget = READING_MODES[mode]?.textBudgetChars ?? 45e3;
35915
+ if (s.length <= budget) return s;
35916
+ if (mode === "pass1") {
35917
+ const head = s.slice(0, Math.floor(budget * 0.75));
35918
+ const tail = s.slice(-Math.floor(budget * 0.25));
35919
+ return `${head}
35920
+ \u2026\uFF08\u4E2D\u6BB5\u7701\u7565\uFF09\u2026
35921
+ ${tail}`;
35922
+ }
35923
+ return `${s.slice(0, budget)}
35924
+ \u2026\uFF08\u8D85\u51FA\u9884\u7B97\u622A\u65AD\uFF09\u2026`;
35925
+ }
35926
+ function buildReadPackage(mode, { title, text, figures = [] }) {
35927
+ const m = READING_MODES[mode] ?? READING_MODES.pass1;
35928
+ const lines = [
35929
+ `\u3010\u6587\u732E\u89E3\u8BFB\u4EFB\u52A1 \xB7 ${m.name}\u3011`,
35930
+ `\u8BBA\u6587\uFF1A${title}`,
35931
+ "",
35932
+ "\u4EFB\u52A1\u8981\u6C42\uFF1A",
35933
+ ...m.instructions.map((s, i) => `${i + 1}. ${s}`),
35934
+ "",
35935
+ "\u8F93\u51FA\u6A21\u677F\uFF08\u76F4\u63A5\u6309\u6B64\u7ED3\u6784\u586B\u5199\uFF09\uFF1A",
35936
+ ...m.template,
35937
+ "",
35938
+ figures.length ? "\u53EF\u7528\u56FE\u8868\u6E05\u5355\uFF1A" : "",
35939
+ ...figures.slice(0, 12).map((f) => ` - ${f}`),
35940
+ "",
35941
+ "\u2014 \u4EE5\u4E0B\u4E3A\u8BBA\u6587\u6587\u672C \u2014",
35942
+ sliceForMode(text, mode)
35943
+ ].filter(Boolean);
35944
+ return lines.join("\n");
35945
+ }
35946
+ var READING_MODES;
35947
+ var init_reading_modes = __esm({
35948
+ "src/node/courseware/reading-modes.js"() {
35949
+ READING_MODES = {
35950
+ pass1: {
35951
+ name: "\u901F\u8BFB \xB7 \u5206\u6D41",
35952
+ textBudgetChars: 12e3,
35953
+ instructions: [
35954
+ "\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",
35955
+ "\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",
35956
+ '\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'
35957
+ ],
35958
+ template: [
35959
+ "\u3010\u901F\u8BFB\u5361\u3011",
35960
+ "\u7814\u7A76\u95EE\u9898\uFF1A",
35961
+ "\u6838\u5FC3\u4E3B\u5F20\uFF08\u4E00\u53E5\u8BDD\uFF09\uFF1A",
35962
+ "\u65B9\u6CD5\u6982\u8981\uFF1A",
35963
+ "\u4E3B\u8981\u7ED3\u679C\uFF1A",
35964
+ "\u4E0E\u6211\u7684\u4E3B\u9898\u7684\u5173\u7CFB\uFF1A",
35965
+ "\u76F8\u5173\u6027\uFF1A\u9AD8\u76F8\u5173 / \u4E00\u822C / \u4E0D\u76F8\u5173 \u2014 \u7406\u7531"
35966
+ ]
35967
+ },
35968
+ pass2: {
35969
+ name: "\u6DF1\u8BFB \xB7 \u4E3B\u5F20\u4E0E\u8BC1\u636E",
35970
+ textBudgetChars: 45e3,
35971
+ instructions: [
35972
+ "\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",
35973
+ "\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",
35974
+ "\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",
35975
+ "\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"
35976
+ ],
35977
+ template: [
35978
+ "\u3010\u6DF1\u8BFB\u5361\u3011",
35979
+ "\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",
35980
+ "1. ",
35981
+ "2. ",
35982
+ "\u65B9\u6CD5\u5256\u6790\uFF1A\u8F93\u5165 \u2192 \u5904\u7406 \u2192 \u8F93\u51FA\uFF1B\u5173\u952E\u5047\u8BBE\uFF1A",
35983
+ "\u65B9\u6CD5\u63A2\u6D4B\uFF1A\u5982\u679C\u6362\u6570\u636E\u96C6/\u573A\u666F\uFF0C\u53EF\u80FD\u5931\u6548\u7684\u662F\uFF1A",
35984
+ "\u5B9E\u8BC1 vs \u63A8\u6D4B\uFF1A",
35985
+ "\u672A\u89E3\u51B3\u7684\u95EE\u9898 / \u5C40\u9650\uFF1A"
35986
+ ]
35987
+ },
35988
+ pass3: {
35989
+ name: "\u7CBE\u8BFB \xB7 \u7B2C\u4E00\u6027\u539F\u7406\u4E0E\u5DE5\u827A",
35990
+ textBudgetChars: 45e3,
35991
+ instructions: [
35992
+ "\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",
35993
+ "\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",
35994
+ "\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",
35995
+ "\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"
35996
+ ],
35997
+ template: [
35998
+ "\u3010\u7CBE\u8BFB\u5361\u3011",
35999
+ "\u7B2C\u4E00\u6027\u539F\u7406\uFF1A",
36000
+ " \u72B6\u6001\uFF1A",
36001
+ " \u65F6\u95F4\uFF1A",
36002
+ " \u534F\u8C03\uFF1A",
36003
+ " \u63A5\u53E3\uFF1A",
36004
+ "\u865A\u62DF\u91CD\u5B9E\u73B0\uFF1A\u6838\u5FC3\u51B3\u7B56\u4E0E\u6700\u96BE\u6B65\u9AA4\uFF1A",
36005
+ "\u5F15\u8A00\u5DE5\u827A\uFF08\u516D\u6BB5\uFF09\uFF1A",
36006
+ "\u91CD\u8981\u56FE\u8868\uFF08\u56FE\u8868/\u9875\u7801/\u652F\u6491\u7684\u8BBA\u70B9\uFF09\uFF1A",
36007
+ "\u6570\u636E\u7F3A\u5931\u3001\u53EF\u751F\u6210\u793A\u610F\u56FE\u7684\u4F4D\u7F6E\uFF1A"
36008
+ ]
36009
+ }
36010
+ };
36011
+ }
36012
+ });
36013
+
35897
36014
  // src/node/doctor-selfheal.js
35898
36015
  var doctor_selfheal_exports = {};
35899
36016
  __export(doctor_selfheal_exports, {
@@ -36534,7 +36651,7 @@ function textResult(value) {
36534
36651
  };
36535
36652
  }
36536
36653
  function toolDefs() {
36537
- return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool()];
36654
+ return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool(), deepreadTool()];
36538
36655
  }
36539
36656
  function registerTools(ctx2) {
36540
36657
  let mounted = [];
@@ -36869,6 +36986,49 @@ function figureTool() {
36869
36986
  }
36870
36987
  };
36871
36988
  }
36989
+ function deepreadTool() {
36990
+ const MODES = /* @__PURE__ */ new Set(["pass1", "pass2", "pass3"]);
36991
+ return {
36992
+ name: "literature_deepread",
36993
+ 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",
36994
+ parameters: {
36995
+ type: "object",
36996
+ properties: {
36997
+ key: { type: "string", description: "\u6761\u76EE key" },
36998
+ 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" }
36999
+ },
37000
+ required: ["key"]
37001
+ },
37002
+ output: textResult(),
37003
+ timeoutMs: 3e4,
37004
+ async execute(args) {
37005
+ const key = String(args?.key ?? "");
37006
+ if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
37007
+ const mode = MODES.has(args?.depth) ? args.depth : "pass1";
37008
+ const item = await getItem(key);
37009
+ if (!item) return `\u672A\u627E\u5230\u6761\u76EE ${key}\u3002\u8BF7\u5148\u7528 literature_search \u83B7\u53D6\u6B63\u786E\u7684 key\u3002`;
37010
+ 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`;
37011
+ const { extractPdfText: extractPdfText2 } = await Promise.resolve().then(() => (init_pdf_text(), pdf_text_exports));
37012
+ let text = "";
37013
+ try {
37014
+ text = await extractPdfText2(item.pdf.path);
37015
+ } catch {
37016
+ 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";
37017
+ }
37018
+ if (!text) return "\u8BE5 PDF \u6CA1\u6709\u53EF\u63D0\u53D6\u7684\u6587\u672C\uFF08\u53EF\u80FD\u662F\u626B\u63CF\u4EF6\uFF09\u3002";
37019
+ const title = item.record?.title ?? item.title ?? item.display ?? key;
37020
+ const figures = [];
37021
+ for (const m of text.matchAll(/(?:Fig(?:ure)?|表|Table)\s*\d+[.::][^\n]{5,90}/g)) {
37022
+ if (figures.length < 12) figures.push(m[0].trim());
37023
+ }
37024
+ const { buildReadPackage: buildReadPackage2 } = await Promise.resolve().then(() => (init_reading_modes(), reading_modes_exports));
37025
+ const pack = buildReadPackage2(mode, { title, text, figures });
37026
+ return pack + `
37027
+
37028
+ \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`;
37029
+ }
37030
+ };
37031
+ }
36872
37032
  function saveTool() {
36873
37033
  return {
36874
37034
  name: "literature_save",
@@ -37121,7 +37281,7 @@ function createActivation({ idleTimeoutMs = IDLE_TIMEOUT_MS } = {}) {
37121
37281
  // src/node/index.js
37122
37282
  init_log();
37123
37283
  var name = "dsh-literature-pre";
37124
- var inject = ["webServer", "tools"];
37284
+ var inject = ["webServer", "tools", "systemPrompt"];
37125
37285
  function apply(ctx2, config) {
37126
37286
  const onUncaught = (e) => error("uncaught exception:", e?.stack ?? e);
37127
37287
  const onUnhandled = (e) => error("unhandled rejection:", e?.stack ?? e);
@@ -37135,9 +37295,30 @@ function apply(ctx2, config) {
37135
37295
  await ensureDirs();
37136
37296
  await init();
37137
37297
  const activation2 = createActivation();
37298
+ activation2.activate("always-on");
37138
37299
  const toolsCtl = registerTools(ctx2);
37300
+ toolsCtl.mount();
37139
37301
  disposers.push(activation2.onTransition(({ active }) => active ? toolsCtl.mount() : toolsCtl.unmount()));
37140
37302
  disposers.push(() => activation2.dispose());
37303
+ try {
37304
+ disposers.push(
37305
+ ctx2.systemPrompt.section({
37306
+ name: "dsh:dsh-literature-capabilities",
37307
+ order: 9900,
37308
+ text: () => [
37309
+ "\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",
37310
+ "\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",
37311
+ "- \u627E\u5E93\u91CC\u5DF2\u6709\u7684 \u2192 literature_search\uFF08\u5148\u67E5\u518D\u7B54\uFF0C\u4E0D\u8981\u51ED\u7A7A\u7F16\u9020\u6761\u76EE\uFF09",
37312
+ "- \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",
37313
+ "- \u5199\u4F5C\u5F15\u7528 \u2192 literature_cite\uFF08APA/GB/MLA/Chicago/BibTeX\uFF0C\u52FF\u624B\u5DE5\u62FC\u88C5\uFF09",
37314
+ "- \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",
37315
+ "\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"
37316
+ ].join("\n")
37317
+ })
37318
+ );
37319
+ } catch (e) {
37320
+ error("systemPrompt unavailable:", e.message);
37321
+ }
37141
37322
  disposers.push(...registerRoutes(ctx2, { activation: activation2 }));
37142
37323
  try {
37143
37324
  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.1",
4
4
  "description": "DSH Literature 文献侧窗:在 DeepSeek Harness 侧边栏识别 DOI/arXiv/标题、抓取元数据与全文、写入本地文献库或导出目录,并提供内置 PDF 阅读器(缩放/翻页/目录/搜索/高亮/笔记)。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",