@poe-platform/safe-bash 0.1.759 → 0.1.761

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 (38) hide show
  1. package/dist/image-ast/index.browser.js +74 -17
  2. package/dist/image-ast/index.js +74 -17
  3. package/dist/pdf-ast/ast.d.ts +8 -3
  4. package/dist/pdf-ast/index.js +80 -20
  5. package/dist/safe-bash/chunks/{chunk-AYPUGSOV.js → chunk-CRQDMBQA.js} +123 -8
  6. package/dist/safe-bash/command-chunks/{chunk-HVEAK3OS.js → chunk-6VX5ZQL5.js} +2 -2
  7. package/dist/safe-bash/command-chunks/{chunk-7JA44PVV.js → chunk-GR725WRX.js} +1 -1
  8. package/dist/safe-bash/command-chunks/{chunk-BAUGDXLZ.js → chunk-OSMLVM7P.js} +79 -17
  9. package/dist/safe-bash/commands/htmlq/index.d.ts +1 -1
  10. package/dist/safe-bash/commands/htmlq/index.js +4 -1
  11. package/dist/safe-bash/commands/python/index.browser.js +1 -1
  12. package/dist/safe-bash/commands/python/index.d.ts +1 -1
  13. package/dist/safe-bash/commands/python/llm-capability.d.ts +7 -3
  14. package/dist/safe-bash/commands/python/llm-capability.js +149 -10
  15. package/dist/safe-bash/core.browser.js +4 -3
  16. package/dist/safe-bash/shell/runtime.js +1 -1
  17. package/dist/safe-bash-command-ffmpeg/index.js +3125 -3085
  18. package/dist/safe-bash-command-gh/index.js +128 -27
  19. package/dist/safe-bash-command-git/LICENSE +21 -0
  20. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  21. package/dist/safe-bash-command-pandoc/command.js +3 -3
  22. package/dist/safe-bash-command-pandoc/index.js +3 -3
  23. package/dist/safe-bash-command-pdfimages/index.js +74 -17
  24. package/dist/safe-bash-command-pdfinfo/index.js +78 -20
  25. package/dist/safe-bash-command-pdftk/index.js +74 -17
  26. package/dist/safe-bash-command-pdftoppm/index.js +78 -20
  27. package/dist/safe-bash-command-pdftotext/index.js +74 -17
  28. package/dist/safe-bash-command-qpdf/index.js +74 -17
  29. package/dist/safe-bash-command-sips/index.js +2 -2
  30. package/dist/safe-bash-command-soffice/index.js +1 -1
  31. package/dist/safe-bash-command-ssconvert/index.js +74 -17
  32. package/dist/safe-bash-command-wkhtmltopdf/index.js +74 -17
  33. package/dist/safe-bash-io-engine/internal.d.ts +2 -2
  34. package/dist/safe-bash-mcp/index.d.ts +1 -1
  35. package/package.json +2 -2
  36. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +30 -0
  37. package/third-party/pdf-ast/licenses/AGG-2.3.txt +7 -0
  38. package/third-party/pdf-ast/licenses/MIT.txt +21 -0
@@ -1738,9 +1738,90 @@ function record(value) {
1738
1738
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError("Expected a structured Python LLM request");
1739
1739
  return value;
1740
1740
  }
1741
+ function jsonBytes(value, limit) {
1742
+ if (limit === Infinity) return 0;
1743
+ let bytes = 0;
1744
+ const ancestors = /* @__PURE__ */ new Set();
1745
+ const add2 = (size) => {
1746
+ if (size > limit - bytes) throw new RangeError("Python LLM serialized response limit exceeded");
1747
+ bytes += size;
1748
+ };
1749
+ const string = (text2) => {
1750
+ add2(2);
1751
+ if (text2.length > limit - bytes) throw new RangeError("Python LLM serialized response limit exceeded");
1752
+ for (let i = 0; i < text2.length; i++) {
1753
+ const point = text2.codePointAt(i);
1754
+ if (point > 65535) {
1755
+ add2(4);
1756
+ i++;
1757
+ } else if (point === 34 || point === 92) add2(2);
1758
+ else if (point < 32) add2([8, 9, 10, 12, 13].includes(point) ? 2 : 6);
1759
+ else if (point >= 55296 && point <= 57343) add2(6);
1760
+ else add2(point < 128 ? 1 : point < 2048 ? 2 : 3);
1761
+ }
1762
+ };
1763
+ const visit = (item) => {
1764
+ if (typeof item === "string") {
1765
+ string(item);
1766
+ return;
1767
+ }
1768
+ if (item === null || typeof item === "boolean" || typeof item === "number" && Number.isFinite(item)) {
1769
+ add2(JSON.stringify(item).length);
1770
+ return;
1771
+ }
1772
+ if (!item || typeof item !== "object" || ancestors.has(item)) throw new TypeError("Python LLM response must contain acyclic data");
1773
+ ancestors.add(item);
1774
+ add2(2);
1775
+ let entries = 0;
1776
+ if (Array.isArray(item)) {
1777
+ if (item.length > limit - bytes) throw new RangeError("Python LLM serialized response limit exceeded");
1778
+ for (let i = 0; i < item.length; i++) {
1779
+ const descriptor = Object.getOwnPropertyDescriptor(item, String(i));
1780
+ if (!descriptor || !("value" in descriptor)) throw new TypeError("Python LLM response must contain data");
1781
+ if (entries++) add2(1);
1782
+ visit(descriptor.value);
1783
+ }
1784
+ } else {
1785
+ for (const key in item) {
1786
+ if (!Object.hasOwn(item, key)) continue;
1787
+ const descriptor = Object.getOwnPropertyDescriptor(item, key);
1788
+ if (!("value" in descriptor)) throw new TypeError("Python LLM response must contain data");
1789
+ if (entries++) add2(1);
1790
+ string(key);
1791
+ add2(1);
1792
+ visit(descriptor.value);
1793
+ }
1794
+ }
1795
+ ancestors.delete(item);
1796
+ };
1797
+ visit(value);
1798
+ return bytes;
1799
+ }
1800
+ function* textFragments(text2, limit) {
1801
+ let start = 0, bytes = 0;
1802
+ for (let i = 0; i < text2.length; ) {
1803
+ const point = text2.codePointAt(i);
1804
+ const width = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
1805
+ if (width > limit) throw new RangeError("Python LLM stream chunk limit cannot fit a Unicode scalar");
1806
+ if (width > limit - bytes) {
1807
+ yield text2.slice(start, i);
1808
+ start = i;
1809
+ bytes = 0;
1810
+ }
1811
+ bytes += width;
1812
+ i += point > 65535 ? 2 : 1;
1813
+ }
1814
+ if (start < text2.length || !text2.length) yield text2.slice(start);
1815
+ }
1741
1816
  function createPythonLlmCapability(context, service, options = {}) {
1742
1817
  const chunkBytes = options.maxStreamChunkBytes ?? 16384;
1743
1818
  if (!Number.isSafeInteger(chunkBytes) || chunkBytes < 1) throw new RangeError("Invalid Python LLM stream chunk limit");
1819
+ const bufferedLimit = options.maxBufferedResponseBytes ?? Infinity;
1820
+ const eventLimit = options.maxBufferedEvents ?? bufferedLimit;
1821
+ const metadataLimit = options.maxMetadataBytes ?? bufferedLimit;
1822
+ for (const limit of [bufferedLimit, eventLimit, metadataLimit]) {
1823
+ if (limit !== Infinity && (!Number.isSafeInteger(limit) || limit < 1)) throw new RangeError("Invalid Python LLM host limit");
1824
+ }
1744
1825
  const prepare = async (value, signal) => {
1745
1826
  const payload = record(value);
1746
1827
  for (const key of ["template", "conversation"]) {
@@ -1797,7 +1878,15 @@ function createPythonLlmCapability(context, service, options = {}) {
1797
1878
  request.signal.throwIfAborted();
1798
1879
  yield { type: "bytes", data: Array.from(event.data.subarray(offset, offset + chunkBytes)) };
1799
1880
  }
1800
- } else yield event;
1881
+ } else if (event.type === "text") {
1882
+ for (const text2 of textFragments(event.text, chunkBytes)) {
1883
+ request.signal.throwIfAborted();
1884
+ yield { type: "text", text: text2 };
1885
+ }
1886
+ } else {
1887
+ jsonBytes(event.response, metadataLimit);
1888
+ yield event;
1889
+ }
1801
1890
  }
1802
1891
  };
1803
1892
  return {
@@ -1820,15 +1909,41 @@ function createPythonLlmCapability(context, service, options = {}) {
1820
1909
  });
1821
1910
  }
1822
1911
  if (operation.operation !== "complete") throw new TypeError("Unsupported Python LLM operation");
1823
- const text2 = [], data = [];
1912
+ const request = await prepare(payload, signal);
1913
+ const bounded = { ...request, maxOutputBytes: Math.min(request.maxOutputBytes ?? Infinity, bufferedLimit) };
1914
+ let text2 = "", textBytes = 0, dataBytes = 0, received = 0;
1915
+ const data = [];
1824
1916
  let response = {};
1825
- for await (const value2 of events(payload, { signal })) {
1826
- const event = record(value2);
1827
- if (event.type === "text") text2.push(event.text);
1828
- else if (event.type === "bytes") for (const byte of event.data) data.push(byte);
1829
- else if (event.type === "response") response = { ...record(event.response) };
1917
+ let envelopeBytes = jsonBytes({ text: "", data: [] }, bufferedLimit);
1918
+ const admit = (size) => {
1919
+ if (size > bufferedLimit - envelopeBytes - textBytes - dataBytes) throw new RangeError("Python LLM buffered response limit exceeded");
1920
+ };
1921
+ for await (const event of service.stream(bounded)) {
1922
+ bounded.signal.throwIfAborted();
1923
+ if (++received > eventLimit) throw new RangeError("Python LLM buffered event limit exceeded");
1924
+ if (event.type === "text") {
1925
+ const size = bufferedLimit === Infinity || !event.text ? 0 : jsonBytes(event.text, bufferedLimit - envelopeBytes - textBytes - dataBytes + 2) - 2;
1926
+ admit(size);
1927
+ textBytes += size;
1928
+ if (event.text) text2 += event.text;
1929
+ } else if (event.type === "bytes") {
1930
+ let size = 0;
1931
+ if (bufferedLimit !== Infinity) for (let i = 0; i < event.data.length; i++) {
1932
+ size += String(event.data[i]).length + (data.length || i ? 1 : 0);
1933
+ admit(size);
1934
+ }
1935
+ dataBytes += size;
1936
+ for (const byte of event.data) data.push(byte);
1937
+ } else {
1938
+ jsonBytes(event.response, metadataLimit);
1939
+ const details = record(event.response);
1940
+ const size = jsonBytes({ ...details, text: "", data: [] }, bufferedLimit);
1941
+ if (size > bufferedLimit - textBytes - dataBytes) throw new RangeError("Python LLM buffered response limit exceeded");
1942
+ envelopeBytes = size;
1943
+ response = { ...details };
1944
+ }
1830
1945
  }
1831
- return { ...response, text: text2.join(""), data };
1946
+ return { ...response, text: text2, data };
1832
1947
  },
1833
1948
  stream: events
1834
1949
  };
@@ -48,11 +48,11 @@ import {
48
48
  trimImage,
49
49
  unflattenImage,
50
50
  unpremultiplyRgbaImage
51
- } from "./chunk-7JA44PVV.js";
51
+ } from "./chunk-GR725WRX.js";
52
52
  import {
53
53
  PdfDocument,
54
54
  encodePng
55
- } from "./chunk-BAUGDXLZ.js";
55
+ } from "./chunk-OSMLVM7P.js";
56
56
  import {
57
57
  createLuaFilterCapability
58
58
  } from "./chunk-Y2KHC6TZ.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PdfDocument,
3
3
  renderPdfPageToPng
4
- } from "./chunk-BAUGDXLZ.js";
4
+ } from "./chunk-OSMLVM7P.js";
5
5
  import {
6
6
  init_buffer
7
7
  } from "./chunk-HX3SHTCE.js";
@@ -32422,7 +32422,7 @@ function evaluateContentStreamToDisplayList(params) {
32422
32422
  const [x, y] = transformPoint(st.ctm, seg.x, seg.y);
32423
32423
  transformedSegments.push({ kind: "cubic", x1, y1, x2, y2, x, y });
32424
32424
  } else if (seg.kind === "rect") {
32425
- if (hasRotOrShear) {
32425
+ if (hasRotOrShear || seg.width * st.ctm[0] < 0 || seg.height * st.ctm[3] < 0) {
32426
32426
  const [p0x, p0y] = transformPoint(st.ctm, seg.x, seg.y);
32427
32427
  const [p1x, p1y] = transformPoint(st.ctm, seg.x + seg.width, seg.y);
32428
32428
  const [p2x, p2y] = transformPoint(st.ctm, seg.x + seg.width, seg.y + seg.height);
@@ -32455,7 +32455,12 @@ function evaluateContentStreamToDisplayList(params) {
32455
32455
  transformedSegments.push({ kind: "close" });
32456
32456
  }
32457
32457
  }
32458
- if (node.clip && transformedSegments.length > 0) {
32458
+ const applyClip = () => {
32459
+ if (!node.clip) return;
32460
+ st.clipPaths = [...st.clipPaths ?? [], {
32461
+ segments: transformedSegments,
32462
+ fillRule: node.clip === "W*" ? "evenodd" : "nonzero"
32463
+ }];
32459
32464
  let cMinX = Infinity, cMinY = Infinity, cMaxX = -Infinity, cMaxY = -Infinity;
32460
32465
  for (const s of transformedSegments) {
32461
32466
  if (s.kind === "move" || s.kind === "line") {
@@ -32483,8 +32488,11 @@ function evaluateContentStreamToDisplayList(params) {
32483
32488
  Math.min(st.clipRect[3], cMaxY)
32484
32489
  ] : [cMinX, cMinY, cMaxX, cMaxY];
32485
32490
  }
32491
+ };
32492
+ if (node.paint === "n") {
32493
+ applyClip();
32494
+ break;
32486
32495
  }
32487
- if (node.paint === "n") break;
32488
32496
  const isFill = ["f", "F", "f*", "B", "B*", "b", "b*"].includes(node.paint);
32489
32497
  const isStroke = ["S", "s", "B", "B*", "b", "b*"].includes(node.paint);
32490
32498
  let evaluatedFillPattern = false;
@@ -32617,7 +32625,10 @@ function evaluateContentStreamToDisplayList(params) {
32617
32625
  }
32618
32626
  }
32619
32627
  }
32620
- if (evaluatedFillPattern && !isStroke) break;
32628
+ if (evaluatedFillPattern && !isStroke) {
32629
+ applyClip();
32630
+ break;
32631
+ }
32621
32632
  const fillRule = node.paint.includes("*") ? "evenodd" : "nonzero";
32622
32633
  const ctmScale = Math.max(1e-6, Math.hypot(st.ctm[0], st.ctm[1]));
32623
32634
  const scaledStrokeWidth = st.strokeWidth === 0 ? 0 : st.strokeWidth * ctmScale;
@@ -32637,6 +32648,7 @@ function evaluateContentStreamToDisplayList(params) {
32637
32648
  ...st.dashPhase !== void 0 ? { dashPhase: st.dashPhase } : {},
32638
32649
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
32639
32650
  } });
32651
+ applyClip();
32640
32652
  break;
32641
32653
  }
32642
32654
  case "xobject": {
@@ -33953,6 +33965,44 @@ function formatExtractedPageText(page, options = {}) {
33953
33965
 
33954
33966
  // packages/pdf-ast/src/render/raster.ts
33955
33967
  init_buffer();
33968
+
33969
+ // packages/pdf-ast/src/render/cubic.ts
33970
+ init_buffer();
33971
+ function flattenCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
33972
+ const points = [[x1, y1]];
33973
+ const subdivide = (ax, ay, bx, by, cx, cy, dx, dy, level) => {
33974
+ if (level > 16) return;
33975
+ const abx = (ax + bx) / 2, aby = (ay + by) / 2;
33976
+ const bcx = (bx + cx) / 2, bcy = (by + cy) / 2;
33977
+ const cdx = (cx + dx) / 2, cdy = (cy + dy) / 2;
33978
+ const abcx = (abx + bcx) / 2, abcy = (aby + bcy) / 2;
33979
+ const bcdx = (bcx + cdx) / 2, bcdy = (bcy + cdy) / 2;
33980
+ const midx = (abcx + bcdx) / 2, midy = (abcy + bcdy) / 2;
33981
+ const chordX = dx - ax, chordY = dy - ay;
33982
+ const d2 = Math.abs((bx - dx) * chordY - (by - dy) * chordX);
33983
+ const d3 = Math.abs((cx - dx) * chordY - (cy - dy) * chordX);
33984
+ const significant2 = d2 > 1e-30, significant3 = d3 > 1e-30;
33985
+ if (!significant2 && !significant3) {
33986
+ if (Math.abs(ax + cx - 2 * bx) + Math.abs(ay + cy - 2 * by) + Math.abs(bx + dx - 2 * cx) + Math.abs(by + dy - 2 * cy) <= 4) {
33987
+ points.push([midx, midy]);
33988
+ return;
33989
+ }
33990
+ } else {
33991
+ const distance = (significant2 ? d2 : 0) + (significant3 ? d3 : 0);
33992
+ if (distance * distance <= 0.25 * (chordX * chordX + chordY * chordY)) {
33993
+ points.push([bcx, bcy]);
33994
+ return;
33995
+ }
33996
+ }
33997
+ subdivide(ax, ay, abx, aby, abcx, abcy, midx, midy, level + 1);
33998
+ subdivide(midx, midy, bcdx, bcdy, cdx, cdy, dx, dy, level + 1);
33999
+ };
34000
+ subdivide(x1, y1, x2, y2, x3, y3, x4, y4, 0);
34001
+ points.push([x4, y4]);
34002
+ return points;
34003
+ }
34004
+
34005
+ // packages/pdf-ast/src/render/raster.ts
33956
34006
  function encodePng(bitmap) {
33957
34007
  return encodeRgbaToPng(bitmap.width, bitmap.height, bitmap.data);
33958
34008
  }
@@ -34719,14 +34769,11 @@ function segmentsToScreenEdges(segments, pageHeight, scale, closeSubpaths = fals
34719
34769
  const [p1x, p1y] = toScreen(seg.x1, seg.y1);
34720
34770
  const [p2x, p2y] = toScreen(seg.x2, seg.y2);
34721
34771
  const [p3x, p3y] = toScreen(seg.x, seg.y);
34722
- const steps = 12;
34772
+ const points = flattenCubic(curX, curY, p1x, p1y, p2x, p2y, p3x, p3y);
34723
34773
  let px = curX;
34724
34774
  let py = curY;
34725
- for (let s = 1; s <= steps; s++) {
34726
- const t = s / steps;
34727
- const mt = 1 - t;
34728
- const qx = mt * mt * mt * curX + 3 * mt * mt * t * p1x + 3 * mt * t * t * p2x + t * t * t * p3x;
34729
- const qy = mt * mt * mt * curY + 3 * mt * mt * t * p1y + 3 * mt * t * t * p2y + t * t * t * p3y;
34775
+ for (let i = 1; i < points.length; i++) {
34776
+ const [qx, qy] = points[i];
34730
34777
  edges.push({ x0: px, y0: py, x1: qx, y1: qy });
34731
34778
  px = qx;
34732
34779
  py = qy;
@@ -34745,8 +34792,8 @@ function segmentsToScreenEdges(segments, pageHeight, scale, closeSubpaths = fals
34745
34792
  if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
34746
34793
  edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
34747
34794
  }
34748
- const [rx0, ry0] = toScreen(seg.x, seg.y + seg.height);
34749
- const [rx1, ry1] = toScreen(seg.x + seg.width, seg.y);
34795
+ const [rx0, ry0] = toScreen(seg.x, seg.y);
34796
+ const [rx1, ry1] = toScreen(seg.x + seg.width, seg.y + seg.height);
34750
34797
  edges.push(
34751
34798
  { x0: rx0, y0: ry0, x1: rx1, y1: ry0 },
34752
34799
  { x0: rx1, y0: ry0, x1: rx1, y1: ry1 },
@@ -34889,21 +34936,24 @@ function renderDisplayListToBitmap(displayList, options = {}) {
34889
34936
  }
34890
34937
  const aaVec = options.antialiasVector !== false;
34891
34938
  const aaTxt = options.antialiasText !== false;
34892
- const clipMasks = /* @__PURE__ */ new Map();
34939
+ let cachedClips;
34940
+ let cachedClipMask;
34893
34941
  const imageClipMasks = /* @__PURE__ */ new Map();
34894
34942
  for (const original of paintOperations(displayList)) {
34895
34943
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
34896
34944
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
34897
34945
  const clips = original.value.clipPaths;
34898
- let clipMask = clips ? clipMasks.get(clips) : void 0;
34946
+ let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
34899
34947
  if (clips && !clipMask) {
34900
34948
  clipMask = new Uint8Array(width * height * 4).fill(255);
34901
- for (const segments of clips) {
34949
+ for (const clip of clips) {
34950
+ const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
34902
34951
  const layer = new Uint8Array(width * height * 4);
34903
- fillEdgesScanline4x4(layer, width, height, segmentsToScreenEdges(segments, displayList.height, scale, true), { r: 1, g: 1, b: 1 });
34952
+ fillEdgesScanline4x4(layer, width, height, segmentsToScreenEdges(segments, displayList.height, scale, true), { r: 1, g: 1, b: 1 }, 1, fillRule);
34904
34953
  for (let i = 3; i < layer.length; i += 4) clipMask[i] = Math.round(clipMask[i] * layer[i] / 255);
34905
34954
  }
34906
- clipMasks.set(clips, clipMask);
34955
+ cachedClips = clips;
34956
+ cachedClipMask = clipMask;
34907
34957
  }
34908
34958
  const imageClips = original.value.clipImages;
34909
34959
  if (imageClips) {
@@ -37216,3 +37266,15 @@ export {
37216
37266
  * Copyright 2017 Mozilla Foundation. Licensed under Apache-2.0.
37217
37267
  * See licenses/PDFJS-APACHE-2.0.txt and THIRD_PARTY_NOTICES.md.
37218
37268
  */
37269
+ /*!
37270
+ * Anti-Grain Geometry - Version 2.3
37271
+ * Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
37272
+ *
37273
+ * Permission to copy, use, modify, sell and distribute this software
37274
+ * is granted provided this copyright notice appears in all copies.
37275
+ * This software is provided "as is" without express or implied
37276
+ * warranty, and with no claim as to its suitability for any purpose.
37277
+ *
37278
+ * Adapted from PDFium third_party/agg23/agg_curves.cpp, curve4_div.
37279
+ * See THIRD_PARTY_NOTICES.md for the pinned revision and adaptations.
37280
+ */
@@ -2,5 +2,5 @@ import { HtmlError, detachHtmlNode, htmlText, htmlq, htmlqBaseline, htmlqBytes,
2
2
  export { selectHtml, parseHtmlqArguments, htmlqBytes, htmlq, parseHtml, parseHtmlSync, inclusiveHtmlDescendants, serializeHtml, serializeHtmlBytes, htmlText, detachHtmlNode, HtmlError, htmlqBaseline, };
3
3
  export type { HtmlqArguments, HtmlqCommandOptions, HtmlqCommandsOptions, HtmlqRunOptions, HtmlqResult, HtmlAccounting, HtmlOptions, HtmlLimits, HtmlNode, HtmlNamespace, HtmlAttribute, HtmlErrorCode, } from "../../../safe-bash-command-htmlq/index.js";
4
4
  export { createHtmlqCommand, createHtmlqCommands, htmlqCommand, htmlqCommands } from "../../../safe-bash-command-htmlq/index.js";
5
- export declare function evalSyncHtmlq(inBytes: Uint8Array, opArgs: readonly string[], readFileSync?: (filePath: string) => Uint8Array | undefined, writeFileSync?: (filePath: string, bytes: Uint8Array) => boolean): string | undefined;
5
+ export declare function evalSyncHtmlq(inBytes: Uint8Array | undefined, opArgs: readonly string[], readFileSync?: (filePath: string) => Uint8Array | undefined, writeFileSync?: (filePath: string, bytes: Uint8Array) => boolean): string | undefined;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -17,7 +17,7 @@ const syncHtmlLimits = Object.freeze({
17
17
  outputBytes: Infinity,
18
18
  });
19
19
  export function evalSyncHtmlq(inBytes, opArgs, readFileSync, writeFileSync) {
20
- if (inBytes.byteLength > 16384)
20
+ if (inBytes && inBytes.byteLength > 16384)
21
21
  return undefined;
22
22
  try {
23
23
  const invocation = invocationOptions({ signal: syncAbortSignal(), limits: syncHtmlLimits });
@@ -33,6 +33,9 @@ export function evalSyncHtmlq(inBytes, opArgs, readFileSync, writeFileSync) {
33
33
  return undefined;
34
34
  srcBytes = fBytes;
35
35
  }
36
+ // Missing bytes mean inherited stdin has not been collected by the fast path.
37
+ if (!srcBytes)
38
+ return undefined;
36
39
  const budget = new HtmlBudget(invocation);
37
40
  const original = syncHtmlDecoder.decode(srcBytes);
38
41
  const document = parseHtmlSync(original, invocation, budget);
@@ -16,7 +16,7 @@ import {
16
16
  pythonCommands,
17
17
  pythonDocumentPackages,
18
18
  pythonHostFailureCode
19
- } from "../../chunks/chunk-AYPUGSOV.js";
19
+ } from "../../chunks/chunk-CRQDMBQA.js";
20
20
  import {
21
21
  PythonFailure,
22
22
  inspectPythonCapabilities
@@ -4,7 +4,7 @@ import { type PythonDiagnosticObserver } from './diagnostics.js';
4
4
  import { createPythonHostBridge, type PythonHostCapability, type PythonHostBridgeOptions } from './host-capabilities.js';
5
5
  export * from './host-capabilities.js';
6
6
  export { createPythonShellCapability } from './shell-capability.js';
7
- export { createPythonLlmCapability } from './llm-capability.js';
7
+ export { createPythonLlmCapability, type PythonLlmCapabilityOptions } from './llm-capability.js';
8
8
  /** A dedicated interpreter worker. The service event loop must never block. */
9
9
  export interface PythonWorkerEndpoint {
10
10
  postMessage(value: unknown): void;
@@ -1,8 +1,12 @@
1
1
  import type { CommandContext } from '../../contracts/index.js';
2
2
  import type { LlmService } from '../llm/service.js';
3
3
  import type { PythonHostCapability } from './host-capabilities.js';
4
- /** Reuses the invocation's authorized service; Python receives only model data. */
5
- export declare function createPythonLlmCapability(context: Pick<CommandContext, 'fs' | 'cwd' | 'inputBudget'>, service: LlmService, options?: {
4
+ export interface PythonLlmCapabilityOptions {
6
5
  readonly maxStreamChunkBytes?: number;
7
- }): PythonHostCapability;
6
+ readonly maxBufferedResponseBytes?: number;
7
+ readonly maxBufferedEvents?: number;
8
+ readonly maxMetadataBytes?: number;
9
+ }
10
+ /** Reuses the invocation's authorized service; Python receives only model data. */
11
+ export declare function createPythonLlmCapability(context: Pick<CommandContext, 'fs' | 'cwd' | 'inputBudget'>, service: LlmService, options?: PythonLlmCapabilityOptions): PythonHostCapability;
8
12
  //# sourceMappingURL=llm-capability.d.ts.map
@@ -5,11 +5,112 @@ function record(value) {
5
5
  throw new TypeError('Expected a structured Python LLM request');
6
6
  return value;
7
7
  }
8
+ /** Count the wire representation before retaining/serializing host metadata. */
9
+ function jsonBytes(value, limit) {
10
+ if (limit === Infinity)
11
+ return 0;
12
+ let bytes = 0;
13
+ const ancestors = new Set();
14
+ const add = (size) => {
15
+ if (size > limit - bytes)
16
+ throw new RangeError('Python LLM serialized response limit exceeded');
17
+ bytes += size;
18
+ };
19
+ const string = (text) => {
20
+ add(2);
21
+ if (text.length > limit - bytes)
22
+ throw new RangeError('Python LLM serialized response limit exceeded');
23
+ for (let i = 0; i < text.length; i++) {
24
+ const point = text.codePointAt(i);
25
+ if (point > 65535) {
26
+ add(4);
27
+ i++;
28
+ }
29
+ else if (point === 34 || point === 92)
30
+ add(2);
31
+ else if (point < 32)
32
+ add([8, 9, 10, 12, 13].includes(point) ? 2 : 6);
33
+ else if (point >= 0xd800 && point <= 0xdfff)
34
+ add(6);
35
+ else
36
+ add(point < 128 ? 1 : point < 2048 ? 2 : 3);
37
+ }
38
+ };
39
+ const visit = (item) => {
40
+ if (typeof item === 'string') {
41
+ string(item);
42
+ return;
43
+ }
44
+ if (item === null || typeof item === 'boolean' || typeof item === 'number' && Number.isFinite(item)) {
45
+ add(JSON.stringify(item).length);
46
+ return;
47
+ }
48
+ if (!item || typeof item !== 'object' || ancestors.has(item))
49
+ throw new TypeError('Python LLM response must contain acyclic data');
50
+ ancestors.add(item);
51
+ add(2);
52
+ let entries = 0;
53
+ if (Array.isArray(item)) {
54
+ if (item.length > limit - bytes)
55
+ throw new RangeError('Python LLM serialized response limit exceeded');
56
+ for (let i = 0; i < item.length; i++) {
57
+ const descriptor = Object.getOwnPropertyDescriptor(item, String(i));
58
+ if (!descriptor || !('value' in descriptor))
59
+ throw new TypeError('Python LLM response must contain data');
60
+ if (entries++)
61
+ add(1);
62
+ visit(descriptor.value);
63
+ }
64
+ }
65
+ else {
66
+ for (const key in item) {
67
+ if (!Object.hasOwn(item, key))
68
+ continue;
69
+ const descriptor = Object.getOwnPropertyDescriptor(item, key);
70
+ if (!('value' in descriptor))
71
+ throw new TypeError('Python LLM response must contain data');
72
+ if (entries++)
73
+ add(1);
74
+ string(key);
75
+ add(1);
76
+ visit(descriptor.value);
77
+ }
78
+ }
79
+ ancestors.delete(item);
80
+ };
81
+ visit(value);
82
+ return bytes;
83
+ }
84
+ function* textFragments(text, limit) {
85
+ let start = 0, bytes = 0;
86
+ for (let i = 0; i < text.length;) {
87
+ const point = text.codePointAt(i);
88
+ const width = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
89
+ if (width > limit)
90
+ throw new RangeError('Python LLM stream chunk limit cannot fit a Unicode scalar');
91
+ if (width > limit - bytes) {
92
+ yield text.slice(start, i);
93
+ start = i;
94
+ bytes = 0;
95
+ }
96
+ bytes += width;
97
+ i += point > 65535 ? 2 : 1;
98
+ }
99
+ if (start < text.length || !text.length)
100
+ yield text.slice(start);
101
+ }
8
102
  /** Reuses the invocation's authorized service; Python receives only model data. */
9
103
  export function createPythonLlmCapability(context, service, options = {}) {
10
104
  const chunkBytes = options.maxStreamChunkBytes ?? 16384;
11
105
  if (!Number.isSafeInteger(chunkBytes) || chunkBytes < 1)
12
106
  throw new RangeError('Invalid Python LLM stream chunk limit');
107
+ const bufferedLimit = options.maxBufferedResponseBytes ?? Infinity;
108
+ const eventLimit = options.maxBufferedEvents ?? bufferedLimit;
109
+ const metadataLimit = options.maxMetadataBytes ?? bufferedLimit;
110
+ for (const limit of [bufferedLimit, eventLimit, metadataLimit]) {
111
+ if (limit !== Infinity && (!Number.isSafeInteger(limit) || limit < 1))
112
+ throw new RangeError('Invalid Python LLM host limit');
113
+ }
13
114
  const prepare = async (value, signal) => {
14
115
  const payload = record(value);
15
116
  for (const key of ['template', 'conversation']) {
@@ -73,8 +174,16 @@ export function createPythonLlmCapability(context, service, options = {}) {
73
174
  yield { type: 'bytes', data: Array.from(event.data.subarray(offset, offset + chunkBytes)) };
74
175
  }
75
176
  }
76
- else
177
+ else if (event.type === 'text') {
178
+ for (const text of textFragments(event.text, chunkBytes)) {
179
+ request.signal.throwIfAborted();
180
+ yield { type: 'text', text };
181
+ }
182
+ }
183
+ else {
184
+ jsonBytes(event.response, metadataLimit);
77
185
  yield event;
186
+ }
78
187
  }
79
188
  };
80
189
  return {
@@ -93,19 +202,49 @@ export function createPythonLlmCapability(context, service, options = {}) {
93
202
  }
94
203
  if (operation.operation !== 'complete')
95
204
  throw new TypeError('Unsupported Python LLM operation');
96
- const text = [], data = [];
205
+ const request = await prepare(payload, signal);
206
+ const bounded = { ...request, maxOutputBytes: Math.min(request.maxOutputBytes ?? Infinity, bufferedLimit) };
207
+ let text = '', textBytes = 0, dataBytes = 0, received = 0;
208
+ const data = [];
97
209
  let response = {};
98
- for await (const value of events(payload, { signal })) {
99
- const event = record(value);
100
- if (event.type === 'text')
101
- text.push(event.text);
102
- else if (event.type === 'bytes')
210
+ let envelopeBytes = jsonBytes({ text: '', data: [] }, bufferedLimit);
211
+ const admit = (size) => {
212
+ if (size > bufferedLimit - envelopeBytes - textBytes - dataBytes)
213
+ throw new RangeError('Python LLM buffered response limit exceeded');
214
+ };
215
+ for await (const event of service.stream(bounded)) {
216
+ bounded.signal.throwIfAborted();
217
+ if (++received > eventLimit)
218
+ throw new RangeError('Python LLM buffered event limit exceeded');
219
+ if (event.type === 'text') {
220
+ const size = bufferedLimit === Infinity || !event.text ? 0 : jsonBytes(event.text, bufferedLimit - envelopeBytes - textBytes - dataBytes + 2) - 2;
221
+ admit(size);
222
+ textBytes += size;
223
+ if (event.text)
224
+ text += event.text;
225
+ }
226
+ else if (event.type === 'bytes') {
227
+ let size = 0;
228
+ if (bufferedLimit !== Infinity)
229
+ for (let i = 0; i < event.data.length; i++) {
230
+ size += String(event.data[i]).length + (data.length || i ? 1 : 0);
231
+ admit(size);
232
+ }
233
+ dataBytes += size;
103
234
  for (const byte of event.data)
104
235
  data.push(byte);
105
- else if (event.type === 'response')
106
- response = { ...record(event.response) };
236
+ }
237
+ else {
238
+ jsonBytes(event.response, metadataLimit);
239
+ const details = record(event.response);
240
+ const size = jsonBytes({ ...details, text: '', data: [] }, bufferedLimit);
241
+ if (size > bufferedLimit - textBytes - dataBytes)
242
+ throw new RangeError('Python LLM buffered response limit exceeded');
243
+ envelopeBytes = size;
244
+ response = { ...details };
245
+ }
107
246
  }
108
- return { ...response, text: text.join(''), data };
247
+ return { ...response, text, data };
109
248
  },
110
249
  stream: events,
111
250
  };
@@ -158,7 +158,7 @@ import {
158
158
  sha256,
159
159
  sha384,
160
160
  sha512
161
- } from "./chunks/chunk-AYPUGSOV.js";
161
+ } from "./chunks/chunk-CRQDMBQA.js";
162
162
  import {
163
163
  PythonFailure,
164
164
  inspectPythonCapabilities
@@ -52607,7 +52607,7 @@ var syncHtmlLimits = Object.freeze({
52607
52607
  outputBytes: Infinity
52608
52608
  });
52609
52609
  function evalSyncHtmlq(inBytes, opArgs, readFileSync, writeFileSync) {
52610
- if (inBytes.byteLength > 16384) return void 0;
52610
+ if (inBytes && inBytes.byteLength > 16384) return void 0;
52611
52611
  try {
52612
52612
  const invocation = invocationOptions({ signal: syncAbortSignal3(), limits: syncHtmlLimits });
52613
52613
  const args = parseHtmlqArguments(opArgs, invocation);
@@ -52619,6 +52619,7 @@ function evalSyncHtmlq(inBytes, opArgs, readFileSync, writeFileSync) {
52619
52619
  if (!fBytes || fBytes.byteLength > 16384) return void 0;
52620
52620
  srcBytes = fBytes;
52621
52621
  }
52622
+ if (!srcBytes) return void 0;
52622
52623
  const budget = new HtmlBudget(invocation);
52623
52624
  const original = syncHtmlDecoder.decode(srcBytes);
52624
52625
  const document = parseHtmlSync(original, invocation, budget);
@@ -90388,7 +90389,7 @@ unsigned int ${ident}_len = ${view.byteLength};
90388
90389
  })() : w0Plain === "base32" ? (() => {
90389
90390
  const b32 = (0, base_exports.evalSyncBase32)(inBytes, allArgs, readFile);
90390
90391
  return b32 !== void 0 ? sharedSyncPipeDecoder.decode(b32) : void 0;
90391
- })() : w0Plain === "xq" || w0Plain === "yq" ? this.evalSyncXqOrYq(w0Plain, inBytes, allArgs, readFile) : w0Plain === "xmllint" ? evalSyncXmllint(inBytes, allArgs, readFile) : evalSyncHtmlq(inBytes, allArgs, readFile, (p, b) => {
90392
+ })() : w0Plain === "xq" || w0Plain === "yq" ? this.evalSyncXqOrYq(w0Plain, inBytes, allArgs, readFile) : w0Plain === "xmllint" ? evalSyncXmllint(inBytes, allArgs, readFile) : evalSyncHtmlq(optInBytes, allArgs, readFile, (p, b) => {
90392
90393
  try {
90393
90394
  if (this._inSyncLoopPreflight) return Boolean(this.canFastMemoryRedirect && this._isMemoryBackingFs);
90394
90395
  return tryWriteMemoryFileSync(this.backingFs, resolvePath(rawState.cwd, p), b, false, 438 & ~(rawState.umask ?? 18), this.commandSignal);
@@ -38325,7 +38325,7 @@ export class Runtime {
38325
38325
  ? this.evalSyncXqOrYq(w0Plain, inBytes, allArgs, readFile)
38326
38326
  : w0Plain === "xmllint"
38327
38327
  ? evalSyncXmllint(inBytes, allArgs, readFile)
38328
- : evalSyncHtmlq(inBytes, allArgs, readFile, (p, b) => { try {
38328
+ : evalSyncHtmlq(optInBytes, allArgs, readFile, (p, b) => { try {
38329
38329
  if (this._inSyncLoopPreflight)
38330
38330
  return Boolean(this.canFastMemoryRedirect && this._isMemoryBackingFs);
38331
38331
  return tryWriteMemoryFileSync(this.backingFs, resolvePath(rawState.cwd, p), b, false, 0o666 & ~(rawState.umask ?? 0o022), this.commandSignal);