@a9i5k4/dsh-literature 0.2.9 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/client.js +10 -10
  2. package/lib/index.js +1461 -470
  3. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -1774,13 +1774,46 @@ __export(cite_exports, {
1774
1774
  stripItalic: () => stripItalic,
1775
1775
  toSegments: () => toSegments
1776
1776
  });
1777
- function authorsList(record, { max = 99, ellipsis = ", et al." } = {}) {
1777
+ function apaInitials(firstName) {
1778
+ const s = String(firstName ?? "").trim();
1779
+ if (!s) return "";
1780
+ return s.charAt(0).toUpperCase() + ".";
1781
+ }
1782
+ function apaAuthors(record) {
1783
+ const list = record.authors ?? [];
1784
+ if (!list.length) return "";
1785
+ const name2 = (a) => {
1786
+ if (CJK.test(a.lastName ?? "") || CJK.test(a.firstName ?? "")) return `${a.lastName ?? ""}${a.firstName ?? ""}`;
1787
+ return [a.lastName, apaInitials(a.firstName)].filter(Boolean).join(", ");
1788
+ };
1789
+ if (list.length === 1) return name2(list[0]);
1790
+ if (list.length <= 20) {
1791
+ const names = list.map(name2);
1792
+ return names.slice(0, -1).join(", ") + ", & " + names[names.length - 1];
1793
+ }
1794
+ return list.slice(0, 19).map(name2).join(", ") + ", \u2026 " + name2(list[list.length - 1]);
1795
+ }
1796
+ function mlaAuthors(record) {
1778
1797
  const list = record.authors ?? [];
1779
1798
  if (!list.length) return "";
1780
- const names = list.map((a) => [a.lastName, a.firstName].filter(Boolean).join(", "));
1781
- if (names.length === 1) return names[0];
1782
- if (names.length <= max) return names.slice(0, -1).join(", ") + ", & " + names[names.length - 1];
1783
- return names.slice(0, max).join(", ") + ellipsis;
1799
+ const inverted = (a) => [a.lastName, a.firstName].filter(Boolean).join(", ");
1800
+ const upright = (a) => [a.firstName, a.lastName].filter(Boolean).join(" ");
1801
+ if (list.length === 1) return inverted(list[0]);
1802
+ if (list.length === 2) return inverted(list[0]) + ", and " + upright(list[1]);
1803
+ return inverted(list[0]) + ", et al";
1804
+ }
1805
+ function chicagoAuthors(record) {
1806
+ const list = record.authors ?? [];
1807
+ if (!list.length) return "";
1808
+ const inverted = (a) => [a.lastName, a.firstName].filter(Boolean).join(", ");
1809
+ const upright = (a) => [a.firstName, a.lastName].filter(Boolean).join(" ");
1810
+ if (list.length === 1) return inverted(list[0]);
1811
+ if (list.length === 2) return inverted(list[0]) + ", and " + upright(list[1]);
1812
+ if (list.length <= 10) {
1813
+ const parts = [inverted(list[0]), ...list.slice(1, -1).map(upright)];
1814
+ return parts.join(", ") + ", and " + upright(list[list.length - 1]);
1815
+ }
1816
+ return list.slice(0, 7).map(inverted).join(", ") + ", et al";
1784
1817
  }
1785
1818
  function authorsShort(record) {
1786
1819
  const list = record.authors ?? [];
@@ -1800,8 +1833,8 @@ function doiUrl(record) {
1800
1833
  return record.doi ? `https://doi.org/${record.doi}` : record.url ?? "";
1801
1834
  }
1802
1835
  function apa(record) {
1803
- const authors2 = authorsList(record, { max: 20 });
1804
- const who = authors2 ? `${authors2}. ` : "";
1836
+ const authors2 = apaAuthors(record);
1837
+ const who = authors2 ? `${authors2} ` : "";
1805
1838
  const year = `(${yearStr(record)}). `;
1806
1839
  const title = (record.title ?? "Untitled").trim();
1807
1840
  if (record.itemType === "journalArticle" || record.itemType === "preprint") {
@@ -1833,10 +1866,16 @@ function apa(record) {
1833
1866
  }
1834
1867
  function gb(record) {
1835
1868
  const list = record.authors ?? [];
1869
+ const cjk = (s) => /[\u4e00-\u9fff]/.test(s ?? "");
1870
+ const gbName = (a) => {
1871
+ if (cjk(a.lastName) || cjk(a.firstName)) return `${a.lastName ?? ""}${a.firstName ?? ""}`;
1872
+ const ini = String(a.firstName ?? "").trim();
1873
+ return [a.lastName, ini ? ini.charAt(0).toUpperCase() : ""].filter(Boolean).join(" ");
1874
+ };
1836
1875
  let who;
1837
1876
  if (!list.length) who = "";
1838
- else if (list.length <= 3) who = list.map((a) => `${a.lastName}${a.firstName ? " " + a.firstName : ""}`).join(", ");
1839
- else who = `${list.slice(0, 3).map((a) => `${a.lastName}${a.firstName ? " " + a.firstName : ""}`).join(", ")}, \u7B49`;
1877
+ else if (list.length <= 3) who = list.map(gbName).join(", ");
1878
+ else who = `${list.slice(0, 3).map(gbName).join(", ")}, \u7B49`;
1840
1879
  const whoPart = who ? `${who}. ` : "";
1841
1880
  const title = (record.title ?? "").trim();
1842
1881
  const year = yearStr(record);
@@ -1865,8 +1904,8 @@ function gb(record) {
1865
1904
  return `${whoPart}${title}[Z]. ${year}.`.trim();
1866
1905
  }
1867
1906
  function mla(record) {
1868
- const list = record.authors ?? [];
1869
- const who = list.length ? list.map((a) => `${a.lastName}, ${a.firstName ?? ""}`.trim()).join(", ") + ". " : "";
1907
+ const who0 = mlaAuthors(record);
1908
+ const who = who0 ? who0 + ". " : "";
1870
1909
  const title = (record.title ?? "Untitled").trim();
1871
1910
  if (record.itemType === "journalArticle" || record.itemType === "preprint") {
1872
1911
  const journal = record.container ? ` *${record.container}*, ` : "";
@@ -1884,8 +1923,8 @@ function mla(record) {
1884
1923
  return `${who}"${title}." ${record.publisher ?? ""} ${yearStr(record)}.`.trim();
1885
1924
  }
1886
1925
  function chicago(record) {
1887
- const list = record.authors ?? [];
1888
- const who = list.length ? list.map((a) => `${a.firstName ?? ""} ${a.lastName ?? ""}`.trim()).join(", ") + ". " : "";
1926
+ const who0 = chicagoAuthors(record);
1927
+ const who = who0 ? who0 + ". " : "";
1889
1928
  const title = (record.title ?? "Untitled").trim();
1890
1929
  if (record.itemType === "journalArticle" || record.itemType === "preprint") {
1891
1930
  const journal = record.container ? ` *${record.container}*` : "";
@@ -1990,14 +2029,15 @@ function authorsShortGb(record) {
1990
2029
  if (!list.length) return "\u4F5A\u540D";
1991
2030
  if (list.length === 1) return list[0].lastName;
1992
2031
  if (list.length === 2) return `${list[0].lastName}\u3001${list[1].lastName}`;
1993
- return `${list[0].lastName}\u7B49`;
2032
+ return `${list[0].lastName} \u7B49`;
1994
2033
  }
1995
2034
  function listStyles() {
1996
2035
  return Object.entries(STYLES).map(([id, s]) => ({ id, label: s.label }));
1997
2036
  }
1998
- var STYLES;
2037
+ var CJK, STYLES;
1999
2038
  var init_cite = __esm({
2000
2039
  "src/node/cite.js"() {
2040
+ CJK = /[\u4e00-\u9fff]/;
2001
2041
  STYLES = {
2002
2042
  apa: { label: "APA 7th", format: apa },
2003
2043
  gb: { label: "GB/T 7714-2015", format: gb },
@@ -2586,6 +2626,183 @@ var init_importer = __esm({
2586
2626
  }
2587
2627
  });
2588
2628
 
2629
+ // src/node/courseware/pptx.js
2630
+ var pptx_exports = {};
2631
+ __export(pptx_exports, {
2632
+ deckToText: () => deckToText,
2633
+ parsePptx: () => parsePptx
2634
+ });
2635
+ import { readFileSync } from "node:fs";
2636
+ import { inflateRawSync } from "node:zlib";
2637
+ function readZipEntries(bytes) {
2638
+ let eocd = -1;
2639
+ for (let i = bytes.length - 22; i >= 0 && i > bytes.length - 66e3; i -= 1) {
2640
+ if (bytes.readUInt32LE(i) === EOCD_SIG) {
2641
+ eocd = i;
2642
+ break;
2643
+ }
2644
+ }
2645
+ if (eocd < 0) throw new Error("not a zip archive");
2646
+ const count = bytes.readUInt16LE(eocd + 10);
2647
+ let off = bytes.readUInt32LE(eocd + 16);
2648
+ const entries = /* @__PURE__ */ new Map();
2649
+ for (let i = 0; i < count; i += 1) {
2650
+ if (bytes.readUInt32LE(off) !== CD_SIG) break;
2651
+ const method = bytes.readUInt16LE(off + 10);
2652
+ const compSize = bytes.readUInt32LE(off + 20);
2653
+ const nameLen = bytes.readUInt16LE(off + 28);
2654
+ const extraLen = bytes.readUInt16LE(off + 30);
2655
+ const commentLen = bytes.readUInt16LE(off + 32);
2656
+ const localOff = bytes.readUInt32LE(off + 42);
2657
+ const name2 = bytes.slice(off + 46, off + 46 + nameLen).toString("utf8");
2658
+ if (bytes.readUInt32LE(localOff) === LOCAL_SIG) {
2659
+ const lNameLen = bytes.readUInt16LE(localOff + 26);
2660
+ const lExtraLen = bytes.readUInt16LE(localOff + 28);
2661
+ const dataStart = localOff + 30 + lNameLen + lExtraLen;
2662
+ const raw = bytes.slice(dataStart, dataStart + compSize);
2663
+ let data;
2664
+ try {
2665
+ data = method === 0 ? Buffer.from(raw) : inflateRawSync(raw);
2666
+ } catch {
2667
+ data = null;
2668
+ }
2669
+ entries.set(name2, data);
2670
+ }
2671
+ off += 46 + nameLen + extraLen + commentLen;
2672
+ }
2673
+ return entries;
2674
+ }
2675
+ function paragraphsFromSlideXml(xml) {
2676
+ const out = [];
2677
+ const re = /<a:p>([\s\S]*?)<\/a:p>/g;
2678
+ let m;
2679
+ while (m = re.exec(xml)) {
2680
+ const runs = [...m[1].matchAll(/<a:t>([\s\S]*?)<\/a:t>/g)].map((r) => r[1]);
2681
+ const text = runs.join("").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").trim();
2682
+ if (text) out.push(text);
2683
+ }
2684
+ return out;
2685
+ }
2686
+ function isTitleShape(shapeXml) {
2687
+ return /<p:ph[^>]*type="(?:title|ctrTitle)"/.test(shapeXml);
2688
+ }
2689
+ function aspectOf(cx, cy) {
2690
+ const r = cx / cy;
2691
+ if (r > 1.7) return "16:9";
2692
+ if (r > 1.2) return "4:3";
2693
+ return `${r.toFixed(2)}:1`;
2694
+ }
2695
+ function parseChartXml(xml) {
2696
+ const cats = [...xml.matchAll(/<c:pt idx="(\d+)">\s*<c:v>([\s\S]*?)<\/c:v>/g)];
2697
+ const catMatch = xml.match(/<c:cat>([\s\S]*?)<\/c:cat>/);
2698
+ const categories = catMatch ? [...catMatch[1].matchAll(/<c:v>([\s\S]*?)<\/c:v>/g)].map((m) => m[1].trim()) : [];
2699
+ const series = [];
2700
+ for (const m of xml.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)) {
2701
+ const name2 = m[1].match(/<c:tx>[\s\S]*?<c:v>([\s\S]*?)<\/c:v>/)?.[1]?.trim() ?? "";
2702
+ const valBlock = m[1].match(/<c:val>([\s\S]*?)<\/c:val>/)?.[1] ?? "";
2703
+ const values = [...valBlock.matchAll(/<c:v>([\s\S]*?)<\/c:v>/g)].map((v) => Number(v[1]) || 0);
2704
+ if (values.length) series.push({ name: name2, values });
2705
+ }
2706
+ return { categories, series, rawPts: cats.length };
2707
+ }
2708
+ function naturalSlideIndex(name2) {
2709
+ const m = name2.match(/slide(\d+)\.xml$/);
2710
+ return m ? Number(m[1]) : 0;
2711
+ }
2712
+ function parsePptx(input) {
2713
+ const bytes = Buffer.isBuffer(input) ? input : readFileSync(input);
2714
+ const warnings = [];
2715
+ let entries;
2716
+ try {
2717
+ entries = readZipEntries(bytes);
2718
+ } catch (e) {
2719
+ throw new Error(`\u65E0\u6CD5\u89E3\u6790\u8BE5\u6587\u4EF6\uFF1A${e.message}\uFF08\u82E5\u4E3A\u65E7\u7248 .ppt\uFF0C\u8BF7\u53E6\u5B58\u4E3A .pptx \u6216\u5BFC\u51FA PDF\uFF09`);
2720
+ }
2721
+ if (!entries.has("[Content_Types].xml")) throw new Error("\u4E0D\u662F\u6709\u6548\u7684 .pptx\uFF08\u7F3A\u5C11 OOXML \u5185\u5BB9\u7C7B\u578B\u6E05\u5355\uFF09");
2722
+ const slideNames = [...entries.keys()].filter((n) => /^ppt\/slides\/slide\d+\.xml$/.test(n)).sort((a, b) => naturalSlideIndex(a) - naturalSlideIndex(b));
2723
+ if (!slideNames.length) throw new Error("\u8BE5 .pptx \u4E2D\u6CA1\u6709\u5E7B\u706F\u7247");
2724
+ const pres = entries.get("ppt/presentation.xml")?.toString("utf8") ?? "";
2725
+ const size = pres.match(/<p:sldSz cx="(\d+)" cy="(\d+)"/);
2726
+ const aspect = size ? aspectOf(Number(size[1]), Number(size[2])) : "";
2727
+ const notesOf = /* @__PURE__ */ new Map();
2728
+ for (const name2 of entries.keys()) {
2729
+ const m = name2.match(/^ppt\/notesSlides\/notesSlide(\d+)\.xml$/);
2730
+ if (m) notesOf.set(Number(m[1]), entries.get(name2)?.toString("utf8") ?? "");
2731
+ }
2732
+ const charts = [];
2733
+ for (const name2 of [...entries.keys()].sort()) {
2734
+ const m = name2.match(/^ppt\/charts\/chart(\d+)\.xml$/);
2735
+ if (!m) continue;
2736
+ const xml = entries.get(name2)?.toString("utf8") ?? "";
2737
+ if (!xml) continue;
2738
+ const parsed = parseChartXml(xml);
2739
+ charts.push({ name: name2, ...parsed });
2740
+ }
2741
+ const slides = slideNames.map((name2) => {
2742
+ const n = naturalSlideIndex(name2);
2743
+ const xml = entries.get(name2)?.toString("utf8") ?? "";
2744
+ const shapes = [...xml.matchAll(/<p:sp>[\s\S]*?<\/p:sp>/g)].map((s) => s[0]);
2745
+ let title = "";
2746
+ const body = [];
2747
+ for (const shape of shapes) {
2748
+ const paras = paragraphsFromSlideXml(shape);
2749
+ if (!paras.length) continue;
2750
+ if (!title && isTitleShape(shape)) title = paras.join(" ");
2751
+ else body.push(...paras);
2752
+ }
2753
+ if (!title && body.length) {
2754
+ title = body.shift();
2755
+ }
2756
+ const images = [...xml.matchAll(/<p:pic>[\s\S]*?<\/p:pic>/g)].length;
2757
+ return {
2758
+ index: n,
2759
+ title: title || `\u7B2C ${n} \u9875`,
2760
+ paragraphs: body,
2761
+ notes: (() => {
2762
+ const nx = notesOf.get(n) ?? "";
2763
+ return nx ? paragraphsFromSlideXml(nx) : [];
2764
+ })(),
2765
+ images
2766
+ };
2767
+ });
2768
+ const media = [...entries.keys()].filter((n) => n.startsWith("ppt/media/")).map((n) => ({ name: n }));
2769
+ return {
2770
+ kind: "pptx",
2771
+ slideCount: slides.length,
2772
+ aspect,
2773
+ slides,
2774
+ media,
2775
+ charts,
2776
+ warnings
2777
+ };
2778
+ }
2779
+ function deckToText(parsed, { maxChars = 4e4 } = {}) {
2780
+ const parts = [];
2781
+ let total = 0;
2782
+ for (const slide of parsed.slides) {
2783
+ const lines = [`## \u7B2C ${slide.index} \u9875 \xB7 ${slide.title}`];
2784
+ lines.push(...slide.paragraphs.map((p) => `- ${p}`));
2785
+ if (slide.notes.length) lines.push(`\uFF08\u8BB2\u8005\u5907\u6CE8\uFF1A${slide.notes.join("\uFF1B")}\uFF09`);
2786
+ if (slide.images) lines.push(`\uFF08\u672C\u9875\u63D2\u56FE ${slide.images} \u5F20\uFF09`);
2787
+ const block = lines.join("\n");
2788
+ if (total + block.length > maxChars) {
2789
+ parts.push("\u2026\uFF08\u8D85\u51FA\u957F\u5EA6\u4E0A\u9650\uFF0C\u5176\u4F59\u9875\u672A\u5305\u542B\uFF09");
2790
+ break;
2791
+ }
2792
+ parts.push(block);
2793
+ total += block.length;
2794
+ }
2795
+ return parts.join("\n\n");
2796
+ }
2797
+ var EOCD_SIG, CD_SIG, LOCAL_SIG;
2798
+ var init_pptx = __esm({
2799
+ "src/node/courseware/pptx.js"() {
2800
+ EOCD_SIG = 101010256;
2801
+ CD_SIG = 33639248;
2802
+ LOCAL_SIG = 67324752;
2803
+ }
2804
+ });
2805
+
2589
2806
  // src/node/pipeline.js
2590
2807
  var pipeline_exports = {};
2591
2808
  __export(pipeline_exports, {
@@ -2593,6 +2810,7 @@ __export(pipeline_exports, {
2593
2810
  arxivBase: () => arxivBase,
2594
2811
  discardItem: () => discardItem,
2595
2812
  fetchItemPdf: () => fetchItemPdf,
2813
+ importDroppedCourseware: () => importDroppedCourseware,
2596
2814
  importDroppedPdf: () => importDroppedPdf,
2597
2815
  importPdf: () => importPdf,
2598
2816
  log: () => log,
@@ -2893,8 +3111,8 @@ async function saveItem(key, { mode, tags } = {}) {
2893
3111
  if (wantMode === "dir") {
2894
3112
  let buffer = null;
2895
3113
  if (current.pdf?.path) {
2896
- const { readFile: readFile6 } = await import("node:fs/promises");
2897
- buffer = await readFile6(current.pdf.path).catch(() => null);
3114
+ const { readFile: readFile7 } = await import("node:fs/promises");
3115
+ buffer = await readFile7(current.pdf.path).catch(() => null);
2898
3116
  }
2899
3117
  result = await exportToDirectory(current.record, buffer);
2900
3118
  const updated2 = await patchItem(key, { state: "saved", saveMode: "dir", export: result, error: null, updatedAt: Date.now() });
@@ -2904,14 +3122,14 @@ async function saveItem(key, { mode, tags } = {}) {
2904
3122
  }
2905
3123
  let pdfBuffer = null;
2906
3124
  if (current.pdf?.path) {
2907
- const { readFile: readFile6 } = await import("node:fs/promises");
2908
- pdfBuffer = await readFile6(current.pdf.path).catch(() => null);
3125
+ const { readFile: readFile7 } = await import("node:fs/promises");
3126
+ pdfBuffer = await readFile7(current.pdf.path).catch(() => null);
2909
3127
  }
2910
3128
  if (!pdfBuffer) {
2911
3129
  const fetched = await fetchItemPdf(key);
2912
3130
  if (fetched?.pdf?.path) {
2913
- const { readFile: readFile6 } = await import("node:fs/promises");
2914
- pdfBuffer = await readFile6(fetched.pdf.path).catch(() => null);
3131
+ const { readFile: readFile7 } = await import("node:fs/promises");
3132
+ pdfBuffer = await readFile7(fetched.pdf.path).catch(() => null);
2915
3133
  } else {
2916
3134
  const err = fetched?.error ?? failure("fetch_failed", "\u65E0\u6CD5\u83B7\u53D6\u5168\u6587 PDF\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u5230\u6587\u732E\u5E93");
2917
3135
  throw Object.assign(new Error(err.message), { code: err.code ?? "fetch_failed", detail: err.detail });
@@ -3048,6 +3266,48 @@ async function importDroppedPdf(buffer, { filename = "dropped.pdf" } = {}) {
3048
3266
  emitItem(saved);
3049
3267
  return saved;
3050
3268
  }
3269
+ async function importDroppedCourseware(buffer, { filename = "deck.pptx" } = {}) {
3270
+ if (!buffer || buffer.length < 4 || buffer.subarray(0, 2).toString("latin1") !== "PK") {
3271
+ throw failure("network", "\u62D6\u5165\u7684\u6587\u4EF6\u4E0D\u662F\u6709\u6548\u7684 .pptx\uFF08\u65E7\u7248 .ppt \u8BF7\u5148\u53E6\u5B58\u4E3A .pptx \u6216\u5BFC\u51FA PDF\uFF09");
3272
+ }
3273
+ const { parsePptx: parsePptx2, deckToText: deckToText2 } = await Promise.resolve().then(() => (init_pptx(), pptx_exports));
3274
+ let parsed;
3275
+ try {
3276
+ parsed = parsePptx2(buffer);
3277
+ } catch (e) {
3278
+ throw failure("network", e?.message ?? "\u8BFE\u4EF6\u89E3\u6790\u5931\u8D25");
3279
+ }
3280
+ const base = String(filename).replace(/\.pptx$/i, "");
3281
+ const title = parsed.slides[0]?.title && parsed.slides[0].title !== "\u7B2C 1 \u9875" ? parsed.slides[0].title : base;
3282
+ const key = `cw_${randomUUID2().slice(0, 8)}`;
3283
+ const path = join5(PDF_DIR, `${key.replace(/[^\w.-]+/g, "_")}.pptx`);
3284
+ await mkdir4(dirname3(path), { recursive: true });
3285
+ await writeFile4(path, buffer);
3286
+ const item = await putItem({
3287
+ key,
3288
+ kind: "courseware",
3289
+ display: title,
3290
+ title,
3291
+ sourceFile: filename,
3292
+ state: "fetched",
3293
+ courseware: {
3294
+ format: "pptx",
3295
+ path,
3296
+ filename,
3297
+ slideCount: parsed.slideCount,
3298
+ aspect: parsed.aspect,
3299
+ outline: parsed.slides.map((s) => ({ index: s.index, title: s.title })),
3300
+ charts: parsed.charts.map((c) => ({ name: c.name, categories: c.categories, series: c.series })),
3301
+ mediaCount: parsed.media.length,
3302
+ text: deckToText2(parsed, { maxChars: 6e4 })
3303
+ },
3304
+ pdf: { path, size: buffer.length, source: "courseware-import", url: "", filename },
3305
+ tags: ["\u8BFE\u4EF6"],
3306
+ createdAt: Date.now()
3307
+ });
3308
+ emitItem(item);
3309
+ return item;
3310
+ }
3051
3311
  var FAILURE_MESSAGES;
3052
3312
  var init_pipeline = __esm({
3053
3313
  "src/node/pipeline.js"() {
@@ -3096,6 +3356,118 @@ var init_session_track = __esm({
3096
3356
  }
3097
3357
  });
3098
3358
 
3359
+ // src/node/pyenv.js
3360
+ var pyenv_exports = {};
3361
+ __export(pyenv_exports, {
3362
+ detectPythons: () => detectPythons,
3363
+ figureInterpreter: () => figureInterpreter,
3364
+ installFigureDeps: () => installFigureDeps,
3365
+ venvDir: () => venvDir,
3366
+ venvExists: () => venvExists
3367
+ });
3368
+ import { execFile } from "node:child_process";
3369
+ import { existsSync, readdirSync } from "node:fs";
3370
+ import { join as join6 } from "node:path";
3371
+ import { homedir as homedir3 } from "node:os";
3372
+ function run(cmd, args, { timeout = 2e4 } = {}) {
3373
+ return new Promise((resolve6) => {
3374
+ execFile(cmd, args, { timeout, windowsHide: true }, (err, stdout, stderr) => {
3375
+ resolve6({ ok: !err, out: String(stdout ?? "").trim(), err: String(stderr ?? "").trim(), code: err?.code });
3376
+ });
3377
+ });
3378
+ }
3379
+ async function probe(exe) {
3380
+ const v = await run(exe, ["--version"]);
3381
+ if (!v.ok) return null;
3382
+ const cap = await run(exe, ["-c", 'import venv, ensurepip; print("ok")']);
3383
+ const mpl = await run(exe, ["-c", "import matplotlib; print(matplotlib.__version__)"]);
3384
+ return {
3385
+ exe,
3386
+ version: v.out.split(" ").pop() ?? "",
3387
+ venvCapable: cap.ok,
3388
+ hasMatplotlib: mpl.ok,
3389
+ matplotlibVersion: mpl.ok ? mpl.out : ""
3390
+ };
3391
+ }
3392
+ async function detectPythons({ force = false } = {}) {
3393
+ if (!force && cache.pythons.length && Date.now() - cache.at < CACHE_MS) return cache.pythons;
3394
+ const candidates2 = [];
3395
+ const tryPush = async (exe) => {
3396
+ if (!exe || candidates2.some((c) => c.exe === exe)) return;
3397
+ const p = await probe(exe);
3398
+ if (p) candidates2.push(p);
3399
+ };
3400
+ if (process.platform === "win32") {
3401
+ const py = await run("py", ["-0p"]);
3402
+ if (py.ok) {
3403
+ for (const line of py.out.split("\n")) {
3404
+ const m = line.match(/[-*]\s*(?:Version: .*)?(?:\|\s*)?(.+\.exe)\s*$/i) ?? line.match(/([A-Za-z]:\\[^\s]+python\.exe)/i);
3405
+ if (m?.[1]) await tryPush(m[1].trim());
3406
+ }
3407
+ }
3408
+ }
3409
+ await tryPush("python");
3410
+ await tryPush("python3");
3411
+ if (process.env.WORKBUDDY_PY) await tryPush(process.env.WORKBUDDY_PY);
3412
+ const managed = join6(homedir3(), ".workbuddy", "binaries", "python", "versions");
3413
+ if (existsSync(managed)) {
3414
+ try {
3415
+ for (const v of readdirSync(managed).sort().reverse()) {
3416
+ await tryPush(join6(managed, v, "python.exe"));
3417
+ await tryPush(join6(managed, v, "bin", "python3"));
3418
+ }
3419
+ } catch {
3420
+ }
3421
+ }
3422
+ cache = { at: Date.now(), pythons: candidates2 };
3423
+ return candidates2;
3424
+ }
3425
+ function venvDir() {
3426
+ return join6(homedir3(), ".dsh", "dsh-literature", "pyvenv");
3427
+ }
3428
+ function venvPython(dir = venvDir()) {
3429
+ return process.platform === "win32" ? join6(dir, "Scripts", "python.exe") : join6(dir, "bin", "python");
3430
+ }
3431
+ function venvExists(dir = venvDir()) {
3432
+ return existsSync(venvPython(dir));
3433
+ }
3434
+ async function figureInterpreter() {
3435
+ if (venvExists()) {
3436
+ const p = await probe(venvPython());
3437
+ if (p?.hasMatplotlib) return { ...p, source: "venv" };
3438
+ if (p) return { ...p, source: "venv", hasMatplotlib: false };
3439
+ }
3440
+ for (const p of await detectPythons()) {
3441
+ if (p.hasMatplotlib) return { ...p, source: "system" };
3442
+ }
3443
+ return null;
3444
+ }
3445
+ async function installFigureDeps(onLog = () => {
3446
+ }) {
3447
+ const pythons = await detectPythons({ force: true });
3448
+ const base = pythons.find((p) => p.venvCapable);
3449
+ if (!base) return { ok: false, error: "\u672A\u627E\u5230\u53EF\u7528\u7684 Python\uFF08\u9700\u8981\u5E26 venv \u6A21\u5757\u7684 Python 3.8+\uFF09" };
3450
+ const dir = venvDir();
3451
+ if (!venvExists(dir)) {
3452
+ onLog("\u521B\u5EFA\u865A\u62DF\u73AF\u5883\u2026");
3453
+ const r2 = await run(base.exe, ["-m", "venv", dir], { timeout: 12e4 });
3454
+ if (!r2.ok) return { ok: false, error: "venv \u521B\u5EFA\u5931\u8D25\uFF1A" + (r2.err || r2.out) };
3455
+ }
3456
+ const py = venvPython(dir);
3457
+ onLog("\u5B89\u88C5 matplotlib\u2026");
3458
+ const r = await run(py, ["-m", "pip", "install", "--disable-pip-version-check", "matplotlib"], { timeout: 3e5 });
3459
+ if (!r.ok) return { ok: false, error: "matplotlib \u5B89\u88C5\u5931\u8D25\uFF1A" + (r.err || r.out).slice(0, 400) };
3460
+ cache = { at: 0, pythons: [] };
3461
+ return { ok: true, python: py, dir };
3462
+ }
3463
+ var CACHE_MS, cache;
3464
+ var init_pyenv = __esm({
3465
+ "src/node/pyenv.js"() {
3466
+ CACHE_MS = 6e4;
3467
+ cache = { at: 0, pythons: [] };
3468
+ }
3469
+ });
3470
+
3099
3471
  // node_modules/pdfjs-dist/legacy/build/pdf.mjs
3100
3472
  var pdf_exports = {};
3101
3473
  __export(pdf_exports, {
@@ -3543,7 +3915,7 @@ function getColorValues(colors) {
3543
3915
  }
3544
3916
  span.remove();
3545
3917
  }
3546
- function getCurrentTransform(ctx) {
3918
+ function getCurrentTransform(ctx2) {
3547
3919
  const {
3548
3920
  a,
3549
3921
  b,
@@ -3551,10 +3923,10 @@ function getCurrentTransform(ctx) {
3551
3923
  d,
3552
3924
  e,
3553
3925
  f
3554
- } = ctx.getTransform();
3926
+ } = ctx2.getTransform();
3555
3927
  return [a, b, c, d, e, f];
3556
3928
  }
3557
- function getCurrentTransformInverse(ctx) {
3929
+ function getCurrentTransformInverse(ctx2) {
3558
3930
  const {
3559
3931
  a,
3560
3932
  b,
@@ -3562,7 +3934,7 @@ function getCurrentTransformInverse(ctx) {
3562
3934
  d,
3563
3935
  e,
3564
3936
  f
3565
- } = ctx.getTransform().invertSelf();
3937
+ } = ctx2.getTransform().invertSelf();
3566
3938
  return [a, b, c, d, e, f];
3567
3939
  }
3568
3940
  function setLayerDimensions(div, viewport, mustFlip = false, mustRotate = true) {
@@ -4010,7 +4382,7 @@ function loadMeshShader() {
4010
4382
  function drawMeshWithGPU(posData, colData, vertexCount, context, backgroundColor, paddedWidth, paddedHeight, borderSize) {
4011
4383
  return _webGPU.draw(posData, colData, vertexCount, context, backgroundColor, paddedWidth, paddedHeight, borderSize);
4012
4384
  }
4013
- function applyBoundingBox(ctx, bbox) {
4385
+ function applyBoundingBox(ctx2, bbox) {
4014
4386
  if (!bbox) {
4015
4387
  return;
4016
4388
  }
@@ -4018,7 +4390,7 @@ function applyBoundingBox(ctx, bbox) {
4018
4390
  const height = bbox[3] - bbox[1];
4019
4391
  const region = new Path2D();
4020
4392
  region.rect(bbox[0], bbox[1], width, height);
4021
- ctx.clip(region);
4393
+ ctx2.clip(region);
4022
4394
  }
4023
4395
  function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
4024
4396
  const coords = context.coords, colors = context.colors;
@@ -4124,31 +4496,31 @@ function getShadingPattern(IR) {
4124
4496
  }
4125
4497
  throw new Error(`Unknown IR type: ${IR[0]}`);
4126
4498
  }
4127
- function mirrorContextOperations(ctx, destCtx) {
4128
- if (ctx._removeMirroring) {
4499
+ function mirrorContextOperations(ctx2, destCtx) {
4500
+ if (ctx2._removeMirroring) {
4129
4501
  throw new Error("Context is already forwarding operations.");
4130
4502
  }
4131
4503
  const originalMethods = /* @__PURE__ */ new Map();
4132
4504
  for (const name2 of ["save", "restore", "rotate", "scale", "translate", "transform", "setTransform", "resetTransform", "clip", "moveTo", "lineTo", "bezierCurveTo", "quadraticCurveTo", "arc", "arcTo", "ellipse", "rect", "roundRect", "closePath", "beginPath"]) {
4133
- const original = ctx[name2];
4505
+ const original = ctx2[name2];
4134
4506
  if (typeof original !== "function" || typeof destCtx[name2] !== "function") {
4135
4507
  continue;
4136
4508
  }
4137
4509
  originalMethods.set(name2, original);
4138
- ctx[name2] = function(...args) {
4510
+ ctx2[name2] = function(...args) {
4139
4511
  destCtx[name2](...args);
4140
4512
  return original.apply(this, args);
4141
4513
  };
4142
4514
  }
4143
- ctx._removeMirroring = () => {
4515
+ ctx2._removeMirroring = () => {
4144
4516
  for (const [name2, original] of originalMethods) {
4145
- ctx[name2] = original;
4517
+ ctx2[name2] = original;
4146
4518
  }
4147
- delete ctx._removeMirroring;
4519
+ delete ctx2._removeMirroring;
4148
4520
  };
4149
4521
  }
4150
- function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) {
4151
- const [a, b, c, d, tx, ty] = getCurrentTransform(ctx);
4522
+ function drawImageAtIntegerCoords(ctx2, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) {
4523
+ const [a, b, c, d, tx, ty] = getCurrentTransform(ctx2);
4152
4524
  if (b === 0 && c === 0) {
4153
4525
  const tlX = destX * a + tx;
4154
4526
  const rTlX = Math.round(tlX);
@@ -4158,9 +4530,9 @@ function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, de
4158
4530
  const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
4159
4531
  const brY = (destY + destH) * d + ty;
4160
4532
  const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
4161
- ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY);
4162
- ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight);
4163
- ctx.setTransform(a, b, c, d, tx, ty);
4533
+ ctx2.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY);
4534
+ ctx2.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight);
4535
+ ctx2.setTransform(a, b, c, d, tx, ty);
4164
4536
  return [rWidth, rHeight];
4165
4537
  }
4166
4538
  if (a === 0 && d === 0) {
@@ -4172,17 +4544,17 @@ function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, de
4172
4544
  const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
4173
4545
  const brY = (destX + destW) * b + ty;
4174
4546
  const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
4175
- ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY);
4176
- ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth);
4177
- ctx.setTransform(a, b, c, d, tx, ty);
4547
+ ctx2.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY);
4548
+ ctx2.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth);
4549
+ ctx2.setTransform(a, b, c, d, tx, ty);
4178
4550
  return [rHeight, rWidth];
4179
4551
  }
4180
- ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
4552
+ ctx2.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
4181
4553
  const scaleX = Math.hypot(a, b);
4182
4554
  const scaleY = Math.hypot(c, d);
4183
4555
  return [scaleX * destW, scaleY * destH];
4184
4556
  }
4185
- function putBinaryImageData(ctx, imgData) {
4557
+ function putBinaryImageData(ctx2, imgData) {
4186
4558
  const {
4187
4559
  width,
4188
4560
  height,
@@ -4191,7 +4563,7 @@ function putBinaryImageData(ctx, imgData) {
4191
4563
  const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
4192
4564
  const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
4193
4565
  const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
4194
- const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
4566
+ const chunkImgData = ctx2.createImageData(width, FULL_CHUNK_HEIGHT);
4195
4567
  let srcPos = 0;
4196
4568
  const src = imgData.data;
4197
4569
  const dest = chunkImgData.data;
@@ -4207,7 +4579,7 @@ function putBinaryImageData(ctx, imgData) {
4207
4579
  width,
4208
4580
  height: i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight
4209
4581
  }));
4210
- ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
4582
+ ctx2.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
4211
4583
  }
4212
4584
  } else if (kind === ImageKind.RGBA_32BPP) {
4213
4585
  let j = 0;
@@ -4215,13 +4587,13 @@ function putBinaryImageData(ctx, imgData) {
4215
4587
  for (i = 0; i < fullChunks; i++) {
4216
4588
  dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
4217
4589
  srcPos += elemsInThisChunk;
4218
- ctx.putImageData(chunkImgData, 0, j);
4590
+ ctx2.putImageData(chunkImgData, 0, j);
4219
4591
  j += FULL_CHUNK_HEIGHT;
4220
4592
  }
4221
4593
  if (i < totalChunks) {
4222
4594
  elemsInThisChunk = width * partialChunkHeight * 4;
4223
4595
  dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
4224
- ctx.putImageData(chunkImgData, 0, j);
4596
+ ctx2.putImageData(chunkImgData, 0, j);
4225
4597
  }
4226
4598
  } else if (kind === ImageKind.RGB_24BPP) {
4227
4599
  for (i = 0; i < totalChunks; i++) {
@@ -4234,15 +4606,15 @@ function putBinaryImageData(ctx, imgData) {
4234
4606
  width,
4235
4607
  height: i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight
4236
4608
  }));
4237
- ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
4609
+ ctx2.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
4238
4610
  }
4239
4611
  } else {
4240
4612
  throw new Error(`bad image kind: ${kind}`);
4241
4613
  }
4242
4614
  }
4243
- function putBinaryImageMask(ctx, imgData) {
4615
+ function putBinaryImageMask(ctx2, imgData) {
4244
4616
  if (imgData.bitmap) {
4245
- ctx.drawImage(imgData.bitmap, 0, 0);
4617
+ ctx2.drawImage(imgData.bitmap, 0, 0);
4246
4618
  return;
4247
4619
  }
4248
4620
  const {
@@ -4252,7 +4624,7 @@ function putBinaryImageMask(ctx, imgData) {
4252
4624
  const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
4253
4625
  const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
4254
4626
  const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
4255
- const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
4627
+ const chunkImgData = ctx2.createImageData(width, FULL_CHUNK_HEIGHT);
4256
4628
  let srcPos = 0;
4257
4629
  const src = imgData.data;
4258
4630
  const dest = chunkImgData.data;
@@ -4267,7 +4639,7 @@ function putBinaryImageMask(ctx, imgData) {
4267
4639
  height: i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight,
4268
4640
  nonBlackColor: 0
4269
4641
  }));
4270
- ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
4642
+ ctx2.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
4271
4643
  }
4272
4644
  }
4273
4645
  function copyCtxState(sourceCtx, destCtx) {
@@ -4282,25 +4654,25 @@ function copyCtxState(sourceCtx, destCtx) {
4282
4654
  destCtx.lineDashOffset = sourceCtx.lineDashOffset;
4283
4655
  }
4284
4656
  }
4285
- function resetCtxToDefault(ctx) {
4286
- ctx.strokeStyle = ctx.fillStyle = "#000000";
4287
- ctx.fillRule = "nonzero";
4288
- ctx.globalAlpha = 1;
4289
- ctx.lineWidth = 1;
4290
- ctx.lineCap = "butt";
4291
- ctx.lineJoin = "miter";
4292
- ctx.miterLimit = 10;
4293
- ctx.globalCompositeOperation = "source-over";
4294
- ctx.font = "10px sans-serif";
4295
- if (ctx.setLineDash !== void 0) {
4296
- ctx.setLineDash([]);
4297
- ctx.lineDashOffset = 0;
4657
+ function resetCtxToDefault(ctx2) {
4658
+ ctx2.strokeStyle = ctx2.fillStyle = "#000000";
4659
+ ctx2.fillRule = "nonzero";
4660
+ ctx2.globalAlpha = 1;
4661
+ ctx2.lineWidth = 1;
4662
+ ctx2.lineCap = "butt";
4663
+ ctx2.lineJoin = "miter";
4664
+ ctx2.miterLimit = 10;
4665
+ ctx2.globalCompositeOperation = "source-over";
4666
+ ctx2.font = "10px sans-serif";
4667
+ if (ctx2.setLineDash !== void 0) {
4668
+ ctx2.setLineDash([]);
4669
+ ctx2.lineDashOffset = 0;
4298
4670
  }
4299
4671
  const {
4300
4672
  filter
4301
- } = ctx;
4673
+ } = ctx2;
4302
4674
  if (filter !== "none" && filter !== "") {
4303
- ctx.filter = "none";
4675
+ ctx2.filter = "none";
4304
4676
  }
4305
4677
  }
4306
4678
  function getImageSmoothingEnabled(transform, interpolate) {
@@ -5950,10 +6322,10 @@ var init_pdf2 = __esm({
5950
6322
  var isCallable = __webpack_require__2(4901);
5951
6323
  var replacement = /#|\.prototype\./;
5952
6324
  var isForced = function(feature, detection) {
5953
- var value = data[normalize(feature)];
6325
+ var value = data[normalize2(feature)];
5954
6326
  return value === POLYFILL ? true : value === NATIVE ? false : isCallable(detection) ? fails(detection) : !!detection;
5955
6327
  };
5956
- var normalize = isForced.normalize = function(string) {
6328
+ var normalize2 = isForced.normalize = function(string) {
5957
6329
  return String(string).replace(replacement, ".").toLowerCase();
5958
6330
  };
5959
6331
  var data = isForced.data = {};
@@ -6323,7 +6695,7 @@ var init_pdf2 = __esm({
6323
6695
  var defineProperty = Object.defineProperty;
6324
6696
  var stringSlice = uncurryThis("".slice);
6325
6697
  var replace = uncurryThis("".replace);
6326
- var join7 = uncurryThis([].join);
6698
+ var join9 = uncurryThis([].join);
6327
6699
  var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
6328
6700
  return defineProperty(function() {
6329
6701
  }, "length", { value: 8 }).length !== 8;
@@ -6350,7 +6722,7 @@ var init_pdf2 = __esm({
6350
6722
  }
6351
6723
  var state2 = enforceInternalState(value);
6352
6724
  if (!hasOwn(state2, "source")) {
6353
- state2.source = join7(TEMPLATE, typeof name2 == "string" ? name2 : "");
6725
+ state2.source = join9(TEMPLATE, typeof name2 == "string" ? name2 : "");
6354
6726
  }
6355
6727
  return value;
6356
6728
  };
@@ -8873,7 +9245,7 @@ var init_pdf2 = __esm({
8873
9245
  var charAt = uncurryThis("".charAt);
8874
9246
  var Uint8Array2 = globalThis2.Uint8Array;
8875
9247
  var $Array = globalThis2.Array;
8876
- var join7 = uncurryThis([].join);
9248
+ var join9 = uncurryThis([].join);
8877
9249
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
8878
9250
  try {
8879
9251
  var target = new Uint8Array2();
@@ -8919,7 +9291,7 @@ var init_pdf2 = __esm({
8919
9291
  result[written++] = "=";
8920
9292
  }
8921
9293
  }
8922
- return join7(result, "");
9294
+ return join9(result, "");
8923
9295
  }
8924
9296
  });
8925
9297
  },
@@ -8931,7 +9303,7 @@ var init_pdf2 = __esm({
8931
9303
  var anUint8Array = __webpack_require__2(4154);
8932
9304
  var notDetached = __webpack_require__2(5169);
8933
9305
  var numberToString = uncurryThis(1.1.toString);
8934
- var join7 = uncurryThis([].join);
9306
+ var join9 = uncurryThis([].join);
8935
9307
  var $Array = Array;
8936
9308
  var Uint8Array2 = globalThis2.Uint8Array;
8937
9309
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
@@ -8951,7 +9323,7 @@ var init_pdf2 = __esm({
8951
9323
  var hex = numberToString(this[i], 16);
8952
9324
  result[i] = hex.length === 1 ? "0" + hex : hex;
8953
9325
  }
8954
- return join7(result, "");
9326
+ return join9(result, "");
8955
9327
  }
8956
9328
  });
8957
9329
  },
@@ -9430,13 +9802,13 @@ var init_pdf2 = __esm({
9430
9802
  });
9431
9803
  }
9432
9804
  static get isCanvasFilterSupported() {
9433
- let ctx;
9805
+ let ctx2;
9434
9806
  if (this.isOffscreenCanvasSupported) {
9435
- ctx = new OffscreenCanvas(1, 1).getContext("2d");
9807
+ ctx2 = new OffscreenCanvas(1, 1).getContext("2d");
9436
9808
  } else if (typeof document !== "undefined") {
9437
- ctx = document.createElement("canvas").getContext("2d");
9809
+ ctx2 = document.createElement("canvas").getContext("2d");
9438
9810
  }
9439
- return shadow(this, "isCanvasFilterSupported", ctx?.filter !== void 0);
9811
+ return shadow(this, "isCanvasFilterSupported", ctx2?.filter !== void 0);
9440
9812
  }
9441
9813
  static get isAlphaColorInputSupported() {
9442
9814
  if (typeof document === "undefined") {
@@ -10583,14 +10955,14 @@ var init_pdf2 = __esm({
10583
10955
  static get _isSVGFittingCanvas() {
10584
10956
  const svg = `data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 1 1" width="1" height="1" xmlns="${SVG_NS}"><rect width="1" height="1" style="fill:red;"/></svg>`;
10585
10957
  const canvas = new OffscreenCanvas(1, 3);
10586
- const ctx = canvas.getContext("2d", {
10958
+ const ctx2 = canvas.getContext("2d", {
10587
10959
  willReadFrequently: true
10588
10960
  });
10589
10961
  const image = new Image();
10590
10962
  image.src = svg;
10591
10963
  const promise = image.decode().then(() => {
10592
- ctx.drawImage(image, 0, 0, 1, 1, 0, 0, 1, 3);
10593
- return new Uint32Array(ctx.getImageData(0, 0, 1, 1).data.buffer)[0] === 0;
10964
+ ctx2.drawImage(image, 0, 0, 1, 1, 0, 0, 1, 3);
10965
+ return new Uint32Array(ctx2.getImageData(0, 0, 1, 1).data.buffer)[0] === 0;
10594
10966
  });
10595
10967
  return shadow(this, "_isSVGFittingCanvas", promise);
10596
10968
  }
@@ -10698,8 +11070,8 @@ var init_pdf2 = __esm({
10698
11070
  return data;
10699
11071
  }
10700
11072
  const offscreen = new OffscreenCanvas(canvas.width, canvas.height);
10701
- const ctx = offscreen.getContext("2d");
10702
- ctx.drawImage(canvas, 0, 0);
11073
+ const ctx2 = offscreen.getContext("2d");
11074
+ ctx2.drawImage(canvas, 0, 0);
10703
11075
  data = {
10704
11076
  bitmap: offscreen.transferToImageBitmap(),
10705
11077
  id: `image_${this.#baseId}_${this.#id++}`,
@@ -10732,8 +11104,8 @@ var init_pdf2 = __esm({
10732
11104
  } = data;
10733
11105
  if (!data.url && !data.file) {
10734
11106
  const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
10735
- const ctx = canvas.getContext("bitmaprenderer");
10736
- ctx.transferFromImageBitmap(bitmap);
11107
+ const ctx2 = canvas.getContext("bitmaprenderer");
11108
+ ctx2.transferFromImageBitmap(bitmap);
10737
11109
  data.blobPromise = canvas.convertToBlob();
10738
11110
  }
10739
11111
  bitmap.close?.();
@@ -15630,8 +16002,8 @@ var init_pdf2 = __esm({
15630
16002
  }
15631
16003
  return this;
15632
16004
  }
15633
- pushBaseTransform(ctx) {
15634
- this.#baseTransformStack.push(Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx.getTransform()));
16005
+ pushBaseTransform(ctx2) {
16006
+ this.#baseTransformStack.push(Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx2.getTransform()));
15635
16007
  return this;
15636
16008
  }
15637
16009
  popBaseTransform() {
@@ -15647,8 +16019,8 @@ var init_pdf2 = __esm({
15647
16019
  }
15648
16020
  return this;
15649
16021
  }
15650
- recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
15651
- const transform = Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx.getTransform());
16022
+ recordClipBox(idx, ctx2, minX, maxX, minY, maxY) {
16023
+ const transform = Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx2.getTransform());
15652
16024
  const clipBox = BBOX_INIT.slice();
15653
16025
  Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, clipBox);
15654
16026
  const intersection = Util.intersect(this.#clipBox, clipBox);
@@ -15663,12 +16035,12 @@ var init_pdf2 = __esm({
15663
16035
  }
15664
16036
  return this;
15665
16037
  }
15666
- recordBBox(idx, ctx, minX, maxX, minY, maxY) {
16038
+ recordBBox(idx, ctx2, minX, maxX, minY, maxY) {
15667
16039
  const clipBox = this.#clipBox;
15668
16040
  if (clipBox[0] === Infinity) {
15669
16041
  return this;
15670
16042
  }
15671
- const transform = Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx.getTransform());
16043
+ const transform = Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx2.getTransform());
15672
16044
  if (clipBox[0] === -Infinity) {
15673
16045
  Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, this.#pendingBBox);
15674
16046
  return this;
@@ -15751,7 +16123,7 @@ var init_pdf2 = __esm({
15751
16123
  inheritPendingDependenciesAsFutureForcedDependencies() {
15752
16124
  return this;
15753
16125
  }
15754
- recordCharacterBBox(idx, ctx, font, scale = 1, x = 0, y = 0, getMeasure) {
16126
+ recordCharacterBBox(idx, ctx2, font, scale = 1, x = 0, y = 0, getMeasure) {
15755
16127
  return this;
15756
16128
  }
15757
16129
  getSimpleIndex(dependencyName) {
@@ -15850,8 +16222,8 @@ var init_pdf2 = __esm({
15850
16222
  this.#bboxTracker.endMarkedContent(opIdx, this.#recordDebugMetadataDepenencyAfterRestore);
15851
16223
  return this;
15852
16224
  }
15853
- pushBaseTransform(ctx) {
15854
- this.#bboxTracker.pushBaseTransform(ctx);
16225
+ pushBaseTransform(ctx2) {
16226
+ this.#bboxTracker.pushBaseTransform(ctx2);
15855
16227
  return this;
15856
16228
  }
15857
16229
  popBaseTransform() {
@@ -15899,15 +16271,15 @@ var init_pdf2 = __esm({
15899
16271
  this.#bboxTracker.resetBBox(idx);
15900
16272
  return this;
15901
16273
  }
15902
- recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
15903
- this.#bboxTracker.recordClipBox(idx, ctx, minX, maxX, minY, maxY);
16274
+ recordClipBox(idx, ctx2, minX, maxX, minY, maxY) {
16275
+ this.#bboxTracker.recordClipBox(idx, ctx2, minX, maxX, minY, maxY);
15904
16276
  return this;
15905
16277
  }
15906
- recordBBox(idx, ctx, minX, maxX, minY, maxY) {
15907
- this.#bboxTracker.recordBBox(idx, ctx, minX, maxX, minY, maxY);
16278
+ recordBBox(idx, ctx2, minX, maxX, minY, maxY) {
16279
+ this.#bboxTracker.recordBBox(idx, ctx2, minX, maxX, minY, maxY);
15908
16280
  return this;
15909
16281
  }
15910
- recordCharacterBBox(idx, ctx, font, scale = 1, x = 0, y = 0, getMeasure) {
16282
+ recordCharacterBBox(idx, ctx2, font, scale = 1, x = 0, y = 0, getMeasure) {
15911
16283
  const fontBBox = font.bbox;
15912
16284
  let isBBoxTrustworthy;
15913
16285
  let computedBBox;
@@ -15920,7 +16292,7 @@ var init_pdf2 = __esm({
15920
16292
  scaleCharBBox(scale, -scale, x, y, computedBBox);
15921
16293
  }
15922
16294
  if (isBBoxTrustworthy) {
15923
- return this.recordBBox(idx, ctx, computedBBox[0], computedBBox[2], computedBBox[1], computedBBox[3]);
16295
+ return this.recordBBox(idx, ctx2, computedBBox[0], computedBBox[2], computedBBox[1], computedBBox[3]);
15924
16296
  }
15925
16297
  }
15926
16298
  }
@@ -15932,10 +16304,10 @@ var init_pdf2 = __esm({
15932
16304
  isBBoxTrustworthy = computedBBox[0] <= x - measure.actualBoundingBoxLeft && computedBBox[2] >= x + measure.actualBoundingBoxRight && computedBBox[1] <= y - measure.actualBoundingBoxAscent && computedBBox[3] >= y + measure.actualBoundingBoxDescent;
15933
16305
  this.#fontBBoxTrustworthy.set(font, isBBoxTrustworthy);
15934
16306
  if (isBBoxTrustworthy) {
15935
- return this.recordBBox(idx, ctx, computedBBox[0], computedBBox[2], computedBBox[1], computedBBox[3]);
16307
+ return this.recordBBox(idx, ctx2, computedBBox[0], computedBBox[2], computedBBox[1], computedBBox[3]);
15936
16308
  }
15937
16309
  }
15938
- return this.recordBBox(idx, ctx, x - measure.actualBoundingBoxLeft, x + measure.actualBoundingBoxRight, y - measure.actualBoundingBoxAscent, y + measure.actualBoundingBoxDescent);
16310
+ return this.recordBBox(idx, ctx2, x - measure.actualBoundingBoxLeft, x + measure.actualBoundingBoxRight, y - measure.actualBoundingBoxAscent, y + measure.actualBoundingBoxDescent);
15939
16311
  }
15940
16312
  recordFullPageBBox(idx) {
15941
16313
  this.#bboxTracker.recordFullPageBBox(idx);
@@ -16057,8 +16429,8 @@ var init_pdf2 = __esm({
16057
16429
  endMarkedContent(opIdx) {
16058
16430
  return this;
16059
16431
  }
16060
- pushBaseTransform(ctx) {
16061
- this.#dependencyTracker.pushBaseTransform(ctx);
16432
+ pushBaseTransform(ctx2) {
16433
+ this.#dependencyTracker.pushBaseTransform(ctx2);
16062
16434
  return this;
16063
16435
  }
16064
16436
  popBaseTransform() {
@@ -16102,21 +16474,21 @@ var init_pdf2 = __esm({
16102
16474
  }
16103
16475
  return this;
16104
16476
  }
16105
- recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
16477
+ recordClipBox(idx, ctx2, minX, maxX, minY, maxY) {
16106
16478
  if (!this.#ignoreBBoxes) {
16107
- this.#dependencyTracker.recordClipBox(this.#opIdx, ctx, minX, maxX, minY, maxY);
16479
+ this.#dependencyTracker.recordClipBox(this.#opIdx, ctx2, minX, maxX, minY, maxY);
16108
16480
  }
16109
16481
  return this;
16110
16482
  }
16111
- recordBBox(idx, ctx, minX, maxX, minY, maxY) {
16483
+ recordBBox(idx, ctx2, minX, maxX, minY, maxY) {
16112
16484
  if (!this.#ignoreBBoxes) {
16113
- this.#dependencyTracker.recordBBox(this.#opIdx, ctx, minX, maxX, minY, maxY);
16485
+ this.#dependencyTracker.recordBBox(this.#opIdx, ctx2, minX, maxX, minY, maxY);
16114
16486
  }
16115
16487
  return this;
16116
16488
  }
16117
- recordCharacterBBox(idx, ctx, font, scale, x, y, getMeasure) {
16489
+ recordCharacterBBox(idx, ctx2, font, scale, x, y, getMeasure) {
16118
16490
  if (!this.#ignoreBBoxes) {
16119
- this.#dependencyTracker.recordCharacterBBox(this.#opIdx, ctx, font, scale, x, y, getMeasure);
16491
+ this.#dependencyTracker.recordCharacterBBox(this.#opIdx, ctx2, font, scale, x, y, getMeasure);
16120
16492
  }
16121
16493
  return this;
16122
16494
  }
@@ -16178,14 +16550,14 @@ var init_pdf2 = __esm({
16178
16550
  this.#canvasWidth = canvas.width;
16179
16551
  this.#canvasHeight = canvas.height;
16180
16552
  }
16181
- record(ctx, width, height, clipBox) {
16553
+ record(ctx2, width, height, clipBox) {
16182
16554
  if (this.#count === this.#capacity) {
16183
16555
  this.#capacity *= 2;
16184
16556
  const newCoords = new _CanvasImagesTracker.#CoordsArray(this.#capacity * 6);
16185
16557
  newCoords.set(this.#coords);
16186
16558
  this.#coords = newCoords;
16187
16559
  }
16188
- const transform = getCurrentTransform(ctx);
16560
+ const transform = getCurrentTransform(ctx2);
16189
16561
  let coords;
16190
16562
  if (clipBox[0] !== Infinity) {
16191
16563
  const bbox = BBOX_INIT.slice();
@@ -16411,7 +16783,7 @@ var init_pdf2 = __esm({
16411
16783
  const canvas = this._document.createElement("canvas");
16412
16784
  canvas.width = 1;
16413
16785
  canvas.height = 1;
16414
- const ctx = canvas.getContext("2d");
16786
+ const ctx2 = canvas.getContext("2d");
16415
16787
  let called = 0;
16416
16788
  function isFontReady(name2, callback) {
16417
16789
  if (++called > 30) {
@@ -16419,9 +16791,9 @@ var init_pdf2 = __esm({
16419
16791
  callback();
16420
16792
  return;
16421
16793
  }
16422
- ctx.font = "30px " + name2;
16423
- ctx.fillText(".", 0, 20);
16424
- const imageData = ctx.getImageData(0, 0, 1, 1);
16794
+ ctx2.font = "30px " + name2;
16795
+ ctx2.fillText(".", 0, 20);
16796
+ const imageData = ctx2.getImageData(0, 0, 1, 1);
16425
16797
  if (imageData.data[3] > 0) {
16426
16798
  callback();
16427
16799
  return;
@@ -18160,7 +18532,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18160
18532
  const dist = Math.hypot(this._p0[0] - this._p1[0], this._p0[1] - this._p1[1]);
18161
18533
  return dist + this._r1 > this._r0 && dist + this._r0 > this._r1;
18162
18534
  }
18163
- _createGradient(ctx, transform = null) {
18535
+ _createGradient(ctx2, transform = null) {
18164
18536
  let grad;
18165
18537
  let firstPoint = this._p0;
18166
18538
  let secondPoint = this._p1;
@@ -18171,7 +18543,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18171
18543
  Util.applyTransform(secondPoint, transform);
18172
18544
  }
18173
18545
  if (this._type === "axial") {
18174
- grad = ctx.createLinearGradient(firstPoint[0], firstPoint[1], secondPoint[0], secondPoint[1]);
18546
+ grad = ctx2.createLinearGradient(firstPoint[0], firstPoint[1], secondPoint[0], secondPoint[1]);
18175
18547
  } else if (this._type === "radial") {
18176
18548
  let r0 = this._r0;
18177
18549
  let r1 = this._r1;
@@ -18181,14 +18553,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18181
18553
  r0 *= scale[0];
18182
18554
  r1 *= scale[0];
18183
18555
  }
18184
- grad = ctx.createRadialGradient(firstPoint[0], firstPoint[1], r0, secondPoint[0], secondPoint[1], r1);
18556
+ grad = ctx2.createRadialGradient(firstPoint[0], firstPoint[1], r0, secondPoint[0], secondPoint[1], r1);
18185
18557
  }
18186
18558
  for (const colorStop of this._colorStops) {
18187
18559
  grad.addColorStop(colorStop[0], colorStop[1]);
18188
18560
  }
18189
18561
  return grad;
18190
18562
  }
18191
- _createReversedGradient(ctx, transform = null) {
18563
+ _createReversedGradient(ctx2, transform = null) {
18192
18564
  let firstPoint = this._p1;
18193
18565
  let secondPoint = this._p0;
18194
18566
  if (transform) {
@@ -18205,14 +18577,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18205
18577
  r0 *= scale[0];
18206
18578
  r1 *= scale[0];
18207
18579
  }
18208
- const grad = ctx.createRadialGradient(firstPoint[0], firstPoint[1], r0, secondPoint[0], secondPoint[1], r1);
18580
+ const grad = ctx2.createRadialGradient(firstPoint[0], firstPoint[1], r0, secondPoint[0], secondPoint[1], r1);
18209
18581
  const reversedStops = this._colorStops.map(([t, c]) => [1 - t, c]).reverse();
18210
18582
  for (const [t, c] of reversedStops) {
18211
18583
  grad.addColorStop(t, c);
18212
18584
  }
18213
18585
  return grad;
18214
18586
  }
18215
- getPattern(ctx, owner, inverse, pathType) {
18587
+ getPattern(ctx2, owner, inverse, pathType) {
18216
18588
  let pattern;
18217
18589
  if (pathType === PathType.STROKE || pathType === PathType.FILL) {
18218
18590
  if (this.isOriginBased()) {
@@ -18227,14 +18599,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18227
18599
  if (Math.abs(ps) < precision) {
18228
18600
  if (this.isRadial()) {
18229
18601
  if (Math.abs(n1 - n2) < precision) {
18230
- return this._createGradient(ctx, transf);
18602
+ return this._createGradient(ctx2, transf);
18231
18603
  }
18232
18604
  } else {
18233
- return this._createGradient(ctx, transf);
18605
+ return this._createGradient(ctx2, transf);
18234
18606
  }
18235
18607
  }
18236
18608
  }
18237
- const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, getCurrentTransform(ctx)) || [0, 0, 0, 0];
18609
+ const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, getCurrentTransform(ctx2)) || [0, 0, 0, 0];
18238
18610
  const width = Math.ceil(ownerBBox[2] - ownerBBox[0]) || 1;
18239
18611
  const height = Math.ceil(ownerBBox[3] - ownerBBox[1]) || 1;
18240
18612
  const tmpCanvas = owner.canvasFactory.create(width, height);
@@ -18255,20 +18627,20 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18255
18627
  }
18256
18628
  tmpCtx.fillStyle = this._createGradient(tmpCtx);
18257
18629
  tmpCtx.fill();
18258
- pattern = ctx.createPattern(tmpCanvas.canvas, "no-repeat");
18630
+ pattern = ctx2.createPattern(tmpCanvas.canvas, "no-repeat");
18259
18631
  owner.canvasFactory.destroy(tmpCanvas);
18260
18632
  const domMatrix = new DOMMatrix(inverse);
18261
18633
  pattern.setTransform(domMatrix);
18262
18634
  } else {
18263
18635
  if (this.areConic()) {
18264
- ctx.save();
18265
- applyBoundingBox(ctx, this._bbox);
18266
- ctx.fillStyle = this._createReversedGradient(ctx);
18267
- ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
18268
- ctx.restore();
18636
+ ctx2.save();
18637
+ applyBoundingBox(ctx2, this._bbox);
18638
+ ctx2.fillStyle = this._createReversedGradient(ctx2);
18639
+ ctx2.fillRect(-1e10, -1e10, 2e10, 2e10);
18640
+ ctx2.restore();
18269
18641
  }
18270
- applyBoundingBox(ctx, this._bbox);
18271
- pattern = this._createGradient(ctx);
18642
+ applyBoundingBox(ctx2, this._bbox);
18643
+ pattern = this._createGradient(ctx2);
18272
18644
  }
18273
18645
  return pattern;
18274
18646
  }
@@ -18336,11 +18708,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18336
18708
  isModifyingCurrentTransform() {
18337
18709
  return true;
18338
18710
  }
18339
- getPattern(ctx, owner, inverse, pathType) {
18340
- applyBoundingBox(ctx, this._bbox);
18711
+ getPattern(ctx2, owner, inverse, pathType) {
18712
+ applyBoundingBox(ctx2, this._bbox);
18341
18713
  const scale = new Float32Array(2);
18342
18714
  if (pathType === PathType.SHADING) {
18343
- Util.singularValueDecompose2dScale(getCurrentTransform(ctx), scale);
18715
+ Util.singularValueDecompose2dScale(getCurrentTransform(ctx2), scale);
18344
18716
  } else if (this.matrix) {
18345
18717
  Util.singularValueDecompose2dScale(this.matrix, scale);
18346
18718
  const [matrixScaleX, matrixScaleY] = scale;
@@ -18352,14 +18724,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18352
18724
  }
18353
18725
  const temporaryPatternCanvas = this._createMeshCanvas(scale, pathType === PathType.SHADING ? null : this._background, owner.canvasFactory);
18354
18726
  if (pathType !== PathType.SHADING) {
18355
- ctx.setTransform(...owner.baseTransform);
18727
+ ctx2.setTransform(...owner.baseTransform);
18356
18728
  if (this.matrix) {
18357
- ctx.transform(...this.matrix);
18729
+ ctx2.transform(...this.matrix);
18358
18730
  }
18359
18731
  }
18360
- ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
18361
- ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
18362
- const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat");
18732
+ ctx2.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
18733
+ ctx2.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
18734
+ const pattern = ctx2.createPattern(temporaryPatternCanvas.canvas, "no-repeat");
18363
18735
  owner.canvasFactory.destroy(temporaryPatternCanvas);
18364
18736
  return pattern;
18365
18737
  }
@@ -18375,7 +18747,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18375
18747
  };
18376
18748
  TilingPattern = class _TilingPattern {
18377
18749
  static MAX_PATTERN_SIZE = 3e3;
18378
- constructor(IR, ctx, canvasGraphicsFactory, baseTransform) {
18750
+ constructor(IR, ctx2, canvasGraphicsFactory, baseTransform) {
18379
18751
  this.color = IR[1];
18380
18752
  this.operatorList = IR[2];
18381
18753
  this.matrix = IR[3];
@@ -18385,7 +18757,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18385
18757
  this.paintType = IR[7];
18386
18758
  this.tilingType = IR[8];
18387
18759
  this.needsIsolation = IR[9] ?? true;
18388
- this.ctx = ctx;
18760
+ this.ctx = ctx2;
18389
18761
  this.canvasGraphicsFactory = canvasGraphicsFactory;
18390
18762
  this.baseTransform = baseTransform;
18391
18763
  this.patternBaseMatrix = this.matrix ? Util.transform(baseTransform, this.matrix) : baseTransform;
@@ -18587,13 +18959,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18587
18959
  isModifyingCurrentTransform() {
18588
18960
  return false;
18589
18961
  }
18590
- getPattern(ctx, owner, inverse, pathType, opIdx) {
18962
+ getPattern(ctx2, owner, inverse, pathType, opIdx) {
18591
18963
  const matrix = pathType !== PathType.SHADING ? Util.transform(inverse, this.patternBaseMatrix) : inverse;
18592
18964
  const temporaryPatternCanvas = this.createPatternCanvas(owner, opIdx);
18593
18965
  let domMatrix = new DOMMatrix(matrix);
18594
18966
  domMatrix = domMatrix.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
18595
18967
  domMatrix = domMatrix.scale(1 / temporaryPatternCanvas.scaleX, 1 / temporaryPatternCanvas.scaleY);
18596
- const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "repeat");
18968
+ const pattern = ctx2.createPattern(temporaryPatternCanvas.canvas, "repeat");
18597
18969
  owner.canvasFactory.destroy(temporaryPatternCanvas.canvasEntry);
18598
18970
  pattern.setTransform(domMatrix);
18599
18971
  return pattern;
@@ -18870,13 +19242,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18870
19242
  this.#knockoutElementDepth = 0;
18871
19243
  this.#knockoutGroupLevel = 0;
18872
19244
  this.cachedPatterns.clear();
18873
- for (const cache2 of this._cachedBitmapsMap.values()) {
18874
- for (const canvas of cache2.values()) {
19245
+ for (const cache3 of this._cachedBitmapsMap.values()) {
19246
+ for (const canvas of cache3.values()) {
18875
19247
  if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) {
18876
19248
  canvas.width = canvas.height = 0;
18877
19249
  }
18878
19250
  }
18879
- cache2.clear();
19251
+ cache3.clear();
18880
19252
  }
18881
19253
  this._cachedBitmapsMap.clear();
18882
19254
  this.#drawFilter();
@@ -18962,20 +19334,20 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
18962
19334
  };
18963
19335
  }
18964
19336
  _createMaskCanvas(opIdx, img) {
18965
- const ctx = this.ctx;
19337
+ const ctx2 = this.ctx;
18966
19338
  const {
18967
19339
  width,
18968
19340
  height
18969
19341
  } = img;
18970
19342
  const fillColor = this.current.fillColor;
18971
19343
  const isPatternFill = this.current.patternFill;
18972
- const currentTransform = getCurrentTransform(ctx);
18973
- let cache2, cacheKey, scaled, maskCanvas;
19344
+ const currentTransform = getCurrentTransform(ctx2);
19345
+ let cache3, cacheKey, scaled, maskCanvas;
18974
19346
  if ((img.bitmap || img.data) && img.count > 1) {
18975
19347
  const mainKey = img.bitmap || img.data.buffer;
18976
19348
  cacheKey = JSON.stringify(isPatternFill ? currentTransform : [currentTransform.slice(0, 4), fillColor]);
18977
- cache2 = this._cachedBitmapsMap.getOrInsertComputed(mainKey, makeMap);
18978
- const cachedImage = cache2.get(cacheKey);
19349
+ cache3 = this._cachedBitmapsMap.getOrInsertComputed(mainKey, makeMap);
19350
+ const cachedImage = cache3.get(cacheKey);
18979
19351
  if (cachedImage && !isPatternFill) {
18980
19352
  const offsetX2 = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]);
18981
19353
  const offsetY2 = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]);
@@ -19014,8 +19386,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19014
19386
  this.canvasFactory.destroy(maskCanvas);
19015
19387
  maskCanvas = null;
19016
19388
  }
19017
- if (cache2 && isPatternFill) {
19018
- cache2.set(cacheKey, scaled);
19389
+ if (cache3 && isPatternFill) {
19390
+ cache3.set(cacheKey, scaled);
19019
19391
  scaledEntry = null;
19020
19392
  maskCanvas = null;
19021
19393
  }
@@ -19030,15 +19402,15 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19030
19402
  }
19031
19403
  fillCtx.globalCompositeOperation = "source-in";
19032
19404
  const inverse = Util.transform(getCurrentTransformInverse(fillCtx), [1, 0, 0, 1, -offsetX, -offsetY]);
19033
- fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, PathType.FILL, opIdx) : fillColor;
19405
+ fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx2, this, inverse, PathType.FILL, opIdx) : fillColor;
19034
19406
  fillCtx.fillRect(0, 0, width, height);
19035
- if (cache2 && !isPatternFill) {
19036
- cache2.set(cacheKey, fillCanvas.canvas);
19407
+ if (cache3 && !isPatternFill) {
19408
+ cache3.set(cacheKey, fillCanvas.canvas);
19037
19409
  }
19038
19410
  this.dependencyTracker?.recordDependencies(opIdx, Dependencies.transformAndFill);
19039
19411
  return {
19040
19412
  canvas: fillCanvas.canvas,
19041
- canvasEntry: cache2 && !isPatternFill ? null : fillCanvas,
19413
+ canvasEntry: cache3 && !isPatternFill ? null : fillCanvas,
19042
19414
  offsetX: Math.round(offsetX),
19043
19415
  offsetY: Math.round(offsetY)
19044
19416
  };
@@ -19065,10 +19437,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19065
19437
  }
19066
19438
  setDash(opIdx, dashArray, dashPhase) {
19067
19439
  this.dependencyTracker?.recordSimpleData("dash", opIdx);
19068
- const ctx = this.ctx;
19069
- if (ctx.setLineDash !== void 0) {
19070
- ctx.setLineDash(dashArray);
19071
- ctx.lineDashOffset = dashPhase;
19440
+ const ctx2 = this.ctx;
19441
+ if (ctx2.setLineDash !== void 0) {
19442
+ ctx2.setLineDash(dashArray);
19443
+ ctx2.lineDashOffset = dashPhase;
19072
19444
  }
19073
19445
  }
19074
19446
  setRenderingIntent(opIdx, intent) {
@@ -19267,10 +19639,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19267
19639
  const scratchCanvas = this.canvasFactory.create(drawnWidth, drawnHeight);
19268
19640
  this.smaskScratchCanvas = scratchCanvas;
19269
19641
  this.suspendedCtx = this.ctx;
19270
- const ctx = this.ctx = scratchCanvas.context;
19271
- ctx.setTransform(this.suspendedCtx.getTransform());
19272
- copyCtxState(this.suspendedCtx, ctx);
19273
- mirrorContextOperations(ctx, this.suspendedCtx);
19642
+ const ctx2 = this.ctx = scratchCanvas.context;
19643
+ ctx2.setTransform(this.suspendedCtx.getTransform());
19644
+ copyCtxState(this.suspendedCtx, ctx2);
19645
+ mirrorContextOperations(ctx2, this.suspendedCtx);
19274
19646
  this._ensurePreparedSMask(this.current.activeSMask);
19275
19647
  this.setGState(opIdx, [["BM", "source-over"]]);
19276
19648
  }
@@ -19339,11 +19711,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19339
19711
  }
19340
19712
  return entry;
19341
19713
  }
19342
- const ctx = entry.context;
19343
- ctx.save();
19344
- ctx.setTransform(1, 0, 0, 1, 0, 0);
19345
- ctx.clearRect(0, 0, width, height);
19346
- ctx.restore();
19714
+ const ctx2 = entry.context;
19715
+ ctx2.save();
19716
+ ctx2.setTransform(1, 0, 0, 1, 0, 0);
19717
+ ctx2.clearRect(0, 0, width, height);
19718
+ ctx2.restore();
19347
19719
  return entry;
19348
19720
  }
19349
19721
  #compositeKnockoutSurface(destCtx, surfaceCanvas, options = {}) {
@@ -19483,7 +19855,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19483
19855
  this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
19484
19856
  this.ctx.restore();
19485
19857
  }
19486
- composeSMask(ctx, smask, layerCtx, layerBox) {
19858
+ composeSMask(ctx2, smask, layerCtx, layerBox) {
19487
19859
  const layerOffsetX = layerBox[0];
19488
19860
  const layerOffsetY = layerBox[1];
19489
19861
  const layerWidth = layerBox[2] - layerOffsetX;
@@ -19526,15 +19898,15 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19526
19898
  } else {
19527
19899
  this.genericComposeSMask(smask, layerCtx, layerWidth, layerHeight, layerOffsetX, layerOffsetY);
19528
19900
  }
19529
- if (!ctx) {
19901
+ if (!ctx2) {
19530
19902
  return;
19531
19903
  }
19532
- ctx.save();
19533
- ctx.globalAlpha = 1;
19534
- ctx.globalCompositeOperation = smask.blendMode || "source-over";
19535
- ctx.setTransform(1, 0, 0, 1, 0, 0);
19536
- ctx.drawImage(layerCtx.canvas, layerOffsetX, layerOffsetY, layerWidth, layerHeight, layerOffsetX, layerOffsetY, layerWidth, layerHeight);
19537
- ctx.restore();
19904
+ ctx2.save();
19905
+ ctx2.globalAlpha = 1;
19906
+ ctx2.globalCompositeOperation = smask.blendMode || "source-over";
19907
+ ctx2.setTransform(1, 0, 0, 1, 0, 0);
19908
+ ctx2.drawImage(layerCtx.canvas, layerOffsetX, layerOffsetY, layerWidth, layerHeight, layerOffsetX, layerOffsetY, layerWidth, layerHeight);
19909
+ ctx2.restore();
19538
19910
  }
19539
19911
  _applySMaskOOBAlpha(layerCtx, layerOffsetX, layerOffsetY, layerWidth, layerHeight, maskX0, maskY0, maskX1, maskY1, alpha) {
19540
19912
  const hasInnerCutout = maskX0 < maskX1 && maskY0 < maskY1;
@@ -19641,21 +20013,21 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19641
20013
  }
19642
20014
  stroke(opIdx, path, consumePath = true) {
19643
20015
  const started = consumePath && this.#beginKnockoutElement(this.current.strokeAlpha);
19644
- const ctx = this.ctx;
20016
+ const ctx2 = this.ctx;
19645
20017
  const strokeColor = this.current.strokeColor;
19646
- ctx.globalAlpha = this.current.strokeAlpha;
20018
+ ctx2.globalAlpha = this.current.strokeAlpha;
19647
20019
  if (this.contentVisible) {
19648
20020
  if (typeof strokeColor === "object" && strokeColor?.getPattern) {
19649
- const baseTransform = strokeColor.isModifyingCurrentTransform() ? ctx.getTransform() : null;
19650
- ctx.save();
19651
- ctx.strokeStyle = strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE, opIdx);
20021
+ const baseTransform = strokeColor.isModifyingCurrentTransform() ? ctx2.getTransform() : null;
20022
+ ctx2.save();
20023
+ ctx2.strokeStyle = strokeColor.getPattern(ctx2, this, getCurrentTransformInverse(ctx2), PathType.STROKE, opIdx);
19652
20024
  if (baseTransform) {
19653
20025
  const newPath = new Path2D();
19654
- newPath.addPath(path, ctx.getTransform().invertSelf().multiplySelf(baseTransform));
20026
+ newPath.addPath(path, ctx2.getTransform().invertSelf().multiplySelf(baseTransform));
19655
20027
  path = newPath;
19656
20028
  }
19657
20029
  this.rescaleAndStroke(path, false);
19658
- ctx.restore();
20030
+ ctx2.restore();
19659
20031
  } else {
19660
20032
  this.rescaleAndStroke(path, true);
19661
20033
  }
@@ -19664,7 +20036,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19664
20036
  if (consumePath) {
19665
20037
  this.consumePath(opIdx, path, this.current.getClippedPathBoundingBox(PathType.STROKE, getCurrentTransform(this.ctx)));
19666
20038
  }
19667
- ctx.globalAlpha = this.current.fillAlpha;
20039
+ ctx2.globalAlpha = this.current.fillAlpha;
19668
20040
  this.#endKnockoutElement(started);
19669
20041
  }
19670
20042
  closeStroke(opIdx, path) {
@@ -19672,7 +20044,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19672
20044
  }
19673
20045
  fill(opIdx, path, consumePath = true) {
19674
20046
  const started = consumePath && this.#beginKnockoutElement(this.current.fillAlpha);
19675
- const ctx = this.ctx;
20047
+ const ctx2 = this.ctx;
19676
20048
  const fillColor = this.current.fillColor;
19677
20049
  const isPatternFill = this.current.patternFill;
19678
20050
  let needRestore = false;
@@ -19691,27 +20063,27 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19691
20063
  this.#endKnockoutElement(started);
19692
20064
  return;
19693
20065
  }
19694
- const baseTransform = fillColor.isModifyingCurrentTransform() ? ctx.getTransform() : null;
20066
+ const baseTransform = fillColor.isModifyingCurrentTransform() ? ctx2.getTransform() : null;
19695
20067
  this.dependencyTracker?.save(opIdx);
19696
- ctx.save();
19697
- ctx.fillStyle = fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL, opIdx);
20068
+ ctx2.save();
20069
+ ctx2.fillStyle = fillColor.getPattern(ctx2, this, getCurrentTransformInverse(ctx2), PathType.FILL, opIdx);
19698
20070
  if (baseTransform) {
19699
20071
  const newPath = new Path2D();
19700
- newPath.addPath(path, ctx.getTransform().invertSelf().multiplySelf(baseTransform));
20072
+ newPath.addPath(path, ctx2.getTransform().invertSelf().multiplySelf(baseTransform));
19701
20073
  path = newPath;
19702
20074
  }
19703
20075
  needRestore = true;
19704
20076
  }
19705
20077
  if (this.contentVisible && intersect !== null) {
19706
20078
  if (this.pendingEOFill) {
19707
- ctx.fill(path, "evenodd");
20079
+ ctx2.fill(path, "evenodd");
19708
20080
  this.pendingEOFill = false;
19709
20081
  } else {
19710
- ctx.fill(path);
20082
+ ctx2.fill(path);
19711
20083
  }
19712
20084
  }
19713
20085
  if (needRestore) {
19714
- ctx.restore();
20086
+ ctx2.restore();
19715
20087
  this.dependencyTracker?.restore(opIdx);
19716
20088
  }
19717
20089
  if (consumePath) {
@@ -19767,7 +20139,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19767
20139
  }
19768
20140
  endText(opIdx) {
19769
20141
  const paths = this.pendingTextPaths;
19770
- const ctx = this.ctx;
20142
+ const ctx2 = this.ctx;
19771
20143
  if (this.dependencyTracker) {
19772
20144
  const {
19773
20145
  dependencyTracker
@@ -19779,7 +20151,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19779
20151
  }
19780
20152
  if (paths !== void 0) {
19781
20153
  const newPath = new Path2D();
19782
- const invTransf = ctx.getTransform().invertSelf();
20154
+ const invTransf = ctx2.getTransform().invertSelf();
19783
20155
  for (const {
19784
20156
  transform,
19785
20157
  x,
@@ -19792,7 +20164,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19792
20164
  }
19793
20165
  newPath.addPath(path, new DOMMatrix(transform).preMultiplySelf(invTransf).translate(x, y).scale(fontSize, -fontSize));
19794
20166
  }
19795
- ctx.clip(newPath);
20167
+ ctx2.clip(newPath);
19796
20168
  }
19797
20169
  delete this.pendingTextPaths;
19798
20170
  }
@@ -19884,7 +20256,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19884
20256
  return newPath;
19885
20257
  }
19886
20258
  paintChar(opIdx, character, x, y, patternFillTransform, patternStrokeTransform) {
19887
- const ctx = this.ctx;
20259
+ const ctx2 = this.ctx;
19888
20260
  const current = this.current;
19889
20261
  const font = current.font;
19890
20262
  const textRenderingMode = current.textRenderingMode;
@@ -19898,25 +20270,25 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19898
20270
  path = font.getPathGenerator(this.commonObjs, character);
19899
20271
  }
19900
20272
  if (path && (font.disableFontFace || patternFill || patternStroke)) {
19901
- ctx.save();
19902
- ctx.translate(x, y);
19903
- ctx.scale(fontSize, -fontSize);
19904
- this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font);
20273
+ ctx2.save();
20274
+ ctx2.translate(x, y);
20275
+ ctx2.scale(fontSize, -fontSize);
20276
+ this.dependencyTracker?.recordCharacterBBox(opIdx, ctx2, font);
19905
20277
  let currentTransform;
19906
20278
  if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
19907
20279
  if (patternFillTransform) {
19908
- currentTransform = ctx.getTransform();
19909
- ctx.setTransform(...patternFillTransform);
20280
+ currentTransform = ctx2.getTransform();
20281
+ ctx2.setTransform(...patternFillTransform);
19910
20282
  const scaledPath = this.#getScaledPath(path, currentTransform, patternFillTransform);
19911
- ctx.fill(scaledPath);
20283
+ ctx2.fill(scaledPath);
19912
20284
  } else {
19913
- ctx.fill(path);
20285
+ ctx2.fill(path);
19914
20286
  }
19915
20287
  }
19916
20288
  if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
19917
20289
  if (patternStrokeTransform) {
19918
- currentTransform ||= ctx.getTransform();
19919
- ctx.setTransform(...patternStrokeTransform);
20290
+ currentTransform ||= ctx2.getTransform();
20291
+ ctx2.setTransform(...patternStrokeTransform);
19920
20292
  const {
19921
20293
  a,
19922
20294
  b,
@@ -19926,44 +20298,44 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19926
20298
  const invPatternTransform = Util.inverseTransform(patternStrokeTransform);
19927
20299
  const transf = Util.transform([a, b, c, d, 0, 0], invPatternTransform);
19928
20300
  Util.singularValueDecompose2dScale(transf, XY);
19929
- ctx.lineWidth *= Math.max(XY[0], XY[1]) / fontSize;
19930
- ctx.stroke(this.#getScaledPath(path, currentTransform, patternStrokeTransform));
20301
+ ctx2.lineWidth *= Math.max(XY[0], XY[1]) / fontSize;
20302
+ ctx2.stroke(this.#getScaledPath(path, currentTransform, patternStrokeTransform));
19931
20303
  } else {
19932
- ctx.lineWidth /= fontSize;
19933
- ctx.stroke(path);
20304
+ ctx2.lineWidth /= fontSize;
20305
+ ctx2.stroke(path);
19934
20306
  }
19935
20307
  }
19936
- ctx.restore();
20308
+ ctx2.restore();
19937
20309
  } else {
19938
20310
  if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
19939
- ctx.fillText(character, x, y);
19940
- this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font, fontSize, x, y, () => ctx.measureText(character));
20311
+ ctx2.fillText(character, x, y);
20312
+ this.dependencyTracker?.recordCharacterBBox(opIdx, ctx2, font, fontSize, x, y, () => ctx2.measureText(character));
19941
20313
  }
19942
20314
  if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
19943
20315
  if (this.dependencyTracker) {
19944
- this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font, fontSize, x, y, () => ctx.measureText(character)).recordDependencies(opIdx, Dependencies.stroke);
20316
+ this.dependencyTracker?.recordCharacterBBox(opIdx, ctx2, font, fontSize, x, y, () => ctx2.measureText(character)).recordDependencies(opIdx, Dependencies.stroke);
19945
20317
  }
19946
- ctx.strokeText(character, x, y);
20318
+ ctx2.strokeText(character, x, y);
19947
20319
  }
19948
20320
  }
19949
20321
  if (isAddToPathSet) {
19950
20322
  const paths = this.pendingTextPaths ||= [];
19951
20323
  paths.push({
19952
- transform: getCurrentTransform(ctx),
20324
+ transform: getCurrentTransform(ctx2),
19953
20325
  x,
19954
20326
  y,
19955
20327
  fontSize,
19956
20328
  path
19957
20329
  });
19958
- this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font, fontSize, x, y);
20330
+ this.dependencyTracker?.recordCharacterBBox(opIdx, ctx2, font, fontSize, x, y);
19959
20331
  }
19960
20332
  }
19961
20333
  get isFontSubpixelAAEnabled() {
19962
20334
  const tmpCanvas = this.canvasFactory.create(10, 10);
19963
- const ctx = tmpCanvas.context;
19964
- ctx.scale(1.5, 1);
19965
- ctx.fillText("I", 0, 10);
19966
- const data = ctx.getImageData(0, 0, 10, 10).data;
20335
+ const ctx2 = tmpCanvas.context;
20336
+ ctx2.scale(1.5, 1);
20337
+ ctx2.fillText("I", 0, 10);
20338
+ const data = ctx2.getImageData(0, 0, 10, 10).data;
19967
20339
  this.canvasFactory.destroy(tmpCanvas);
19968
20340
  let enabled = false;
19969
20341
  for (let i = 3; i < data.length; i += 4) {
@@ -19996,7 +20368,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
19996
20368
  return;
19997
20369
  }
19998
20370
  const started = this.#beginKnockoutElement(current.fillAlpha);
19999
- const ctx = this.ctx;
20371
+ const ctx2 = this.ctx;
20000
20372
  const fontSizeScale = current.fontSizeScale;
20001
20373
  const charSpacing = current.charSpacing;
20002
20374
  const wordSpacing = current.wordSpacing;
@@ -20008,15 +20380,15 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20008
20380
  const defaultVMetrics = font.defaultVMetrics;
20009
20381
  const widthAdvanceScale = fontSize * current.fontMatrix[0];
20010
20382
  const simpleFillText = current.textRenderingMode === TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
20011
- ctx.save();
20383
+ ctx2.save();
20012
20384
  if (current.textMatrix) {
20013
- ctx.transform(...current.textMatrix);
20385
+ ctx2.transform(...current.textMatrix);
20014
20386
  }
20015
- ctx.translate(current.x, current.y + current.textRise);
20387
+ ctx2.translate(current.x, current.y + current.textRise);
20016
20388
  if (fontDirection > 0) {
20017
- ctx.scale(textHScale, -1);
20389
+ ctx2.scale(textHScale, -1);
20018
20390
  } else {
20019
- ctx.scale(textHScale, 1);
20391
+ ctx2.scale(textHScale, 1);
20020
20392
  }
20021
20393
  let patternFillTransform, patternStrokeTransform;
20022
20394
  const fillStrokeMode = current.textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
@@ -20032,23 +20404,23 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20032
20404
  lineWidth /= scale;
20033
20405
  }
20034
20406
  if (fontSizeScale !== 1) {
20035
- ctx.scale(fontSizeScale, fontSizeScale);
20407
+ ctx2.scale(fontSizeScale, fontSizeScale);
20036
20408
  lineWidth /= fontSizeScale;
20037
20409
  }
20038
- ctx.lineWidth = lineWidth;
20410
+ ctx2.lineWidth = lineWidth;
20039
20411
  if (needsFill && current.patternFill) {
20040
- ctx.save();
20041
- const pattern = current.fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL, opIdx);
20042
- patternFillTransform = getCurrentTransform(ctx);
20043
- ctx.restore();
20044
- ctx.fillStyle = pattern;
20412
+ ctx2.save();
20413
+ const pattern = current.fillColor.getPattern(ctx2, this, getCurrentTransformInverse(ctx2), PathType.FILL, opIdx);
20414
+ patternFillTransform = getCurrentTransform(ctx2);
20415
+ ctx2.restore();
20416
+ ctx2.fillStyle = pattern;
20045
20417
  }
20046
20418
  if (needsStroke && current.patternStroke) {
20047
- ctx.save();
20048
- const pattern = current.strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE, opIdx);
20049
- patternStrokeTransform = getCurrentTransform(ctx);
20050
- ctx.restore();
20051
- ctx.strokeStyle = pattern;
20419
+ ctx2.save();
20420
+ const pattern = current.strokeColor.getPattern(ctx2, this, getCurrentTransformInverse(ctx2), PathType.STROKE, opIdx);
20421
+ patternStrokeTransform = getCurrentTransform(ctx2);
20422
+ ctx2.restore();
20423
+ ctx2.strokeStyle = pattern;
20052
20424
  }
20053
20425
  if (font.isInvalidPDFjsFont) {
20054
20426
  const chars = [];
@@ -20058,13 +20430,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20058
20430
  width += glyph.width;
20059
20431
  }
20060
20432
  const joinedChars = chars.join("");
20061
- ctx.fillText(joinedChars, 0, 0);
20433
+ ctx2.fillText(joinedChars, 0, 0);
20062
20434
  if (this.dependencyTracker !== null) {
20063
- const measure = ctx.measureText(joinedChars);
20435
+ const measure = ctx2.measureText(joinedChars);
20064
20436
  this.dependencyTracker.recordBBox(opIdx, this.ctx, -measure.actualBoundingBoxLeft, measure.actualBoundingBoxRight, -measure.actualBoundingBoxAscent, measure.actualBoundingBoxDescent).recordShowTextOperation(opIdx);
20065
20437
  }
20066
20438
  current.x += width * widthAdvanceScale * textHScale;
20067
- ctx.restore();
20439
+ ctx2.restore();
20068
20440
  this.compose();
20069
20441
  this.#endKnockoutElement(started);
20070
20442
  return;
@@ -20095,13 +20467,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20095
20467
  }
20096
20468
  let measure;
20097
20469
  if (font.remeasure && width > 0) {
20098
- measure = ctx.measureText(character);
20470
+ measure = ctx2.measureText(character);
20099
20471
  const measuredWidth = measure.width * 1e3 / fontSize * fontSizeScale;
20100
20472
  if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
20101
20473
  const characterScaleX = width / measuredWidth;
20102
20474
  restoreNeeded = true;
20103
- ctx.save();
20104
- ctx.scale(characterScaleX, 1);
20475
+ ctx2.save();
20476
+ ctx2.scale(characterScaleX, 1);
20105
20477
  scaledX /= characterScaleX;
20106
20478
  } else if (width !== measuredWidth) {
20107
20479
  scaledX += (width - measuredWidth) / 2e3 * fontSize / fontSizeScale;
@@ -20109,10 +20481,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20109
20481
  }
20110
20482
  if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
20111
20483
  if (simpleFillText && !accent) {
20112
- ctx.fillText(character, scaledX, scaledY);
20113
- this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, measure ? {
20484
+ ctx2.fillText(character, scaledX, scaledY);
20485
+ this.dependencyTracker?.recordCharacterBBox(opIdx, ctx2, measure ? {
20114
20486
  bbox: null
20115
- } : font, fontSize / fontSizeScale, scaledX, scaledY, () => measure ?? ctx.measureText(character));
20487
+ } : font, fontSize / fontSizeScale, scaledX, scaledY, () => measure ?? ctx2.measureText(character));
20116
20488
  } else {
20117
20489
  this.paintChar(opIdx, character, scaledX, scaledY, patternFillTransform, patternStrokeTransform);
20118
20490
  if (accent) {
@@ -20125,7 +20497,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20125
20497
  const charWidth = vertical ? width * widthAdvanceScale - spacing * fontDirection : width * widthAdvanceScale + spacing * fontDirection;
20126
20498
  x += charWidth;
20127
20499
  if (restoreNeeded) {
20128
- ctx.restore();
20500
+ ctx2.restore();
20129
20501
  }
20130
20502
  }
20131
20503
  if (vertical) {
@@ -20133,13 +20505,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20133
20505
  } else {
20134
20506
  current.x += x * textHScale;
20135
20507
  }
20136
- ctx.restore();
20508
+ ctx2.restore();
20137
20509
  this.compose();
20138
20510
  this.dependencyTracker?.recordShowTextOperation(opIdx);
20139
20511
  this.#endKnockoutElement(started);
20140
20512
  }
20141
20513
  showType3Text(opIdx, glyphs) {
20142
- const ctx = this.ctx;
20514
+ const ctx2 = this.ctx;
20143
20515
  const current = this.current;
20144
20516
  const font = current.font;
20145
20517
  const fontSize = current.fontSize;
@@ -20157,12 +20529,12 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20157
20529
  }
20158
20530
  this._cachedScaleForStroking[0] = -1;
20159
20531
  this._cachedGetSinglePixelWidth = null;
20160
- ctx.save();
20532
+ ctx2.save();
20161
20533
  if (current.textMatrix) {
20162
- ctx.transform(...current.textMatrix);
20534
+ ctx2.transform(...current.textMatrix);
20163
20535
  }
20164
- ctx.translate(current.x, current.y + current.textRise);
20165
- ctx.scale(textHScale, fontDirection);
20536
+ ctx2.translate(current.x, current.y + current.textRise);
20537
+ ctx2.scale(textHScale, fontDirection);
20166
20538
  const dependencyTracker = this.dependencyTracker;
20167
20539
  this.dependencyTracker = dependencyTracker ? new CanvasNestedDependencyTracker(dependencyTracker, opIdx) : null;
20168
20540
  for (i = 0; i < glyphsLength; ++i) {
@@ -20181,20 +20553,20 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20181
20553
  this.save();
20182
20554
  if (operatorList.fnArray[0] === OPS.setCharWidth) {
20183
20555
  current.fillAlpha = current.strokeAlpha = 1;
20184
- ctx.globalAlpha = 1;
20556
+ ctx2.globalAlpha = 1;
20185
20557
  }
20186
- ctx.scale(fontSize, fontSize);
20187
- ctx.transform(...fontMatrix);
20558
+ ctx2.scale(fontSize, fontSize);
20559
+ ctx2.transform(...fontMatrix);
20188
20560
  this.executeOperatorList(operatorList);
20189
20561
  this.restore();
20190
20562
  }
20191
20563
  const p = [glyph.width, 0];
20192
20564
  Util.applyTransform(p, fontMatrix);
20193
20565
  width = p[0] * fontSize + spacing;
20194
- ctx.translate(width, 0);
20566
+ ctx2.translate(width, 0);
20195
20567
  current.x += width * textHScale;
20196
20568
  }
20197
- ctx.restore();
20569
+ ctx2.restore();
20198
20570
  if (dependencyTracker) {
20199
20571
  this.dependencyTracker = dependencyTracker;
20200
20572
  }
@@ -20213,7 +20585,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20213
20585
  if (IR[0] === "TilingPattern") {
20214
20586
  const baseTransform = this.baseTransform || getCurrentTransform(this.ctx);
20215
20587
  const canvasGraphicsFactory = {
20216
- createCanvasGraphics: (ctx, renderingOpIdx) => new _CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
20588
+ createCanvasGraphics: (ctx2, renderingOpIdx) => new _CanvasGraphics(ctx2, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
20217
20589
  optionalContentConfig: this.optionalContentConfig,
20218
20590
  markedContentStack: this.markedContentStack
20219
20591
  }, void 0, void 0, this.dependencyTracker ? new CanvasNestedDependencyTracker(this.dependencyTracker, renderingOpIdx, true) : null)
@@ -20269,16 +20641,16 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20269
20641
  return;
20270
20642
  }
20271
20643
  const started = this.#beginKnockoutElement(this.current.fillAlpha);
20272
- const ctx = this.ctx;
20644
+ const ctx2 = this.ctx;
20273
20645
  this.save(opIdx);
20274
20646
  const pattern = this._getPattern(opIdx, objId);
20275
- ctx.fillStyle = pattern.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.SHADING, opIdx);
20276
- const inv = getCurrentTransformInverse(ctx);
20647
+ ctx2.fillStyle = pattern.getPattern(ctx2, this, getCurrentTransformInverse(ctx2), PathType.SHADING, opIdx);
20648
+ const inv = getCurrentTransformInverse(ctx2);
20277
20649
  if (inv) {
20278
20650
  const {
20279
20651
  width,
20280
20652
  height
20281
- } = ctx.canvas;
20653
+ } = ctx2.canvas;
20282
20654
  const minMax = F32_BBOX_INIT.slice();
20283
20655
  Util.axialAlignedBoundingBox([0, 0, width, height], inv, minMax);
20284
20656
  const [x0, y0, x1, y1] = minMax;
@@ -20450,19 +20822,19 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20450
20822
  }
20451
20823
  this.groupLevel--;
20452
20824
  const groupCtx = this.ctx;
20453
- const ctx = this.groupStack.pop();
20825
+ const ctx2 = this.groupStack.pop();
20454
20826
  const groupMeta = this.#groupStackMeta.pop();
20455
20827
  if (groupMeta) {
20456
20828
  this.#knockoutGroupLevel = groupMeta.savedKnockoutLevel;
20457
20829
  }
20458
- if (ctx === null) {
20830
+ if (ctx2 === null) {
20459
20831
  this.restore(opIdx);
20460
20832
  return;
20461
20833
  }
20462
20834
  if (group.isGray) {
20463
20835
  this.#convertGroupToGray(groupCtx);
20464
20836
  }
20465
- this.ctx = ctx;
20837
+ this.ctx = ctx2;
20466
20838
  this.ctx.imageSmoothingEnabled = false;
20467
20839
  this.dependencyTracker?.popBaseTransform();
20468
20840
  if (group.smask) {
@@ -20492,7 +20864,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20492
20864
  } = groupCtx.canvas;
20493
20865
  const colorEntry = this.canvasFactory.create(width, height);
20494
20866
  const colorCtx = colorEntry.context;
20495
- colorCtx.drawImage(ctx.canvas, groupMeta.offsetX, groupMeta.offsetY, width, height, 0, 0, width, height);
20867
+ colorCtx.drawImage(ctx2.canvas, groupMeta.offsetX, groupMeta.offsetY, width, height, 0, 0, width, height);
20496
20868
  colorCtx.globalCompositeOperation = "source-over";
20497
20869
  colorCtx.drawImage(groupCtx.canvas, 0, 0);
20498
20870
  const shapeMaskEntry = this.#createKnockoutMaskCanvas(groupCtx.canvas);
@@ -20666,14 +21038,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20666
21038
  img = this.getObject(opIdx, img.data, img);
20667
21039
  img.count = count;
20668
21040
  const started = this.#beginKnockoutElement(this.current.fillAlpha);
20669
- const ctx = this.ctx;
21041
+ const ctx2 = this.ctx;
20670
21042
  const mask = this._createMaskCanvas(opIdx, img);
20671
21043
  const maskCanvas = mask.canvas;
20672
- ctx.save();
20673
- ctx.setTransform(1, 0, 0, 1, 0, 0);
20674
- ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
21044
+ ctx2.save();
21045
+ ctx2.setTransform(1, 0, 0, 1, 0, 0);
21046
+ ctx2.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
20675
21047
  this.dependencyTracker?.resetBBox(opIdx).recordBBox(opIdx, this.ctx, mask.offsetX, mask.offsetX + maskCanvas.width, mask.offsetY, mask.offsetY + maskCanvas.height).recordOperation(opIdx);
20676
- ctx.restore();
21048
+ ctx2.restore();
20677
21049
  if (mask.canvasEntry) {
20678
21050
  this.canvasFactory.destroy(mask.canvasEntry);
20679
21051
  }
@@ -20686,19 +21058,19 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20686
21058
  }
20687
21059
  img = this.getObject(opIdx, img.data, img);
20688
21060
  const started = this.#beginKnockoutElement(this.current.fillAlpha);
20689
- const ctx = this.ctx;
20690
- ctx.save();
20691
- const currentTransform = getCurrentTransform(ctx);
20692
- ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
21061
+ const ctx2 = this.ctx;
21062
+ ctx2.save();
21063
+ const currentTransform = getCurrentTransform(ctx2);
21064
+ ctx2.transform(scaleX, skewX, skewY, scaleY, 0, 0);
20693
21065
  const mask = this._createMaskCanvas(opIdx, img);
20694
- ctx.setTransform(1, 0, 0, 1, mask.offsetX - currentTransform[4], mask.offsetY - currentTransform[5]);
21066
+ ctx2.setTransform(1, 0, 0, 1, mask.offsetX - currentTransform[4], mask.offsetY - currentTransform[5]);
20695
21067
  this.dependencyTracker?.resetBBox(opIdx);
20696
21068
  for (let i = 0, ii = positions.length; i < ii; i += 2) {
20697
21069
  const trans = Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
20698
- ctx.drawImage(mask.canvas, trans[4], trans[5]);
21070
+ ctx2.drawImage(mask.canvas, trans[4], trans[5]);
20699
21071
  this.dependencyTracker?.recordBBox(opIdx, this.ctx, trans[4], trans[4] + mask.canvas.width, trans[5], trans[5] + mask.canvas.height);
20700
21072
  }
20701
- ctx.restore();
21073
+ ctx2.restore();
20702
21074
  if (mask.canvasEntry) {
20703
21075
  this.canvasFactory.destroy(mask.canvasEntry);
20704
21076
  }
@@ -20711,7 +21083,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20711
21083
  return;
20712
21084
  }
20713
21085
  const started = this.#beginKnockoutElement(this.current.fillAlpha);
20714
- const ctx = this.ctx;
21086
+ const ctx2 = this.ctx;
20715
21087
  const fillColor = this.current.fillColor;
20716
21088
  const isPatternFill = this.current.patternFill;
20717
21089
  this.dependencyTracker?.resetBBox(opIdx).recordDependencies(opIdx, Dependencies.transformAndFill);
@@ -20728,16 +21100,16 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20728
21100
  const img = this.getObject(opIdx, data, image);
20729
21101
  putBinaryImageMask(maskCtx, img);
20730
21102
  maskCtx.globalCompositeOperation = "source-in";
20731
- maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, getCurrentTransformInverse(ctx), PathType.FILL, opIdx) : fillColor;
21103
+ maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, getCurrentTransformInverse(ctx2), PathType.FILL, opIdx) : fillColor;
20732
21104
  maskCtx.fillRect(0, 0, width, height);
20733
21105
  maskCtx.restore();
20734
- ctx.save();
20735
- ctx.transform(...transform);
20736
- ctx.scale(1, -1);
20737
- drawImageAtIntegerCoords(ctx, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
21106
+ ctx2.save();
21107
+ ctx2.transform(...transform);
21108
+ ctx2.scale(1, -1);
21109
+ drawImageAtIntegerCoords(ctx2, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
20738
21110
  this.canvasFactory.destroy(maskCanvas);
20739
- this.dependencyTracker?.recordBBox(opIdx, ctx, 0, width, 0, height);
20740
- ctx.restore();
21111
+ this.dependencyTracker?.recordBBox(opIdx, ctx2, 0, width, 0, height);
21112
+ ctx2.restore();
20741
21113
  }
20742
21114
  this.compose();
20743
21115
  this.dependencyTracker?.recordOperation(opIdx);
@@ -20777,13 +21149,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20777
21149
  }
20778
21150
  this.paintInlineImageXObjectGroup(opIdx, imgData, map);
20779
21151
  }
20780
- applyTransferMapsToCanvas(ctx) {
21152
+ applyTransferMapsToCanvas(ctx2) {
20781
21153
  if (this.current.transferMaps !== "none") {
20782
- ctx.filter = this.current.transferMaps;
20783
- ctx.drawImage(ctx.canvas, 0, 0);
20784
- ctx.filter = "none";
21154
+ ctx2.filter = this.current.transferMaps;
21155
+ ctx2.drawImage(ctx2.canvas, 0, 0);
21156
+ ctx2.filter = "none";
20785
21157
  }
20786
- return ctx.canvas;
21158
+ return ctx2.canvas;
20787
21159
  }
20788
21160
  applyTransferMapsToBitmap(imgData) {
20789
21161
  if (this.current.transferMaps === "none") {
@@ -20814,15 +21186,15 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20814
21186
  const width = imgData.width;
20815
21187
  const height = imgData.height;
20816
21188
  const started = this.#beginKnockoutElement(this.current.fillAlpha);
20817
- const ctx = this.ctx;
21189
+ const ctx2 = this.ctx;
20818
21190
  this.save(opIdx);
20819
21191
  const {
20820
21192
  filter
20821
- } = ctx;
21193
+ } = ctx2;
20822
21194
  if (filter !== "none" && filter !== "") {
20823
- ctx.filter = "none";
21195
+ ctx2.filter = "none";
20824
21196
  }
20825
- ctx.scale(1 / width, -1 / height);
21197
+ ctx2.scale(1 / width, -1 / height);
20826
21198
  let imgToPaint;
20827
21199
  let inlineImgCanvas = null;
20828
21200
  if (imgData.bitmap) {
@@ -20835,13 +21207,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20835
21207
  imgToPaint = this.applyTransferMapsToCanvas(tmpCanvas.context);
20836
21208
  inlineImgCanvas = tmpCanvas;
20837
21209
  }
20838
- const scaled = this._scaleImage(imgToPaint, getCurrentTransformInverse(ctx));
20839
- ctx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(ctx), imgData.interpolate);
21210
+ const scaled = this._scaleImage(imgToPaint, getCurrentTransformInverse(ctx2));
21211
+ ctx2.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(ctx2), imgData.interpolate);
20840
21212
  if (this.dependencyTracker) {
20841
- this.dependencyTracker.resetBBox(opIdx).recordBBox(opIdx, ctx, 0, width, -height, 0).recordDependencies(opIdx, Dependencies.imageXObject).recordOperation(opIdx);
20842
- this.imagesTracker?.record(ctx, width, height, this.dependencyTracker.clipBox);
21213
+ this.dependencyTracker.resetBBox(opIdx).recordBBox(opIdx, ctx2, 0, width, -height, 0).recordDependencies(opIdx, Dependencies.imageXObject).recordOperation(opIdx);
21214
+ this.imagesTracker?.record(ctx2, width, height, this.dependencyTracker.clipBox);
20843
21215
  }
20844
- drawImageAtIntegerCoords(ctx, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
21216
+ drawImageAtIntegerCoords(ctx2, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
20845
21217
  if (scaled.tmpCanvas) {
20846
21218
  this.canvasFactory.destroy(scaled.tmpCanvas);
20847
21219
  }
@@ -20857,7 +21229,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20857
21229
  return;
20858
21230
  }
20859
21231
  const started = this.#beginKnockoutElement(this.current.fillAlpha);
20860
- const ctx = this.ctx;
21232
+ const ctx2 = this.ctx;
20861
21233
  let imgToPaint;
20862
21234
  let inlineImgCanvas = null;
20863
21235
  if (imgData.bitmap) {
@@ -20872,12 +21244,12 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20872
21244
  }
20873
21245
  this.dependencyTracker?.resetBBox(opIdx);
20874
21246
  for (const entry of map) {
20875
- ctx.save();
20876
- ctx.transform(...entry.transform);
20877
- ctx.scale(1, -1);
20878
- drawImageAtIntegerCoords(ctx, imgToPaint, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
20879
- this.dependencyTracker?.recordBBox(opIdx, ctx, 0, 1, -1, 0);
20880
- ctx.restore();
21247
+ ctx2.save();
21248
+ ctx2.transform(...entry.transform);
21249
+ ctx2.scale(1, -1);
21250
+ drawImageAtIntegerCoords(ctx2, imgToPaint, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
21251
+ this.dependencyTracker?.recordBBox(opIdx, ctx2, 0, 1, -1, 0);
21252
+ ctx2.restore();
20881
21253
  }
20882
21254
  if (inlineImgCanvas) {
20883
21255
  this.canvasFactory.destroy(inlineImgCanvas);
@@ -20936,13 +21308,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
20936
21308
  if (!this.pendingClip) {
20937
21309
  this.compose(clipBox);
20938
21310
  }
20939
- const ctx = this.ctx;
21311
+ const ctx2 = this.ctx;
20940
21312
  if (this.pendingClip) {
20941
21313
  if (!isEmpty) {
20942
21314
  if (this.pendingClip === EO_CLIP) {
20943
- ctx.clip(path, "evenodd");
21315
+ ctx2.clip(path, "evenodd");
20944
21316
  } else {
20945
- ctx.clip(path);
21317
+ ctx2.clip(path);
20946
21318
  }
20947
21319
  }
20948
21320
  this.pendingClip = null;
@@ -21017,36 +21389,36 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
21017
21389
  }
21018
21390
  rescaleAndStroke(path, saveRestore) {
21019
21391
  const {
21020
- ctx,
21392
+ ctx: ctx2,
21021
21393
  current: {
21022
21394
  lineWidth
21023
21395
  }
21024
21396
  } = this;
21025
21397
  const [scaleX, scaleY] = this.getScaleForStroking();
21026
21398
  if (scaleX === scaleY) {
21027
- ctx.lineWidth = (lineWidth || 1) * scaleX;
21028
- ctx.stroke(path);
21399
+ ctx2.lineWidth = (lineWidth || 1) * scaleX;
21400
+ ctx2.stroke(path);
21029
21401
  return;
21030
21402
  }
21031
21403
  const SCALE_MATRIX = _CanvasGraphics.#SCALE_MATRIX ??= new DOMMatrix();
21032
- const dashes = ctx.getLineDash();
21404
+ const dashes = ctx2.getLineDash();
21033
21405
  if (saveRestore) {
21034
- ctx.save();
21406
+ ctx2.save();
21035
21407
  }
21036
- ctx.scale(scaleX, scaleY);
21408
+ ctx2.scale(scaleX, scaleY);
21037
21409
  SCALE_MATRIX.a = 1 / scaleX;
21038
21410
  SCALE_MATRIX.d = 1 / scaleY;
21039
21411
  const newPath = new Path2D();
21040
21412
  newPath.addPath(path, SCALE_MATRIX);
21041
21413
  if (dashes.length > 0) {
21042
21414
  const scale = Math.max(scaleX, scaleY);
21043
- ctx.setLineDash(dashes.map((x) => x / scale));
21044
- ctx.lineDashOffset /= scale;
21415
+ ctx2.setLineDash(dashes.map((x) => x / scale));
21416
+ ctx2.lineDashOffset /= scale;
21045
21417
  }
21046
- ctx.lineWidth = lineWidth || 1;
21047
- ctx.stroke(newPath);
21418
+ ctx2.lineWidth = lineWidth || 1;
21419
+ ctx2.stroke(newPath);
21048
21420
  if (saveRestore) {
21049
- ctx.restore();
21421
+ ctx2.restore();
21050
21422
  }
21051
21423
  }
21052
21424
  isContentVisible() {
@@ -22745,7 +23117,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22745
23117
  const {
22746
23118
  div,
22747
23119
  properties,
22748
- ctx
23120
+ ctx: ctx2
22749
23121
  } = params;
22750
23122
  const {
22751
23123
  style
@@ -22758,10 +23130,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22758
23130
  canvasWidth,
22759
23131
  fontSize
22760
23132
  } = properties;
22761
- _TextLayer.#ensureCtxFont(ctx, fontSize * this.#scale, fontFamily);
23133
+ _TextLayer.#ensureCtxFont(ctx2, fontSize * this.#scale, fontFamily);
22762
23134
  const {
22763
23135
  width
22764
- } = ctx.measureText(div.textContent);
23136
+ } = ctx2.measureText(div.textContent);
22765
23137
  if (width > 0) {
22766
23138
  style.setProperty("--scale-x", canvasWidth * this.#scale / width);
22767
23139
  }
@@ -22783,30 +23155,30 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22783
23155
  this.#canvasContexts.clear();
22784
23156
  }
22785
23157
  static #getCtx(lang = null) {
22786
- let ctx = this.#canvasContexts.get(lang ||= "");
22787
- if (!ctx) {
23158
+ let ctx2 = this.#canvasContexts.get(lang ||= "");
23159
+ if (!ctx2) {
22788
23160
  const canvas = document.createElement("canvas");
22789
23161
  canvas.style.cssText = "position:absolute;top:0;left:0;width:0;height:0;display:none;letter-spacing:normal;word-spacing:normal";
22790
23162
  canvas.lang = lang;
22791
23163
  document.body.append(canvas);
22792
- ctx = canvas.getContext("2d", {
23164
+ ctx2 = canvas.getContext("2d", {
22793
23165
  alpha: false,
22794
23166
  willReadFrequently: true
22795
23167
  });
22796
- this.#canvasContexts.set(lang, ctx);
22797
- this.#canvasCtxFonts.set(ctx, {
23168
+ this.#canvasContexts.set(lang, ctx2);
23169
+ this.#canvasCtxFonts.set(ctx2, {
22798
23170
  size: 0,
22799
23171
  family: ""
22800
23172
  });
22801
23173
  }
22802
- return ctx;
23174
+ return ctx2;
22803
23175
  }
22804
- static #ensureCtxFont(ctx, size, family) {
22805
- const cached3 = this.#canvasCtxFonts.get(ctx);
23176
+ static #ensureCtxFont(ctx2, size, family) {
23177
+ const cached3 = this.#canvasCtxFonts.get(ctx2);
22806
23178
  if (size === cached3.size && family === cached3.family) {
22807
23179
  return;
22808
23180
  }
22809
- ctx.font = `${size}px ${family}`;
23181
+ ctx2.font = `${size}px ${family}`;
22810
23182
  cached3.size = size;
22811
23183
  cached3.family = family;
22812
23184
  }
@@ -22829,13 +23201,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
22829
23201
  if (cachedAscent) {
22830
23202
  return cachedAscent;
22831
23203
  }
22832
- const ctx = this.#getCtx(lang);
22833
- ctx.canvas.width = ctx.canvas.height = DEFAULT_FONT_SIZE;
22834
- this.#ensureCtxFont(ctx, DEFAULT_FONT_SIZE, fontFamily);
22835
- const metrics = ctx.measureText("");
23204
+ const ctx2 = this.#getCtx(lang);
23205
+ ctx2.canvas.width = ctx2.canvas.height = DEFAULT_FONT_SIZE;
23206
+ this.#ensureCtxFont(ctx2, DEFAULT_FONT_SIZE, fontFamily);
23207
+ const metrics = ctx2.measureText("");
22836
23208
  const ascent = metrics.fontBoundingBoxAscent;
22837
23209
  const descent = Math.abs(metrics.fontBoundingBoxDescent);
22838
- ctx.canvas.width = ctx.canvas.height = 0;
23210
+ ctx2.canvas.width = ctx2.canvas.height = 0;
22839
23211
  let ratio = 0.8;
22840
23212
  if (ascent) {
22841
23213
  ratio = ascent / (ascent + descent);
@@ -32575,8 +32947,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32575
32947
  newWidth = Math.ceil(prevWidth / 2);
32576
32948
  newHeight = Math.ceil(prevHeight / 2);
32577
32949
  const offscreen2 = new OffscreenCanvas(newWidth, newHeight);
32578
- const ctx2 = offscreen2.getContext("2d");
32579
- ctx2.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
32950
+ const ctx3 = offscreen2.getContext("2d");
32951
+ ctx3.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
32580
32952
  prevWidth = newWidth;
32581
32953
  prevHeight = newHeight;
32582
32954
  if (bitmap !== originalBitmap) {
@@ -32589,14 +32961,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32589
32961
  newHeight = Math.round(newHeight * ratio);
32590
32962
  }
32591
32963
  const offscreen = new OffscreenCanvas(newWidth, newHeight);
32592
- const ctx = offscreen.getContext("2d", {
32964
+ const ctx2 = offscreen.getContext("2d", {
32593
32965
  willReadFrequently: true
32594
32966
  });
32595
- ctx.fillStyle = "white";
32596
- ctx.fillRect(0, 0, newWidth, newHeight);
32597
- ctx.filter = "grayscale(1)";
32598
- ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, newWidth, newHeight);
32599
- const grayImage = ctx.getImageData(0, 0, newWidth, newHeight).data;
32967
+ ctx2.fillStyle = "white";
32968
+ ctx2.fillRect(0, 0, newWidth, newHeight);
32969
+ ctx2.filter = "grayscale(1)";
32970
+ ctx2.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, newWidth, newHeight);
32971
+ const grayImage = ctx2.getImageData(0, 0, newWidth, newHeight).data;
32600
32972
  const uint8Buf = this.#toUint8(grayImage);
32601
32973
  return [uint8Buf, newWidth, newHeight];
32602
32974
  }
@@ -32606,11 +32978,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32606
32978
  fontWeight
32607
32979
  }, pageWidth, pageHeight, rotation, innerMargin) {
32608
32980
  let canvas = new OffscreenCanvas(1, 1);
32609
- let ctx = canvas.getContext("2d", {
32981
+ let ctx2 = canvas.getContext("2d", {
32610
32982
  alpha: false
32611
32983
  });
32612
32984
  const fontSize = 200;
32613
- const font = ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
32985
+ const font = ctx2.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
32614
32986
  const {
32615
32987
  actualBoundingBoxLeft,
32616
32988
  actualBoundingBoxRight,
@@ -32619,22 +32991,22 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
32619
32991
  fontBoundingBoxAscent,
32620
32992
  fontBoundingBoxDescent,
32621
32993
  width
32622
- } = ctx.measureText(text);
32994
+ } = ctx2.measureText(text);
32623
32995
  const SCALE = 1.5;
32624
32996
  const canvasWidth = Math.ceil(Math.max(Math.abs(actualBoundingBoxLeft) + Math.abs(actualBoundingBoxRight) || 0, width) * SCALE);
32625
32997
  const canvasHeight = Math.ceil(Math.max(Math.abs(actualBoundingBoxAscent) + Math.abs(actualBoundingBoxDescent) || fontSize, Math.abs(fontBoundingBoxAscent) + Math.abs(fontBoundingBoxDescent) || fontSize) * SCALE);
32626
32998
  canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
32627
- ctx = canvas.getContext("2d", {
32999
+ ctx2 = canvas.getContext("2d", {
32628
33000
  alpha: true,
32629
33001
  willReadFrequently: true
32630
33002
  });
32631
- ctx.font = font;
32632
- ctx.filter = "grayscale(1)";
32633
- ctx.fillStyle = "white";
32634
- ctx.fillRect(0, 0, canvasWidth, canvasHeight);
32635
- ctx.fillStyle = "black";
32636
- ctx.fillText(text, canvasWidth * (SCALE - 1) / 2, canvasHeight * (3 - SCALE) / 2);
32637
- const uint8Buf = this.#toUint8(ctx.getImageData(0, 0, canvasWidth, canvasHeight).data);
33003
+ ctx2.font = font;
33004
+ ctx2.filter = "grayscale(1)";
33005
+ ctx2.fillStyle = "white";
33006
+ ctx2.fillRect(0, 0, canvasWidth, canvasHeight);
33007
+ ctx2.fillStyle = "black";
33008
+ ctx2.fillText(text, canvasWidth * (SCALE - 1) / 2, canvasHeight * (3 - SCALE) / 2);
33009
+ const uint8Buf = this.#toUint8(ctx2.getImageData(0, 0, canvasWidth, canvasHeight).data);
32638
33010
  const histogram = this.#getHistogram(uint8Buf);
32639
33011
  const threshold = this.#guessThreshold(histogram);
32640
33012
  const contourList = this.#findContours(uint8Buf, canvasWidth, canvasHeight, threshold);
@@ -33600,8 +33972,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
33600
33972
  if (!this.#isSvg) {
33601
33973
  bitmap = this.#scaleBitmap(scaledWidth, scaledHeight);
33602
33974
  }
33603
- const ctx = canvas.getContext("2d");
33604
- ctx.filter = this._uiManager.hcmFilter;
33975
+ const ctx2 = canvas.getContext("2d");
33976
+ ctx2.filter = this._uiManager.hcmFilter;
33605
33977
  let white = "white", black = "#cfcfd8";
33606
33978
  if (this._uiManager.hcmFilter !== "none") {
33607
33979
  black = "black";
@@ -33619,9 +33991,9 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
33619
33991
  patternCtx.fillStyle = black;
33620
33992
  patternCtx.fillRect(0, 0, boxDimWidth, boxDimHeight);
33621
33993
  patternCtx.fillRect(boxDimWidth, boxDimHeight, boxDimWidth, boxDimHeight);
33622
- ctx.fillStyle = ctx.createPattern(pattern, "repeat");
33623
- ctx.fillRect(0, 0, scaledWidth, scaledHeight);
33624
- ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
33994
+ ctx2.fillStyle = ctx2.createPattern(pattern, "repeat");
33995
+ ctx2.fillRect(0, 0, scaledWidth, scaledHeight);
33996
+ ctx2.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
33625
33997
  }
33626
33998
  let imageData = null;
33627
33999
  if (createImageData) {
@@ -33676,8 +34048,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
33676
34048
  newHeight = Math.ceil(newHeight / 2);
33677
34049
  }
33678
34050
  const offscreen = new OffscreenCanvas(newWidth, newHeight);
33679
- const ctx = offscreen.getContext("2d");
33680
- ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
34051
+ const ctx2 = offscreen.getContext("2d");
34052
+ ctx2.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
33681
34053
  bitmap = offscreen.transferToImageBitmap();
33682
34054
  }
33683
34055
  return bitmap;
@@ -33698,9 +34070,9 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
33698
34070
  canvas.width = scaledWidth;
33699
34071
  canvas.height = scaledHeight;
33700
34072
  const bitmap = this.#isSvg ? this.#bitmap : this.#scaleBitmap(scaledWidth, scaledHeight);
33701
- const ctx = canvas.getContext("2d");
33702
- ctx.filter = this._uiManager.hcmFilter;
33703
- ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
34073
+ const ctx2 = canvas.getContext("2d");
34074
+ ctx2.filter = this._uiManager.hcmFilter;
34075
+ ctx2.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
33704
34076
  }
33705
34077
  #serializeBitmap(toUrl) {
33706
34078
  if (toUrl) {
@@ -33715,8 +34087,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
33715
34087
  width: canvas.width,
33716
34088
  height: canvas.height
33717
34089
  } = this.#bitmap);
33718
- const ctx = canvas.getContext("2d");
33719
- ctx.drawImage(this.#bitmap, 0, 0);
34090
+ const ctx2 = canvas.getContext("2d");
34091
+ ctx2.drawImage(this.#bitmap, 0, 0);
33720
34092
  return canvas.toDataURL();
33721
34093
  }
33722
34094
  if (this.#isSvg) {
@@ -33724,8 +34096,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
33724
34096
  const width = Math.round(this.width * pageWidth * PixelsPerInch.PDF_TO_CSS_UNITS);
33725
34097
  const height = Math.round(this.height * pageHeight * PixelsPerInch.PDF_TO_CSS_UNITS);
33726
34098
  const offscreen = new OffscreenCanvas(width, height);
33727
- const ctx = offscreen.getContext("2d");
33728
- ctx.drawImage(this.#bitmap, 0, 0, this.#bitmap.width, this.#bitmap.height, 0, 0, width, height);
34099
+ const ctx2 = offscreen.getContext("2d");
34100
+ ctx2.drawImage(this.#bitmap, 0, 0, this.#bitmap.width, this.#bitmap.height, 0, 0, width, height);
33729
34101
  return offscreen.transferToImageBitmap();
33730
34102
  }
33731
34103
  return structuredClone(this.#bitmap);
@@ -35224,10 +35596,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
35224
35596
  const imageY2 = Math.floor((y1 + height / this.#pageHeight) * pageCanvas.height);
35225
35597
  imgElement.width = imageX2 - imageX1;
35226
35598
  imgElement.height = imageY2 - imageY1;
35227
- const ctx = imgElement.getContext("2d");
35228
- ctx.setTransform(...inverseTransform);
35229
- ctx.translate(-imageX1, -imageY1);
35230
- ctx.drawImage(pageCanvas, 0, 0);
35599
+ const ctx2 = imgElement.getContext("2d");
35600
+ ctx2.setTransform(...inverseTransform);
35601
+ ctx2.translate(-imageX1, -imageY1);
35602
+ ctx2.drawImage(pageCanvas, 0, 0);
35231
35603
  });
35232
35604
  return container;
35233
35605
  }
@@ -35345,7 +35717,7 @@ async function pdfjs() {
35345
35717
  return pdfjsPromise;
35346
35718
  }
35347
35719
  async function extractPdfText(pdfPath, { maxChars = DEFAULT_MAX_CHARS, force = false } = {}) {
35348
- const hit = cache.get(pdfPath);
35720
+ const hit = cache2.get(pdfPath);
35349
35721
  if (!force && hit && Date.now() - hit.at < CACHE_TTL_MS) return hit.text;
35350
35722
  const data = new Uint8Array(await readFile4(pdfPath));
35351
35723
  const getDocument2 = (await pdfjs()).getDocument;
@@ -35367,16 +35739,16 @@ async function extractPdfText(pdfPath, { maxChars = DEFAULT_MAX_CHARS, force = f
35367
35739
  doc.cleanup?.();
35368
35740
  }
35369
35741
  const text = chunks.join("\n").trim();
35370
- cache.set(pdfPath, { text, at: Date.now() });
35742
+ cache2.set(pdfPath, { text, at: Date.now() });
35371
35743
  return text;
35372
35744
  }
35373
- var DEFAULT_MAX_CHARS, CACHE_TTL_MS, cache, pdfjsPromise;
35745
+ var DEFAULT_MAX_CHARS, CACHE_TTL_MS, cache2, pdfjsPromise;
35374
35746
  var init_pdf_text = __esm({
35375
35747
  "src/node/pdf-text.js"() {
35376
35748
  init_log();
35377
35749
  DEFAULT_MAX_CHARS = 12e4;
35378
35750
  CACHE_TTL_MS = 10 * 60 * 1e3;
35379
- cache = /* @__PURE__ */ new Map();
35751
+ cache2 = /* @__PURE__ */ new Map();
35380
35752
  pdfjsPromise = null;
35381
35753
  }
35382
35754
  });
@@ -35385,7 +35757,8 @@ var init_pdf_text = __esm({
35385
35757
  var ai_exports = {};
35386
35758
  __export(ai_exports, {
35387
35759
  askAi: () => askAi,
35388
- buildPrompt: () => buildPrompt
35760
+ buildPrompt: () => buildPrompt,
35761
+ sendFigure: () => sendFigure
35389
35762
  });
35390
35763
  function buildPrompt({ title, action, question = "", selection = "", text = "" }) {
35391
35764
  const head = `\u3010\u6587\u732E\u52A9\u624B \xB7 ${title}\u3011`;
@@ -35432,7 +35805,7 @@ ${text}
35432
35805
  """`;
35433
35806
  }
35434
35807
  }
35435
- async function askAi(ctx, { key, action = "ask", question = "", selection = "", sessionId = null } = {}) {
35808
+ async function askAi(ctx2, { key, action = "ask", question = "", selection = "", sessionId = null } = {}) {
35436
35809
  const entry = await getItem(String(key ?? ""));
35437
35810
  if (!entry) throw Object.assign(new Error("\u6761\u76EE\u4E0D\u5B58\u5728"), { code: "not_found" });
35438
35811
  if (!["translate", "explain", "summarize", "tldr", "ask"].includes(action)) action = "ask";
@@ -35440,7 +35813,7 @@ async function askAi(ctx, { key, action = "ask", question = "", selection = "",
35440
35813
  if (!sid) {
35441
35814
  throw Object.assign(new Error("\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u5BF9\u8BDD\uFF0C\u8BF7\u5148\u5F00\u59CB\u4E00\u4E2A\u5BF9\u8BDD\u518D\u8BD5"), { code: "no_session" });
35442
35815
  }
35443
- const agent = ctx?.agents?.get?.(sid);
35816
+ const agent = ctx2?.agents?.get?.(sid);
35444
35817
  if (!agent || typeof agent.steer !== "function") {
35445
35818
  throw Object.assign(new Error("\u5F53\u524D\u5BF9\u8BDD\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5"), { code: "no_session" });
35446
35819
  }
@@ -35477,6 +35850,38 @@ async function askAi(ctx, { key, action = "ask", question = "", selection = "",
35477
35850
  log(`ai ask steered (${action}) into session ${sid}`);
35478
35851
  return { ok: true, sessionId: sid, action };
35479
35852
  }
35853
+ async function sendFigure(ctx2, { png, caption = "", title = "\u793A\u610F\u56FE", sessionId = null } = {}) {
35854
+ if (!png || !png.length) throw Object.assign(new Error("\u6CA1\u6709\u56FE\u7247\u6570\u636E"), { code: "no_image" });
35855
+ const sid = sessionId && String(sessionId) || recentSession();
35856
+ if (!sid) throw Object.assign(new Error("\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u5BF9\u8BDD\uFF0C\u8BF7\u5148\u5F00\u59CB\u4E00\u4E2A\u5BF9\u8BDD\u518D\u8BD5"), { code: "no_session" });
35857
+ const agent = ctx2?.agents?.get?.(sid);
35858
+ if (!agent || typeof agent.steer !== "function") {
35859
+ throw Object.assign(new Error("\u5F53\u524D\u5BF9\u8BDD\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5"), { code: "no_session" });
35860
+ }
35861
+ if (!ctx2?.attachments?.saveImages) {
35862
+ throw Object.assign(new Error("\u5BBF\u4E3B\u4E0D\u652F\u6301\u56FE\u7247\u9644\u4EF6"), { code: "no_attachments" });
35863
+ }
35864
+ let bytes = png;
35865
+ const limits = ctx2.attachments.imageLimits ?? {};
35866
+ const maxBytes = limits.maxImageBytes ?? 5 * 1024 * 1024;
35867
+ if (bytes.length > maxBytes) {
35868
+ throw Object.assign(new Error(`\u56FE\u7247\u8D85\u8FC7\u5BBF\u4E3B\u5927\u5C0F\u9650\u5236\uFF08${bytes.length} > ${maxBytes} \u5B57\u8282\uFF09`), { code: "too_large" });
35869
+ }
35870
+ const mediaType = limits.mediaTypes?.length ? limits.mediaTypes.includes("image/png") ? "image/png" : limits.mediaTypes[0] : "image/png";
35871
+ const [ref] = await ctx2.attachments.saveImages([{ data: new Uint8Array(bytes), mediaType, name: title.slice(0, 60) }]);
35872
+ if (!ref) throw Object.assign(new Error("\u56FE\u7247\u9644\u4EF6\u521B\u5EFA\u5931\u8D25"), { code: "no_attachments" });
35873
+ const text = `\u3010\u6587\u732E\u52A9\u624B \xB7 ${title}\u3011
35874
+ ${caption || "\u6839\u636E\u6570\u636E\u751F\u6210\u7684\u793A\u610F\u56FE\u3002"}
35875
+ \uFF08\u56FE\u7531\u63D2\u4EF6\u6839\u636E\u539F\u59CB\u6570\u636E\u7ED8\u5236\uFF0C\u975E\u539F\u6587\u63D2\u56FE\uFF09`;
35876
+ try {
35877
+ const { createUserMessage } = await import("@deepseek-ai/dsh-llm");
35878
+ agent.steer(createUserMessage({ content: [{ type: "text", text }, { type: "image", attachment: ref }], source: { kind: "user" } }));
35879
+ } catch {
35880
+ agent.steer({ content: [{ type: "text", text }, { type: "image", attachment: ref }], source: { kind: "user" }, role: "user", id: `lit_fig_${Date.now()}` });
35881
+ }
35882
+ log(`figure steered into session ${sid}`);
35883
+ return { ok: true, sessionId: sid };
35884
+ }
35480
35885
  var FULLTEXT_ACTIONS, MAX_CONTEXT_CHARS;
35481
35886
  var init_ai = __esm({
35482
35887
  "src/node/ai.js"() {
@@ -35498,13 +35903,13 @@ __export(doctor_selfheal_exports, {
35498
35903
  pipeAvailable: () => pipeAvailable
35499
35904
  });
35500
35905
  import { createHash } from "node:crypto";
35501
- import { existsSync, readdirSync } from "node:fs";
35502
- import { join as join6 } from "node:path";
35503
- import { homedir as homedir3 } from "node:os";
35906
+ import { existsSync as existsSync2, readdirSync as readdirSync2 } from "node:fs";
35907
+ import { join as join8 } from "node:path";
35908
+ import { homedir as homedir4 } from "node:os";
35504
35909
  import { spawn } from "node:child_process";
35505
35910
  import net from "node:net";
35506
35911
  function doctorRoot() {
35507
- return process.env.DSH_DOCTOR_HOME?.trim() || join6(homedir3(), ".dsh-doctor");
35912
+ return process.env.DSH_DOCTOR_HOME?.trim() || join8(homedir4(), ".dsh-doctor");
35508
35913
  }
35509
35914
  function doctorPipeName(root = doctorRoot()) {
35510
35915
  const hash = createHash("sha256").update(root).digest("hex").slice(0, 16);
@@ -35529,16 +35934,16 @@ function pipeAvailable(pipe, timeoutMs = 1500) {
35529
35934
  });
35530
35935
  }
35531
35936
  function findDoctorCli() {
35532
- const profilesDir = join6(homedir3(), ".dsh", "profiles");
35937
+ const profilesDir = join8(homedir4(), ".dsh", "profiles");
35533
35938
  let entries = [];
35534
35939
  try {
35535
- entries = readdirSync(profilesDir);
35940
+ entries = readdirSync2(profilesDir);
35536
35941
  } catch {
35537
35942
  return "";
35538
35943
  }
35539
35944
  for (const name2 of entries) {
35540
- const candidate = join6(profilesDir, name2, "node_modules", "@linxin666", "dsh-doctor", "lib", "cli.mjs");
35541
- if (existsSync(candidate)) return candidate;
35945
+ const candidate = join8(profilesDir, name2, "node_modules", "@linxin666", "dsh-doctor", "lib", "cli.mjs");
35946
+ if (existsSync2(candidate)) return candidate;
35542
35947
  }
35543
35948
  return "";
35544
35949
  }
@@ -35729,7 +36134,7 @@ async function readJsonBody2(req) {
35729
36134
  const { readJsonBody: read } = await Promise.resolve().then(() => (init_http(), http_exports));
35730
36135
  return read(req);
35731
36136
  }
35732
- async function handler(req, res, ctx) {
36137
+ async function handler(req, res, ctx2) {
35733
36138
  if (!isLoopbackRequest(req)) {
35734
36139
  writeJson(res, 403, { error: "forbidden: loopback-only", code: "forbidden" });
35735
36140
  return;
@@ -35747,6 +36152,29 @@ async function handler(req, res, ctx) {
35747
36152
  await handleEvents(req, res);
35748
36153
  return;
35749
36154
  }
36155
+ if (head === "activate" && activation) {
36156
+ activation.activate("panel-open");
36157
+ writeJson(res, 200, { ok: true, active: true });
36158
+ return;
36159
+ }
36160
+ if (head === "pyenv" && methodOk(req, "GET")) {
36161
+ const { detectPythons: detectPythons2, figureInterpreter: figureInterpreter2, venvExists: venvExists2, venvDir: venvDir2 } = await Promise.resolve().then(() => (init_pyenv(), pyenv_exports));
36162
+ const pythons = await detectPythons2();
36163
+ const fig = await figureInterpreter2();
36164
+ writeJson(res, 200, {
36165
+ pythons,
36166
+ venv: { exists: venvExists2(), dir: venvDir2() },
36167
+ figure: fig ? { exe: fig.exe, version: fig.version, source: fig.source, hasMatplotlib: fig.hasMatplotlib } : null
36168
+ });
36169
+ return;
36170
+ }
36171
+ if (head === "install-deps" && methodOk(req, "POST")) {
36172
+ const { installFigureDeps: installFigureDeps2 } = await Promise.resolve().then(() => (init_pyenv(), pyenv_exports));
36173
+ const logs = [];
36174
+ const result = await installFigureDeps2((m) => logs.push(m));
36175
+ writeJson(res, result.ok ? 200 : 500, { ...result, logs });
36176
+ return;
36177
+ }
35750
36178
  if (head === "state" && methodOk(req, "GET")) {
35751
36179
  await handleState(res);
35752
36180
  return;
@@ -35896,6 +36324,11 @@ async function handler(req, res, ctx) {
35896
36324
  const url = new URL(req.url ?? "/", "http://127.0.0.1");
35897
36325
  const filename = url.searchParams.get("filename") || "dropped.pdf";
35898
36326
  const buffer = await readRawBody(req, 128 * 1024 * 1024);
36327
+ if (buffer.length > 4 && buffer.subarray(0, 2).toString("latin1") === "PK" && /\.pptx$/i.test(filename)) {
36328
+ const item2 = await importDroppedCourseware(buffer, { filename });
36329
+ writeJson(res, 200, { item: item2 });
36330
+ return;
36331
+ }
35899
36332
  const item = await importDroppedPdf(buffer, { filename });
35900
36333
  writeJson(res, 200, { item });
35901
36334
  return;
@@ -35959,7 +36392,7 @@ async function handler(req, res, ctx) {
35959
36392
  if (sub === "ask" && methodOk(req, "POST")) {
35960
36393
  const body = await readJsonBody2(req);
35961
36394
  const { askAi: askAi2 } = await Promise.resolve().then(() => (init_ai(), ai_exports));
35962
- const result = await askAi2(ctx, {
36395
+ const result = await askAi2(ctx2, {
35963
36396
  key: String(body?.key ?? ""),
35964
36397
  action: String(body?.action ?? "ask"),
35965
36398
  question: String(body?.question ?? ""),
@@ -35982,11 +36415,11 @@ async function handler(req, res, ctx) {
35982
36415
  else res.end();
35983
36416
  }
35984
36417
  }
35985
- function registerRoutes(ctx) {
35986
- const disposers = [ctx.webServer.register({ kind: "prefix", path: PREFIX2, handler: (req, res) => handler(req, res, ctx) })];
35987
- if (typeof ctx.on === "function") {
36418
+ function registerRoutes(ctx2, { activation: activation2 } = {}) {
36419
+ const disposers = [ctx2.webServer.register({ kind: "prefix", path: PREFIX2, handler: (req, res) => handler(req, res, ctx2) })];
36420
+ if (typeof ctx2.on === "function") {
35988
36421
  disposers.push(
35989
- ctx.on("session/event", (session) => {
36422
+ ctx2.on("session/event", (session) => {
35990
36423
  noteSession(session);
35991
36424
  })
35992
36425
  );
@@ -35998,76 +36431,472 @@ function registerRoutes(ctx) {
35998
36431
  // src/node/tools.js
35999
36432
  init_pipeline();
36000
36433
  init_db();
36434
+
36435
+ // src/node/store/search.js
36436
+ function tokenize(text) {
36437
+ const s = String(text ?? "").toLowerCase();
36438
+ const out = /* @__PURE__ */ new Set();
36439
+ for (const m of s.matchAll(/[a-z0-9][a-z0-9._-]*/g)) {
36440
+ if (m[0].length >= 2) out.add(m[0]);
36441
+ }
36442
+ const cjkRuns = s.match(/[\u3400-\u4dbf\u4e00-\u9fff\u3040-\u30ff]+/g) ?? [];
36443
+ for (const run2 of cjkRuns) {
36444
+ for (let i = 0; i < run2.length; i += 1) {
36445
+ out.add(run2[i]);
36446
+ if (i + 1 < run2.length) out.add(run2.slice(i, i + 2));
36447
+ }
36448
+ }
36449
+ return [...out];
36450
+ }
36451
+ var WEIGHTS = {
36452
+ title: 3,
36453
+ authors: 2,
36454
+ container: 2,
36455
+ abstract: 1,
36456
+ tags: 1
36457
+ };
36458
+ function fieldText(item, field) {
36459
+ const rec = item.record ?? {};
36460
+ switch (field) {
36461
+ case "title":
36462
+ return rec.title ?? item.title ?? item.display ?? "";
36463
+ case "authors":
36464
+ return (rec.authors ?? []).map((a) => `${a.lastName ?? ""} ${a.firstName ?? ""}`.trim()).join(" ");
36465
+ case "container":
36466
+ return rec.container ?? "";
36467
+ case "abstract":
36468
+ return rec.abstract ?? "";
36469
+ case "tags":
36470
+ return (item.tags ?? []).join(" ");
36471
+ default:
36472
+ return "";
36473
+ }
36474
+ }
36475
+ function searchItems2(items, query, { limit = 20 } = {}) {
36476
+ const terms = tokenize(query);
36477
+ if (!terms.length) return [];
36478
+ const scored = [];
36479
+ for (const item of items) {
36480
+ let score = 0;
36481
+ let matched = false;
36482
+ for (const [field, weight] of Object.entries(WEIGHTS)) {
36483
+ const text = String(fieldText(item, field)).toLowerCase();
36484
+ if (!text) continue;
36485
+ for (const t of terms) {
36486
+ if (text.includes(t)) {
36487
+ matched = true;
36488
+ score += weight * (t.length >= 2 ? 2 : 1);
36489
+ }
36490
+ }
36491
+ }
36492
+ if (!matched) continue;
36493
+ const rec = item.record ?? {};
36494
+ scored.push({
36495
+ key: item.key,
36496
+ title: rec.title ?? item.title ?? item.display ?? "(\u65E0\u6807\u9898)",
36497
+ authors: (rec.authors ?? []).slice(0, 3).map((a) => a.lastName ?? "").filter(Boolean).join(", "),
36498
+ year: rec.year ?? item.year ?? null,
36499
+ container: rec.container ?? "",
36500
+ snippet: snippetFor(item, terms),
36501
+ state: item.state ?? "",
36502
+ score
36503
+ });
36504
+ }
36505
+ scored.sort((a, b) => b.score !== a.score ? b.score - a.score : a.key < b.key ? -1 : 1);
36506
+ return scored.slice(0, Math.max(1, Math.min(limit, 50)));
36507
+ }
36508
+ function snippetFor(item, terms) {
36509
+ const rec = item.record ?? {};
36510
+ const source = rec.abstract || rec.title || "";
36511
+ if (!source) return "";
36512
+ const lower = source.toLowerCase();
36513
+ let at = -1;
36514
+ for (const t of terms) {
36515
+ const i = lower.indexOf(t);
36516
+ if (i >= 0 && (at < 0 || i < at)) at = i;
36517
+ }
36518
+ if (at < 0) return String(source).slice(0, 160);
36519
+ const start = Math.max(0, at - 60);
36520
+ const head = start > 0 ? "\u2026" : "";
36521
+ return head + String(source).slice(start, start + 220).trim();
36522
+ }
36523
+
36524
+ // src/node/tools.js
36001
36525
  init_normalize();
36002
36526
  init_log();
36527
+ import { writeFile as writeFile5, mkdtemp, readFile as readFile6, rm } from "node:fs/promises";
36528
+ import { tmpdir } from "node:os";
36529
+ import { join as join7 } from "node:path";
36003
36530
  function textResult(value) {
36004
36531
  return {
36005
36532
  schema: { type: "string" },
36006
36533
  render: (_args, v) => [{ type: "text", text: String(v) }]
36007
36534
  };
36008
36535
  }
36009
- function registerTools(ctx) {
36010
- const disposers = [];
36011
- disposers.push(
36012
- ctx.tools.register({
36013
- name: "zotero_lookup",
36014
- description: "\u4ECE\u6587\u672C\u6216\u6807\u8BC6\u7B26\u4E2D\u8BC6\u522B\u5B66\u672F\u6587\u732E\uFF08DOI\u3001arXiv ID\u3001PMID\u3001ISBN\u3001\u6807\u9898\uFF09\uFF0C\u89E3\u6790\u5143\u6570\u636E\u5E76\u751F\u6210\u4FA7\u7A97\u6761\u76EE\u3002\u5F53\u4F60\u68C0\u7D22\u6216\u5F15\u7528\u6587\u732E\u5E76\u5E0C\u671B\u7528\u6237\u80FD\u5728\u4FA7\u8FB9\u680F\u9884\u89C8/\u4FDD\u5B58\u5168\u6587\u65F6\u8C03\u7528\u3002",
36015
- parameters: {
36016
- type: "object",
36017
- properties: {
36018
- text: { type: "string", description: "\u5305\u542B\u6587\u732E\u6807\u8BC6\u7B26\u6216\u5F15\u7528\u6587\u672C\u7684\u7247\u6BB5" },
36019
- resolve: { type: "string", description: "\u662F\u5426\u7ACB\u5373\u8054\u7F51\u89E3\u6790\u5143\u6570\u636E\uFF0C\u9ED8\u8BA4 yes" }
36020
- },
36021
- required: []
36022
- },
36023
- output: textResult(),
36024
- timeoutMs: 12e4,
36025
- async execute(args) {
36026
- const text = String(args?.text ?? "");
36027
- if (!text.trim()) return "\u6CA1\u6709\u63D0\u4F9B\u6587\u672C\u3002";
36028
- const created = await scanText(text);
36029
- if (!created.length) return "\u672A\u8BC6\u522B\u5230\u65B0\u7684\u6587\u732E\u6761\u76EE\uFF08\u53EF\u80FD\u5DF2\u5B58\u5728\u4E8E\u4FA7\u7A97\uFF09\u3002";
36030
- const wantResolve = String(args?.resolve ?? "yes").toLowerCase() !== "no";
36031
- if (wantResolve) {
36032
- await Promise.all(created.map((i) => resolveItem(i.key).catch((e) => warn("resolve failed", e.message))));
36033
- }
36034
- const items = await Promise.all(created.map((i) => getItem(i.key)));
36035
- const lines = items.filter(Boolean).map((i) => `- ${i.record?.title || i.display} [${i.key}]`);
36036
- return `\u5DF2\u52A0\u5165\u4FA7\u7A97 ${items.length} \u6761\uFF1A
36037
- ${lines.join("\n")}`;
36536
+ function toolDefs() {
36537
+ return [lookupTool(), searchTool(), getTool(), citeTool(), noteTool(), statusTool(), saveTool(), figureTool()];
36538
+ }
36539
+ function registerTools(ctx2) {
36540
+ let mounted = [];
36541
+ return {
36542
+ mount() {
36543
+ if (mounted.length) return;
36544
+ mounted = toolDefs().map((def) => {
36545
+ try {
36546
+ return ctx2.tools.register(def);
36547
+ } catch (e) {
36548
+ warn("tool registration failed:", def.name, e?.message);
36549
+ return null;
36550
+ }
36551
+ });
36552
+ log(`tools mounted: ${toolDefs().map((d) => d.name).join(", ")}`);
36553
+ },
36554
+ unmount() {
36555
+ if (!mounted.length) return;
36556
+ for (const dispose of mounted) {
36557
+ try {
36558
+ dispose?.();
36559
+ } catch (e) {
36560
+ warn("tool dispose failed:", e?.message);
36561
+ }
36038
36562
  }
36039
- })
36040
- );
36041
- disposers.push(
36042
- ctx.tools.register({
36043
- name: "zotero_save",
36044
- description: "\u628A\u4FA7\u7A97\u4E2D\u5DF2\u8BC6\u522B\u7684\u6587\u732E\u4FDD\u5B58\u5230\u672C\u5730 Zotero \u5E93\u6216\u5BFC\u51FA\u76EE\u5F55\uFF08\u4F1A\u81EA\u52A8\u4E0B\u8F7D\u5168\u6587 PDF\uFF09\u3002",
36045
- parameters: {
36046
- type: "object",
36047
- properties: {
36048
- key: { type: "string", description: "\u6761\u76EE key\uFF08\u6765\u81EA zotero_lookup \u7684\u8FD4\u56DE\uFF09" },
36049
- mode: { type: "string", description: "\u4FDD\u5B58\u65B9\u5F0F\uFF1Azotero \u6216 dir\uFF0C\u7F3A\u7701\u7528\u914D\u7F6E\u503C" },
36050
- tags: { type: "string", description: "\u9017\u53F7\u5206\u9694\u7684\u6807\u7B7E" }
36563
+ mounted = [];
36564
+ log("tools unmounted");
36565
+ },
36566
+ isMounted: () => mounted.length > 0,
36567
+ dispose() {
36568
+ this.unmount();
36569
+ }
36570
+ };
36571
+ }
36572
+ function formatHit(h) {
36573
+ const bits = [h.title];
36574
+ if (h.authors) bits.push(h.authors);
36575
+ if (h.year) bits.push(String(h.year));
36576
+ if (h.container) bits.push(h.container);
36577
+ const line = bits.join(" | ") + ` [key=${h.key}]`;
36578
+ return h.snippet ? `${line}
36579
+ ${h.snippet.slice(0, 160)}` : line;
36580
+ }
36581
+ var NEXT_STEP = "\n[\u4E0B\u4E00\u6B65] literature_get(key=\u2026) \u770B\u8BE6\u60C5 \xB7 literature_cite \u751F\u6210\u5F15\u7528 \xB7 literature_search \u7EE7\u7EED\u68C0\u7D22";
36582
+ function lookupTool() {
36583
+ return {
36584
+ name: "literature_lookup",
36585
+ description: "\u4ECE\u6587\u672C\u6216\u6807\u8BC6\u7B26\u4E2D\u8BC6\u522B\u5B66\u672F\u6587\u732E\uFF08DOI\u3001arXiv ID\u3001PMID\u3001ISBN\u3001\u6807\u9898\uFF09\uFF0C\u89E3\u6790\u5143\u6570\u636E\u5E76\u751F\u6210\u4FA7\u7A97\u6761\u76EE\u3002\u5F53\u4F60\u68C0\u7D22\u6216\u5F15\u7528\u6587\u732E\u5E76\u5E0C\u671B\u7528\u6237\u80FD\u5728\u4FA7\u8FB9\u680F\u9884\u89C8/\u4FDD\u5B58\u5168\u6587\u65F6\u8C03\u7528\u3002",
36586
+ parameters: {
36587
+ type: "object",
36588
+ properties: {
36589
+ text: { type: "string", description: "\u5305\u542B\u6587\u732E\u6807\u8BC6\u7B26\u6216\u5F15\u7528\u6587\u672C\u7684\u7247\u6BB5" },
36590
+ resolve: { type: "string", description: "\u662F\u5426\u7ACB\u5373\u8054\u7F51\u89E3\u6790\u5143\u6570\u636E\uFF0C\u9ED8\u8BA4 yes" }
36591
+ },
36592
+ required: []
36593
+ },
36594
+ output: textResult(),
36595
+ timeoutMs: 12e4,
36596
+ async execute(args) {
36597
+ const text = String(args?.text ?? "");
36598
+ if (!text.trim()) return "\u6CA1\u6709\u63D0\u4F9B\u6587\u672C\u3002";
36599
+ const created = await scanText(text);
36600
+ if (!created.length) return "\u672A\u8BC6\u522B\u5230\u65B0\u7684\u6587\u732E\u6761\u76EE\uFF08\u53EF\u80FD\u5DF2\u5B58\u5728\u4E8E\u4FA7\u7A97\uFF09\u3002";
36601
+ const wantResolve = String(args?.resolve ?? "yes").toLowerCase() !== "no";
36602
+ if (wantResolve) {
36603
+ await Promise.all(created.map((i) => resolveItem(i.key).catch((e) => warn("resolve failed", e.message))));
36604
+ }
36605
+ const items = await Promise.all(created.map((i) => getItem(i.key)));
36606
+ const lines = items.filter(Boolean).map((i) => `- ${i.record?.title || i.display} [key=${i.key}]`);
36607
+ return `\u5DF2\u52A0\u5165\u4FA7\u7A97 ${items.length} \u6761\uFF1A
36608
+ ${lines.join("\n")}${NEXT_STEP}`;
36609
+ }
36610
+ };
36611
+ }
36612
+ function searchTool() {
36613
+ return {
36614
+ name: "literature_search",
36615
+ description: "\u5728\u7528\u6237\u7684\u6587\u732E\u5E93\u4E2D\u68C0\u7D22\u5DF2\u4FDD\u5B58\u7684\u6587\u732E\uFF08\u6807\u9898/\u4F5C\u8005/\u671F\u520A/\u6458\u8981/\u6807\u7B7E\u7684\u5173\u952E\u8BCD\u5339\u914D\uFF09\u3002\u5F53\u7528\u6237\u95EE\u300C\u6211\u4E4B\u524D\u5B58\u7684\u90A3\u7BC7\u300D\u300C\u6211\u5E93\u91CC\u6709\u6CA1\u6709\u8BB2 X \u7684\u300D\u300C\u6709\u4EC0\u4E48\u6587\u732E\u53EF\u4EE5\u7528\u300D\u65F6\u8C03\u7528\u3002\u8FD4\u56DE\u7CBE\u7B80\u6761\u76EE\uFF0C\u9700\u8981\u5B8C\u6574\u4FE1\u606F\u518D\u7528 literature_get\u3002",
36616
+ parameters: {
36617
+ type: "object",
36618
+ properties: {
36619
+ query: { type: "string", description: "\u68C0\u7D22\u8BCD\uFF1A\u4E3B\u9898\u3001\u6807\u9898\u7247\u6BB5\u3001\u4F5C\u8005\u59D3\u6C0F\u6216\u671F\u520A\u540D" },
36620
+ limit: { type: "number", description: "\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 8\uFF0C\u6700\u5927 20" }
36621
+ },
36622
+ required: ["query"]
36623
+ },
36624
+ output: textResult(),
36625
+ timeoutMs: 15e3,
36626
+ async execute(args) {
36627
+ const query = String(args?.query ?? "").trim();
36628
+ if (!query) return "\u7F3A\u5C11\u68C0\u7D22\u8BCD\u3002";
36629
+ const limit = Math.max(1, Math.min(Number(args?.limit) || 8, 20));
36630
+ const items = await listItems();
36631
+ const hits = searchItems2(items, query, { limit });
36632
+ if (!hits.length) return `\u672A\u5728\u5E93\u4E2D\u627E\u5230\u4E0E\u300C${query}\u300D\u5339\u914D\u7684\u6761\u76EE\u3002\u53EF\u5148\u7528 literature_lookup \u6DFB\u52A0\uFF0C\u6216\u6362\u66F4\u5BBD\u6CDB\u7684\u68C0\u7D22\u8BCD\u3002`;
36633
+ return `\u547D\u4E2D ${hits.length} \u6761\uFF1A
36634
+ ${hits.map((h) => `- ${formatHit(h)}`).join("\n")}${NEXT_STEP}`;
36635
+ }
36636
+ };
36637
+ }
36638
+ function getTool() {
36639
+ return {
36640
+ name: "literature_get",
36641
+ description: "\u6309 key \u83B7\u53D6\u6761\u76EE\u7684\u5B8C\u6574\u4FE1\u606F\uFF1A\u5143\u6570\u636E\u3001\u6458\u8981\u3001\u6279\u6CE8\u4E0E\u7B14\u8BB0\u3002\u4EC5\u5728 literature_search \u8FD4\u56DE\u8FC7\u8BE5 key \u65F6\u4F7F\u7528\u2014\u2014\u4E0D\u8981\u51ED\u731C\u6D4B\u7F16\u9020 key\u3002",
36642
+ parameters: {
36643
+ type: "object",
36644
+ properties: {
36645
+ key: { type: "string", description: "\u6761\u76EE key" },
36646
+ includeAnnotations: { type: "boolean", description: "\u662F\u5426\u5305\u542B\u6279\u6CE8\uFF0C\u9ED8\u8BA4 true" }
36647
+ },
36648
+ required: ["key"]
36649
+ },
36650
+ output: textResult(),
36651
+ timeoutMs: 15e3,
36652
+ async execute(args) {
36653
+ const key = String(args?.key ?? "");
36654
+ if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
36655
+ const item = await getItem(key);
36656
+ if (!item) return `\u672A\u627E\u5230\u6761\u76EE ${key}\u3002\u8BF7\u5148\u7528 literature_search \u83B7\u53D6\u6B63\u786E\u7684 key\u3002`;
36657
+ const rec = item.record ?? {};
36658
+ const lines = [
36659
+ `\u6807\u9898\uFF1A${rec.title ?? item.title ?? item.display ?? "(\u65E0\u6807\u9898)"}`,
36660
+ `\u4F5C\u8005\uFF1A${(rec.authors ?? []).map((a) => `${a.lastName ?? ""} ${a.firstName ?? ""}`.trim()).filter(Boolean).join("; ") || "\u2014"}`,
36661
+ `\u5E74\u4EFD\uFF1A${rec.year ?? "\u2014"}`,
36662
+ `\u671F\u520A/\u4F1A\u8BAE\uFF1A${rec.container ?? "\u2014"}`,
36663
+ `DOI\uFF1A${rec.doi ?? "\u2014"}`,
36664
+ `\u72B6\u6001\uFF1A${item.state ?? "\u2014"}${item.pdf ? "\uFF08\u5DF2\u6709\u5168\u6587\uFF09" : "\uFF08\u65E0\u5168\u6587\uFF09"}`
36665
+ ];
36666
+ if (rec.abstract) lines.push(`\u6458\u8981\uFF1A${String(rec.abstract).slice(0, 600)}`);
36667
+ if (String(args?.includeAnnotations ?? true) !== "false") {
36668
+ const anns = await getAnnotations(key);
36669
+ if (anns.length) {
36670
+ const shown = anns.slice(0, 50);
36671
+ lines.push(`\u6279\u6CE8\uFF08${anns.length} \u6761${anns.length > shown.length ? `\uFF0C\u5C55\u793A\u524D ${shown.length} \u6761` : ""}\uFF09\uFF1A`);
36672
+ for (const a of shown) lines.push(` - p.${a.pageIndex ?? "?"} ${String(a.text ?? "").slice(0, 120)}${a.note ? ` \uFF5C \u7B14\u8BB0\uFF1A${String(a.note).slice(0, 120)}` : ""}`);
36673
+ }
36674
+ }
36675
+ return lines.join("\n") + "\n[\u4E0B\u4E00\u6B65] literature_cite \u751F\u6210\u5F15\u7528 \xB7 literature_note \u8BB0\u5F55\u5173\u7CFB";
36676
+ }
36677
+ };
36678
+ }
36679
+ function citeTool() {
36680
+ return {
36681
+ name: "literature_cite",
36682
+ description: "\u751F\u6210\u89C4\u8303\u5316\u7684\u5F15\u7528\u6587\u672C\uFF08APA 7 / GB/T 7714 / MLA 9 / Chicago 17 / BibTeX\uFF09\uFF0C\u652F\u6301\u53C2\u8003\u6587\u732E\u6761\u76EE\u3001\u6587\u5185\u5F15\u7528\u4E0E\u5E26\u9875\u7801\u7684\u76F4\u63A5\u5F15\u7528\u3002\u5199\u4F5C\u4E2D\u9700\u8981\u5F15\u7528\u6587\u732E\u65F6\u76F4\u63A5\u8C03\u7528\uFF0C\u4E0D\u8981\u624B\u5DE5\u62FC\u88C5\u4F5C\u8005\u4E0E\u5E74\u4EFD\u3002",
36683
+ parameters: {
36684
+ type: "object",
36685
+ properties: {
36686
+ key: { type: "string", description: "\u6761\u76EE key" },
36687
+ style: { type: "string", description: "apa | gb | mla | chicago | bibtex\uFF0C\u9ED8\u8BA4 apa" },
36688
+ mode: { type: "string", description: "reference\uFF08\u9ED8\u8BA4\uFF09| intext | direct" },
36689
+ pages: { type: "string", description: "\u76F4\u63A5\u5F15\u7528\u7684\u9875\u7801\uFF0C\u5982 12 \u6216 12-15" }
36690
+ },
36691
+ required: ["key"]
36692
+ },
36693
+ output: textResult(),
36694
+ timeoutMs: 15e3,
36695
+ async execute(args) {
36696
+ const key = String(args?.key ?? "");
36697
+ if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
36698
+ const item = await getItem(key);
36699
+ 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
+ const { citeDetailed: citeDetailed2 } = await Promise.resolve().then(() => (init_cite(), cite_exports));
36701
+ const d = citeDetailed2(item.record, {
36702
+ style: args?.style ?? "apa",
36703
+ mode: args?.mode ?? "reference",
36704
+ pages: args?.pages
36705
+ });
36706
+ return `${d.text}
36707
+ \uFF08${d.style} \xB7 ${d.mode}\uFF09
36708
+ [\u4E0B\u4E00\u6B65] literature_verify \u6838\u9A8C\u5F15\u7528\u771F\u5B9E\u6027 \xB7 literature_note \u8BB0\u5F55\u5B83\u548C\u5F53\u524D\u5199\u4F5C\u7684\u5173\u7CFB`;
36709
+ }
36710
+ };
36711
+ }
36712
+ function noteTool() {
36713
+ return {
36714
+ name: "literature_note",
36715
+ description: "\u628A\u4E00\u6761\u7B14\u8BB0\u5199\u56DE\u6587\u732E\u6761\u76EE\uFF1A\u8FD9\u7BC7\u6587\u732E\u4E0E\u7528\u6237\u5F53\u524D\u5199\u4F5C/\u7814\u7A76\u7684\u5173\u7CFB\u3001\u53EF\u7528\u8BBA\u70B9\u3001\u5F85\u9A8C\u8BC1\u4E4B\u5904\u3002\u4F1A\u8FFD\u52A0\u4FDD\u5B58\uFF0C\u4E0B\u6B21\u68C0\u7D22\u8BE5\u6761\u76EE\u65F6\u80FD\u88AB\u627E\u56DE\u3002",
36716
+ parameters: {
36717
+ type: "object",
36718
+ properties: {
36719
+ key: { type: "string", description: "\u6761\u76EE key" },
36720
+ note: { type: "string", description: "\u8981\u8BB0\u5F55\u7684\u7B14\u8BB0\u5185\u5BB9" }
36721
+ },
36722
+ required: ["key", "note"]
36723
+ },
36724
+ output: textResult(),
36725
+ timeoutMs: 15e3,
36726
+ async execute(args) {
36727
+ const key = String(args?.key ?? "");
36728
+ const note = String(args?.note ?? "").trim();
36729
+ if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
36730
+ if (!note) return "\u7B14\u8BB0\u5185\u5BB9\u4E3A\u7A7A\uFF0C\u672A\u5199\u5165\u3002";
36731
+ const item = await getItem(key);
36732
+ if (!item) return `\u672A\u627E\u5230\u6761\u76EE ${key}\u3002`;
36733
+ const notes = Array.isArray(item.notes) ? item.notes : [];
36734
+ 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
+ const entry = { text: note, at: (/* @__PURE__ */ new Date()).toISOString() };
36736
+ await patchItem(key, { notes: [...notes, entry] });
36737
+ return `\u5DF2\u8BB0\u5F55\u5230\u6761\u76EE ${key}\uFF08\u5171 ${notes.length + 1} \u6761\u7B14\u8BB0\uFF09\u3002`;
36738
+ }
36739
+ };
36740
+ }
36741
+ function statusTool() {
36742
+ return {
36743
+ name: "literature_status",
36744
+ description: "\u67E5\u770B\u6587\u732E\u5E93\u7684\u5F53\u524D\u72B6\u6001\uFF1A\u6761\u76EE\u603B\u6570\u3001\u5404\u72B6\u6001\u5206\u5E03\u3001\u6700\u8FD1\u6DFB\u52A0\u7684\u6761\u76EE\u3001\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u3002\u5728\u5F00\u59CB\u6587\u732E\u5DE5\u4F5C\u524D\u4E86\u89E3\u5E93\u91CC\u6709\u4EC0\u4E48\u65F6\u8C03\u7528\u3002",
36745
+ parameters: { type: "object", properties: {}, required: [] },
36746
+ output: textResult(),
36747
+ timeoutMs: 15e3,
36748
+ async execute() {
36749
+ const items = await listItems();
36750
+ const byState = {};
36751
+ for (const i of items) {
36752
+ const s = i.state ?? "unknown";
36753
+ byState[s] = (byState[s] ?? 0) + 1;
36754
+ }
36755
+ const recent = [...items].sort((a, b) => Number(b.createdAt ?? 0) - Number(a.createdAt ?? 0)).slice(0, 5).map((i) => `- ${i.record?.title ?? i.title ?? i.display ?? "(\u65E0\u6807\u9898)"} [key=${i.key}]`);
36756
+ const running = (await listTasks()).filter((t) => t.status === "running");
36757
+ return [
36758
+ `\u6761\u76EE\u603B\u6570\uFF1A${items.length}`,
36759
+ `\u72B6\u6001\u5206\u5E03\uFF1A${Object.entries(byState).map(([k, v]) => `${k}=${v}`).join(", ") || "\u2014"}`,
36760
+ running.length ? `\u8FDB\u884C\u4E2D\u4EFB\u52A1\uFF1A${running.map((t) => `${t.key}(${t.progress ?? 0}%)`).join(", ")}` : "\u8FDB\u884C\u4E2D\u4EFB\u52A1\uFF1A\u65E0",
36761
+ recent.length ? `\u6700\u8FD1\u6DFB\u52A0\uFF1A
36762
+ ${recent.join("\n")}` : "\u5E93\u662F\u7A7A\u7684\u3002"
36763
+ ].join("\n") + NEXT_STEP;
36764
+ }
36765
+ };
36766
+ }
36767
+ function figureTool() {
36768
+ const CHART_TYPES = /* @__PURE__ */ new Set(["bar", "line", "pie"]);
36769
+ return {
36770
+ name: "literature_figure",
36771
+ description: "\u6839\u636E\u8868\u683C\u6570\u636E\u7ED8\u5236\u793A\u610F\u56FE\u5E76\u63D2\u5165\u5F53\u524D\u5BF9\u8BDD\uFF08\u67F1\u72B6\u56FE/\u6298\u7EBF\u56FE/\u997C\u56FE\uFF09\u3002\u4EC5\u5728\u7528\u6237\u660E\u786E\u8981\u6C42\u300C\u753B\u4E2A\u56FE/\u53EF\u89C6\u5316/\u505A\u793A\u610F\u56FE\u300D\u65F6\u8C03\u7528\uFF1B\u4E0D\u8981\u5728\u6CA1\u6709\u6570\u636E\u4F9D\u636E\u65F6\u51ED\u7A7A\u7F16\u9020\u6570\u503C\u3002",
36772
+ parameters: {
36773
+ type: "object",
36774
+ properties: {
36775
+ title: { type: "string", description: "\u56FE\u8868\u6807\u9898\uFF08\u4E5F\u4F1A\u4F5C\u4E3A\u6D88\u606F\u6807\u9898\uFF09" },
36776
+ categories: { type: "array", items: { type: "string" }, description: '\u6A2A\u8F74\u7C7B\u522B\uFF0C\u5982 ["2023","2024","2025"]' },
36777
+ series: {
36778
+ type: "array",
36779
+ description: "\u6570\u636E\u7CFB\u5217\uFF0C\u6BCF\u9879 { name, values }\uFF0Cvalues \u4E0E categories \u7B49\u957F",
36780
+ items: {
36781
+ type: "object",
36782
+ properties: {
36783
+ name: { type: "string" },
36784
+ values: { type: "array", items: { type: "number" } }
36785
+ },
36786
+ required: ["name", "values"]
36787
+ }
36051
36788
  },
36052
- required: ["key"]
36789
+ chartType: { type: "string", description: "bar\uFF08\u9ED8\u8BA4\uFF09| line | pie" },
36790
+ caption: { type: "string", description: "\u56FE\u4E0B\u8BF4\u660E\u6587\u5B57" },
36791
+ key: { type: "string", description: "\u53EF\u9009\uFF1A\u6570\u636E\u6765\u6E90\u6761\u76EE key\uFF08\u4FBF\u4E8E\u6807\u6CE8\u51FA\u5904\uFF09" }
36053
36792
  },
36054
- output: textResult(),
36055
- timeoutMs: 3e5,
36056
- async execute(args) {
36057
- const key = String(args?.key ?? "");
36058
- if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
36059
- const tags = String(args?.tags ?? "").split(",").map((t) => t.trim()).filter(Boolean);
36060
- const item = await saveItem(key, { mode: args?.mode, tags });
36061
- if (!item) return `\u627E\u4E0D\u5230\u6761\u76EE ${key}\u3002`;
36062
- if (item.state === "saved") {
36063
- return `\u5DF2\u4FDD\u5B58\uFF1A${shortLabel(item.record ?? {})}\uFF08${item.saveMode === "dir" ? item.export?.pdfPath : "Zotero \u5E93"}\uFF09`;
36064
- }
36065
- return `\u4FDD\u5B58\u5931\u8D25\uFF1A${item.error?.message ?? "\u672A\u77E5\u9519\u8BEF"}\uFF08${item.error?.code ?? "unknown"}\uFF09`;
36793
+ required: ["title", "categories", "series"]
36794
+ },
36795
+ output: textResult(),
36796
+ timeoutMs: 12e4,
36797
+ async execute(args, exec) {
36798
+ const title = String(args?.title ?? "").trim() || "\u793A\u610F\u56FE";
36799
+ const categories = Array.isArray(args?.categories) ? args.categories.map(String) : [];
36800
+ const series = Array.isArray(args?.series) ? args.series.map((s) => ({ name: String(s?.name ?? "series"), values: (Array.isArray(s?.values) ? s.values : []).map((v) => Number(v)) })).filter((s) => s.values.length) : [];
36801
+ const chartType = CHART_TYPES.has(args?.chartType) ? args.chartType : "bar";
36802
+ if (!categories.length || !series.length) return "\u7F3A\u5C11\u6570\u636E\uFF08categories \u6216 series \u4E3A\u7A7A\uFF09\u3002\u793A\u610F\u56FE\u9700\u8981\u771F\u5B9E\u6570\u636E\uFF0C\u4E0D\u80FD\u51ED\u7A7A\u7ED8\u5236\u3002";
36803
+ const { figureInterpreter: figureInterpreter2 } = await Promise.resolve().then(() => (init_pyenv(), pyenv_exports));
36804
+ const fig = await figureInterpreter2();
36805
+ if (!fig || !fig.hasMatplotlib) {
36806
+ 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
+ }
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");
36812
+ const script = [
36813
+ "import matplotlib",
36814
+ "matplotlib.use('Agg')",
36815
+ "import matplotlib.pyplot as plt",
36816
+ // CJK glyphs are missing from matplotlib's default font (DejaVu Sans),
36817
+ // which turns Chinese labels into tofu boxes. Pick the first installed
36818
+ // CJK-capable font; degrade silently on non-CJK systems.
36819
+ "from matplotlib import font_manager",
36820
+ "_available = {f.name for f in font_manager.fontManager.ttflist}",
36821
+ "for _name in ['Microsoft YaHei', 'SimHei', 'PingFang SC', 'Noto Sans CJK SC', 'Source Han Sans SC', 'WenQuanYi Zen Hei']:",
36822
+ " if _name in _available:",
36823
+ " plt.rcParams['font.sans-serif'] = [_name]",
36824
+ " break",
36825
+ "plt.rcParams['axes.unicode_minus'] = False",
36826
+ `categories = ${JSON.stringify(categories)}`,
36827
+ `series = ${JSON.stringify(series)}`,
36828
+ `chart_type = ${JSON.stringify(chartType)}`,
36829
+ `title = ${JSON.stringify(title)}`,
36830
+ "fig, ax = plt.subplots(figsize=(7, 4.2), dpi=150)",
36831
+ "if chart_type == 'pie':",
36832
+ " vals = series[0]['values']",
36833
+ " ax.pie(vals, labels=categories, autopct='%1.1f%%', startangle=90)",
36834
+ " ax.axis('equal')",
36835
+ "elif chart_type == 'line':",
36836
+ " for s in series: ax.plot(categories, s['values'], marker='o', label=s['name'])",
36837
+ " ax.legend()",
36838
+ "else:",
36839
+ " import numpy as np",
36840
+ " x = np.arange(len(categories)); w = 0.8 / max(len(series), 1)",
36841
+ " for i, s in enumerate(series): ax.bar(x + i * w, s['values'], w, label=s['name'])",
36842
+ " ax.set_xticks(x + w * (len(series) - 1) / 2); ax.set_xticklabels(categories)",
36843
+ " ax.legend()",
36844
+ "ax.set_title(title)",
36845
+ "plt.tight_layout()",
36846
+ `plt.savefig(${JSON.stringify(pngFile)})`
36847
+ ].join("\n");
36848
+ await writeFile5(pyFile, script, "utf8");
36849
+ const { execFile: execFile2 } = await import("node:child_process");
36850
+ const run2 = () => new Promise((resolve6) => execFile2(fig.exe, [pyFile], { timeout: 6e4, windowsHide: true }, (err, stdout, stderr) => resolve6({ err, stdout, stderr })));
36851
+ const r = await run2();
36852
+ let png = null;
36853
+ try {
36854
+ png = await readFile6(pngFile);
36855
+ } catch {
36066
36856
  }
36067
- })
36068
- );
36069
- log("tools registered: zotero_lookup, zotero_save");
36070
- return disposers;
36857
+ await rm(dir, { recursive: true, force: true }).catch(() => {
36858
+ });
36859
+ if (!png) return "\u7ED8\u56FE\u5931\u8D25\uFF1A" + (r.stderr || r.stdout || "\u672A\u77E5\u9519\u8BEF").slice(0, 300);
36860
+ const { sendFigure: sendFigure2 } = await Promise.resolve().then(() => (init_ai(), ai_exports));
36861
+ const sourceNote = args?.key ? `\uFF08\u6570\u636E\u6765\u6E90\uFF1A\u6761\u76EE ${args.key}\uFF09` : "";
36862
+ try {
36863
+ await sendFigure2(ctx, { png, title, caption: `${args?.caption ?? ""}${sourceNote}`.trim(), sessionId: exec?.agent?.sessionId ?? null });
36864
+ return `\u793A\u610F\u56FE\u300C${title}\u300D\u5DF2\u751F\u6210\u5E76\u63D2\u5165\u5F53\u524D\u5BF9\u8BDD\u3002`;
36865
+ } catch (e) {
36866
+ if (e?.code === "no_session") return "\u793A\u610F\u56FE\u5DF2\u751F\u6210\uFF0C\u4F46\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u5BF9\u8BDD\u53EF\u63D2\u5165\u3002\u8BF7\u5148\u6253\u5F00\u4E00\u4E2A\u5BF9\u8BDD\u518D\u8BA9\u6211\u753B\u56FE\u3002";
36867
+ return "\u56FE\u7247\u63D2\u5165\u5BF9\u8BDD\u5931\u8D25\uFF1A" + (e?.message ?? "\u672A\u77E5\u9519\u8BEF");
36868
+ }
36869
+ }
36870
+ };
36871
+ }
36872
+ function saveTool() {
36873
+ return {
36874
+ name: "literature_save",
36875
+ description: "\u628A\u4FA7\u7A97\u4E2D\u5DF2\u8BC6\u522B\u7684\u6587\u732E\u4FDD\u5B58\u5230\u672C\u5730\u6587\u732E\u5E93\u6216\u5BFC\u51FA\u76EE\u5F55\uFF08\u4F1A\u81EA\u52A8\u4E0B\u8F7D\u5168\u6587 PDF\uFF09\u3002",
36876
+ parameters: {
36877
+ type: "object",
36878
+ properties: {
36879
+ key: { type: "string", description: "\u6761\u76EE key\uFF08\u6765\u81EA literature_lookup \u6216 literature_search \u7684\u8FD4\u56DE\uFF09" },
36880
+ mode: { type: "string", description: "\u4FDD\u5B58\u65B9\u5F0F\uFF1Azotero \u6216 dir\uFF0C\u7F3A\u7701\u7528\u914D\u7F6E\u503C" },
36881
+ tags: { type: "string", description: "\u9017\u53F7\u5206\u9694\u7684\u6807\u7B7E" }
36882
+ },
36883
+ required: ["key"]
36884
+ },
36885
+ output: textResult(),
36886
+ timeoutMs: 3e5,
36887
+ async execute(args) {
36888
+ const key = String(args?.key ?? "");
36889
+ if (!key) return "\u7F3A\u5C11\u6761\u76EE key\u3002";
36890
+ const tags = String(args?.tags ?? "").split(",").map((t) => t.trim()).filter(Boolean);
36891
+ const item = await saveItem(key, { mode: args?.mode, tags });
36892
+ if (!item) return `\u627E\u4E0D\u5230\u6761\u76EE ${key}\u3002`;
36893
+ if (item.state === "saved") {
36894
+ return `\u5DF2\u4FDD\u5B58\uFF1A${shortLabel(item.record ?? {})}\uFF08${item.saveMode === "dir" ? item.export?.pdfPath : "\u672C\u5730\u6587\u732E\u5E93"}\uFF09
36895
+ [\u4E0B\u4E00\u6B65] literature_get \u67E5\u770B\u8BE6\u60C5 \xB7 literature_cite \u751F\u6210\u5F15\u7528`;
36896
+ }
36897
+ return `\u4FDD\u5B58\u5931\u8D25\uFF1A${item.error?.message ?? "\u672A\u77E5\u9519\u8BEF"}\uFF08${item.error?.code ?? "unknown"}\uFF09`;
36898
+ }
36899
+ };
36071
36900
  }
36072
36901
 
36073
36902
  // src/node/session-hook.js
@@ -36104,11 +36933,15 @@ function textFromSessionEvent(event) {
36104
36933
  }
36105
36934
  return "";
36106
36935
  }
36107
- function registerSessionHook(ctx) {
36936
+ function registerSessionHook(ctx2, { activation: activation2, detectIntent: detectIntent2 } = {}) {
36108
36937
  const disposers = [];
36109
36938
  disposers.push(
36110
- ctx.on("session/event", (session, event) => {
36939
+ ctx2.on("session/event", (session, event) => {
36111
36940
  const text = textFromSessionEvent(event);
36941
+ if (activation2 && detectIntent2 && event?.type === "user/message") {
36942
+ const verdict = detectIntent2(textFromSessionEvent(event));
36943
+ if (verdict.active) activation2.activate(verdict.reason);
36944
+ }
36112
36945
  if (!text || text.length < 20) return;
36113
36946
  if (!extractIdentifiers(text).length) return;
36114
36947
  checkConfig().then((config) => {
@@ -36130,26 +36963,184 @@ async function checkConfig() {
36130
36963
  return cachedConfig;
36131
36964
  }
36132
36965
 
36966
+ // src/node/activation.js
36967
+ var IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
36968
+ var STRONG = [
36969
+ "\u6587\u732E",
36970
+ "\u8BBA\u6587",
36971
+ "\u53C2\u8003\u6587\u732E",
36972
+ "\u5F15\u7528\u683C\u5F0F",
36973
+ "\u5F15\u6587",
36974
+ "\u7EFC\u8FF0",
36975
+ "\u5F00\u9898",
36976
+ "\u7EC4\u4F1A",
36977
+ "doi",
36978
+ "arxiv",
36979
+ "pmid",
36980
+ "isbn",
36981
+ "bibtex",
36982
+ "apa",
36983
+ "mla",
36984
+ "chicago",
36985
+ "gb/t 7714",
36986
+ "gbt7714",
36987
+ "abstract",
36988
+ "citation",
36989
+ "reference list",
36990
+ "related work",
36991
+ "literature review",
36992
+ "paper",
36993
+ "preprint",
36994
+ "thesis",
36995
+ " dissertation"
36996
+ ];
36997
+ var WEAK = ["\u641C\u96C6", "\u6536\u96C6", "\u68C0\u7D22", "\u67E5\u9605", "\u6574\u7406", "\u51C6\u5907", "\u8C03\u7814", "\u67E5\u4E00\u4E0B", "\u627E\u51E0\u7BC7", "search", "collect", "gather", "find some"];
36998
+ var ACADEMIC_COMPANION = [
36999
+ "\u6587\u732E",
37000
+ "\u8BBA\u6587",
37001
+ "\u8D44\u6599",
37002
+ "\u7814\u7A76",
37003
+ "\u5B66\u672F",
37004
+ "\u671F\u520A",
37005
+ "\u4F1A\u8BAE",
37006
+ "\u5B9E\u9A8C",
37007
+ "\u65B9\u6CD5",
37008
+ "\u7ED3\u8BBA",
37009
+ "research",
37010
+ "study",
37011
+ "studies",
37012
+ "academic",
37013
+ "journal",
37014
+ "conference",
37015
+ "survey"
37016
+ ];
37017
+ var NEGATIVE = [
37018
+ "\u62A5\u9519",
37019
+ "\u5D29\u6E83",
37020
+ "\u7F16\u8BD1",
37021
+ "\u6784\u5EFA",
37022
+ "\u90E8\u7F72",
37023
+ "\u5355\u5143\u6D4B\u8BD5",
37024
+ "commit",
37025
+ "merge",
37026
+ "\u91CD\u6784",
37027
+ "debug",
37028
+ "stack trace",
37029
+ "segfault",
37030
+ "npm ",
37031
+ "pnpm ",
37032
+ "yarn ",
37033
+ "git ",
37034
+ "build failed",
37035
+ "regression"
37036
+ ];
37037
+ function normalize(text) {
37038
+ return String(text ?? "").toLowerCase();
37039
+ }
37040
+ function hitCount(text, list) {
37041
+ let n = 0;
37042
+ for (const w of list) if (text.includes(w)) n += 1;
37043
+ return n;
37044
+ }
37045
+ function detectIntent(text) {
37046
+ const t = normalize(text);
37047
+ if (!t || t.length < 6) return { active: false, score: 0, reason: "empty" };
37048
+ const strong = hitCount(t, STRONG);
37049
+ if (strong > 0) {
37050
+ const neg = hitCount(t, NEGATIVE);
37051
+ if (neg > 0 && neg >= strong) return { active: false, score: 0, reason: "coding-context" };
37052
+ return { active: true, score: 1, reason: "strong-signal" };
37053
+ }
37054
+ const weak = hitCount(t, WEAK);
37055
+ if (weak > 0 && hitCount(t, ACADEMIC_COMPANION) > 0) {
37056
+ return { active: true, score: 0.6, reason: "weak+academic" };
37057
+ }
37058
+ return { active: false, score: 0, reason: "no-signal" };
37059
+ }
37060
+ function createActivation({ idleTimeoutMs = IDLE_TIMEOUT_MS } = {}) {
37061
+ const listeners = /* @__PURE__ */ new Set();
37062
+ let active = false;
37063
+ let reason = "";
37064
+ let timer = null;
37065
+ let lastActivityAt = 0;
37066
+ function emit2(next) {
37067
+ active = next;
37068
+ for (const fn of listeners) {
37069
+ try {
37070
+ fn({ active, reason });
37071
+ } catch {
37072
+ }
37073
+ }
37074
+ }
37075
+ function clearTimer() {
37076
+ if (timer) {
37077
+ clearTimeout(timer);
37078
+ timer = null;
37079
+ }
37080
+ }
37081
+ function armIdle() {
37082
+ clearTimer();
37083
+ timer = setTimeout(() => {
37084
+ if (!active) return;
37085
+ reason = "idle-timeout";
37086
+ emit2(false);
37087
+ }, idleTimeoutMs);
37088
+ timer.unref?.();
37089
+ }
37090
+ return {
37091
+ /** Mount the tools. Safe to call repeatedly — it just refreshes the idle timer. */
37092
+ activate(why = "manual") {
37093
+ lastActivityAt = Date.now();
37094
+ if (!active) {
37095
+ reason = why;
37096
+ emit2(true);
37097
+ }
37098
+ armIdle();
37099
+ },
37100
+ deactivate(why = "manual") {
37101
+ clearTimer();
37102
+ if (active) {
37103
+ reason = why;
37104
+ emit2(false);
37105
+ }
37106
+ },
37107
+ onTransition(fn) {
37108
+ listeners.add(fn);
37109
+ return () => listeners.delete(fn);
37110
+ },
37111
+ isActive: () => active,
37112
+ reason: () => reason,
37113
+ lastActivityAt: () => lastActivityAt,
37114
+ dispose() {
37115
+ clearTimer();
37116
+ listeners.clear();
37117
+ }
37118
+ };
37119
+ }
37120
+
36133
37121
  // src/node/index.js
36134
37122
  init_log();
36135
37123
  var name = "dsh-literature-pre";
36136
37124
  var inject = ["webServer", "tools"];
36137
- function apply(ctx, config) {
37125
+ function apply(ctx2, config) {
36138
37126
  const onUncaught = (e) => error("uncaught exception:", e?.stack ?? e);
36139
37127
  const onUnhandled = (e) => error("unhandled rejection:", e?.stack ?? e);
36140
37128
  process.on("uncaughtException", onUncaught);
36141
37129
  process.on("unhandledRejection", onUnhandled);
36142
37130
  const disposers = [];
36143
- ctx.effect(() => {
37131
+ ctx2.effect(() => {
36144
37132
  ensureDirs().then(() => init()).catch((e) => error("storage init failed:", e.message));
36145
37133
  }, "dsh-literature: storage");
36146
37134
  const ready = (async () => {
36147
37135
  await ensureDirs();
36148
37136
  await init();
36149
- disposers.push(...registerRoutes(ctx));
36150
- disposers.push(...registerTools(ctx));
37137
+ const activation2 = createActivation();
37138
+ const toolsCtl = registerTools(ctx2);
37139
+ disposers.push(activation2.onTransition(({ active }) => active ? toolsCtl.mount() : toolsCtl.unmount()));
37140
+ disposers.push(() => activation2.dispose());
37141
+ disposers.push(...registerRoutes(ctx2, { activation: activation2 }));
36151
37142
  try {
36152
- disposers.push(...registerSessionHook(ctx));
37143
+ disposers.push(...registerSessionHook(ctx2, { activation: activation2, detectIntent }));
36153
37144
  } catch (e) {
36154
37145
  error("session hook unavailable:", e.message);
36155
37146
  }