@qvac/harness 0.7.3 → 0.8.5

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 (146) hide show
  1. package/CHANGELOG.md +87 -1
  2. package/NOTICE.md +16 -0
  3. package/dist-lib/lib/capabilities/completion.d.ts +1 -0
  4. package/dist-lib/lib/capabilities/completion.js +28 -8
  5. package/dist-lib/lib/capabilities/tool-turns.d.ts +3 -0
  6. package/dist-lib/lib/capabilities/tool-turns.js +7 -0
  7. package/dist-lib/lib/context-window.js +2 -2
  8. package/dist-lib/lib/docx/index.d.ts +1 -1
  9. package/dist-lib/lib/docx/index.js +16 -24
  10. package/dist-lib/lib/helpers/run-outcome.d.ts +4 -1
  11. package/dist-lib/lib/helpers/run-outcome.js +14 -8
  12. package/dist-lib/lib/helpers/tool-call-markup.js +4 -4
  13. package/dist-lib/lib/hooks/built-in/arg-repair.js +7 -0
  14. package/dist-lib/lib/office/engine/codes.d.ts +62 -0
  15. package/dist-lib/lib/office/engine/codes.js +61 -0
  16. package/dist-lib/lib/office/engine/docx/document.d.ts +216 -0
  17. package/dist-lib/lib/office/engine/docx/document.js +1152 -0
  18. package/dist-lib/lib/office/engine/docx/index.d.ts +7 -0
  19. package/dist-lib/lib/office/engine/docx/index.js +8 -0
  20. package/dist-lib/lib/office/engine/docx/styles.d.ts +31 -0
  21. package/dist-lib/lib/office/engine/docx/styles.js +173 -0
  22. package/dist-lib/lib/office/engine/docx/template.d.ts +18 -0
  23. package/dist-lib/lib/office/engine/docx/template.js +133 -0
  24. package/dist-lib/lib/office/engine/docx/text.d.ts +55 -0
  25. package/dist-lib/lib/office/engine/docx/text.js +538 -0
  26. package/dist-lib/lib/office/engine/drawingml/chart.d.ts +63 -0
  27. package/dist-lib/lib/office/engine/drawingml/chart.js +539 -0
  28. package/dist-lib/lib/office/engine/drawingml/text.d.ts +35 -0
  29. package/dist-lib/lib/office/engine/drawingml/text.js +352 -0
  30. package/dist-lib/lib/office/engine/errors.d.ts +6 -0
  31. package/dist-lib/lib/office/engine/errors.js +12 -0
  32. package/dist-lib/lib/office/engine/image.d.ts +8 -0
  33. package/dist-lib/lib/office/engine/image.js +48 -0
  34. package/dist-lib/lib/office/engine/index.d.ts +12 -0
  35. package/dist-lib/lib/office/engine/index.js +7 -0
  36. package/dist-lib/lib/office/engine/opc/content-types.d.ts +17 -0
  37. package/dist-lib/lib/office/engine/opc/content-types.js +74 -0
  38. package/dist-lib/lib/office/engine/opc/media.d.ts +13 -0
  39. package/dist-lib/lib/office/engine/opc/media.js +11 -0
  40. package/dist-lib/lib/office/engine/opc/package.d.ts +51 -0
  41. package/dist-lib/lib/office/engine/opc/package.js +324 -0
  42. package/dist-lib/lib/office/engine/opc/paths.d.ts +7 -0
  43. package/dist-lib/lib/office/engine/opc/paths.js +46 -0
  44. package/dist-lib/lib/office/engine/opc/properties.d.ts +7 -0
  45. package/dist-lib/lib/office/engine/opc/properties.js +75 -0
  46. package/dist-lib/lib/office/engine/opc/relationships.d.ts +23 -0
  47. package/dist-lib/lib/office/engine/opc/relationships.js +65 -0
  48. package/dist-lib/lib/office/engine/opc/zip.d.ts +15 -0
  49. package/dist-lib/lib/office/engine/opc/zip.js +264 -0
  50. package/dist-lib/lib/office/engine/pptx/fit.d.ts +12 -0
  51. package/dist-lib/lib/office/engine/pptx/fit.js +37 -0
  52. package/dist-lib/lib/office/engine/pptx/index.d.ts +8 -0
  53. package/dist-lib/lib/office/engine/pptx/index.js +8 -0
  54. package/dist-lib/lib/office/engine/pptx/inherit.d.ts +29 -0
  55. package/dist-lib/lib/office/engine/pptx/inherit.js +155 -0
  56. package/dist-lib/lib/office/engine/pptx/notes.d.ts +5 -0
  57. package/dist-lib/lib/office/engine/pptx/notes.js +85 -0
  58. package/dist-lib/lib/office/engine/pptx/presentation.d.ts +54 -0
  59. package/dist-lib/lib/office/engine/pptx/presentation.js +749 -0
  60. package/dist-lib/lib/office/engine/pptx/read.d.ts +9 -0
  61. package/dist-lib/lib/office/engine/pptx/read.js +66 -0
  62. package/dist-lib/lib/office/engine/pptx/shapes.d.ts +52 -0
  63. package/dist-lib/lib/office/engine/pptx/shapes.js +276 -0
  64. package/dist-lib/lib/office/engine/pptx/slides.d.ts +27 -0
  65. package/dist-lib/lib/office/engine/pptx/slides.js +123 -0
  66. package/dist-lib/lib/office/engine/pptx/template.d.ts +20 -0
  67. package/dist-lib/lib/office/engine/pptx/template.js +391 -0
  68. package/dist-lib/lib/office/engine/pptx/types.d.ts +120 -0
  69. package/dist-lib/lib/office/engine/pptx/types.js +1 -0
  70. package/dist-lib/lib/office/engine/units.d.ts +3 -0
  71. package/dist-lib/lib/office/engine/units.js +12 -0
  72. package/dist-lib/lib/office/engine/utf8.d.ts +2 -0
  73. package/dist-lib/lib/office/engine/utf8.js +103 -0
  74. package/dist-lib/lib/office/engine/xlsx/formula.d.ts +49 -0
  75. package/dist-lib/lib/office/engine/xlsx/formula.js +381 -0
  76. package/dist-lib/lib/office/engine/xlsx/index.d.ts +8 -0
  77. package/dist-lib/lib/office/engine/xlsx/index.js +8 -0
  78. package/dist-lib/lib/office/engine/xlsx/refs.d.ts +22 -0
  79. package/dist-lib/lib/office/engine/xlsx/refs.js +82 -0
  80. package/dist-lib/lib/office/engine/xlsx/reshape.d.ts +21 -0
  81. package/dist-lib/lib/office/engine/xlsx/reshape.js +424 -0
  82. package/dist-lib/lib/office/engine/xlsx/sheet.d.ts +108 -0
  83. package/dist-lib/lib/office/engine/xlsx/sheet.js +662 -0
  84. package/dist-lib/lib/office/engine/xlsx/strings.d.ts +15 -0
  85. package/dist-lib/lib/office/engine/xlsx/strings.js +93 -0
  86. package/dist-lib/lib/office/engine/xlsx/styles.d.ts +38 -0
  87. package/dist-lib/lib/office/engine/xlsx/styles.js +369 -0
  88. package/dist-lib/lib/office/engine/xlsx/template.d.ts +7 -0
  89. package/dist-lib/lib/office/engine/xlsx/template.js +54 -0
  90. package/dist-lib/lib/office/engine/xlsx/workbook.d.ts +161 -0
  91. package/dist-lib/lib/office/engine/xlsx/workbook.js +850 -0
  92. package/dist-lib/lib/office/engine/xlsx/write.d.ts +2 -0
  93. package/dist-lib/lib/office/engine/xlsx/write.js +42 -0
  94. package/dist-lib/lib/office/engine/xml.d.ts +45 -0
  95. package/dist-lib/lib/office/engine/xml.js +258 -0
  96. package/dist-lib/lib/office/extract.d.ts +9 -0
  97. package/dist-lib/lib/office/extract.js +19 -0
  98. package/dist-lib/lib/office/index.d.ts +1 -1
  99. package/dist-lib/lib/office/index.js +74 -19
  100. package/dist-lib/lib/tools/exec/adapters/python/module-distributions.js +0 -3
  101. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +7 -50
  102. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +38 -695
  103. package/dist-lib/lib/tools/exec/adapters/python/run-session.js +1 -85
  104. package/dist-lib/lib/tools/exec/scope.d.ts +2 -0
  105. package/dist-lib/lib/tools/exec/scope.js +33 -2
  106. package/dist-lib/lib/tools/exec.js +9 -20
  107. package/dist-lib/lib/tools/office/ops.d.ts +13 -0
  108. package/dist-lib/lib/tools/office/ops.js +100 -0
  109. package/dist-lib/lib/tools/office.d.ts +12 -0
  110. package/dist-lib/lib/tools/office.js +486 -0
  111. package/dist-lib/lib/tools/pdf/build.d.ts +43 -0
  112. package/dist-lib/lib/tools/pdf/build.js +150 -0
  113. package/dist-lib/lib/tools/pdf/images.d.ts +7 -0
  114. package/dist-lib/lib/tools/pdf/images.js +82 -0
  115. package/dist-lib/lib/tools/pdf/request.d.ts +63 -0
  116. package/dist-lib/lib/tools/pdf/request.js +335 -0
  117. package/dist-lib/lib/tools/pdf.d.ts +6 -0
  118. package/dist-lib/lib/tools/pdf.js +302 -0
  119. package/dist-lib/lib/tools/skill.js +14 -0
  120. package/package.json +34 -6
  121. package/wheels/manifest.json +1 -160
  122. package/worker/harness-sidecar.mjs +5 -1
  123. package/dist-lib/lib/office/pptx.d.ts +0 -1
  124. package/dist-lib/lib/office/pptx.js +0 -26
  125. package/dist-lib/lib/office/python.d.ts +0 -8
  126. package/dist-lib/lib/office/python.js +0 -32
  127. package/dist-lib/lib/office/xlsx.d.ts +0 -1
  128. package/dist-lib/lib/office/xlsx.js +0 -26
  129. package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +0 -7
  130. package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +0 -318
  131. package/wheels/cffi-2.0.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl +0 -0
  132. package/wheels/cryptography-47.0.0-cp314-abi3-pyemscripten_2026_0_wasm32.whl +0 -0
  133. package/wheels/defusedxml-0.7.1-py2.py3-none-any.whl +0 -0
  134. package/wheels/et_xmlfile-2.0.0-py3-none-any.whl +0 -0
  135. package/wheels/fonttools-4.62.1-py3-none-any.whl +0 -0
  136. package/wheels/fpdf2-2.8.8-py3-none-any.whl +0 -0
  137. package/wheels/lxml-6.0.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl +0 -0
  138. package/wheels/openpyxl-3.1.5-py2.py3-none-any.whl +0 -0
  139. package/wheels/pillow-12.2.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl +0 -0
  140. package/wheels/pycparser-3.0-py3-none-any.whl +0 -0
  141. package/wheels/pypdf-6.15.0-py3-none-any.whl +0 -0
  142. package/wheels/python_docx-1.2.0-py3-none-any.whl +0 -0
  143. package/wheels/python_pptx-1.0.2-py3-none-any.whl +0 -0
  144. package/wheels/six-1.17.0-py2.py3-none-any.whl +0 -0
  145. package/wheels/typing_extensions-4.15.0-py3-none-any.whl +0 -0
  146. package/wheels/xlsxwriter-3.2.9-py3-none-any.whl +0 -0
@@ -0,0 +1,2 @@
1
+ export type EmbeddedValue = string | number | null | undefined;
2
+ export declare function writeWorkbook(rows: EmbeddedValue[][], sheet?: string): Uint8Array;
@@ -0,0 +1,42 @@
1
+ import { Package } from '../opc/package.js';
2
+ import * as xml from '../xml.js';
3
+ import { cell } from './refs.js';
4
+ const SML = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
5
+ const REL_BASE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
6
+ const TYPES = {
7
+ workbook: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml',
8
+ worksheet: 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml',
9
+ styles: 'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml'
10
+ };
11
+ const STYLES = `<styleSheet xmlns="${SML}"><fonts count="1"><font><sz val="11"/><name val="Calibri"/></font></fonts><fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`;
12
+ function escape(value) {
13
+ return value
14
+ .replace(/&/g, '&amp;')
15
+ .replace(/</g, '&lt;')
16
+ .replace(/>/g, '&gt;')
17
+ .replace(/"/g, '&quot;');
18
+ }
19
+ function cellXml(value, ref) {
20
+ if (value === null || value === undefined || value === '')
21
+ return '';
22
+ if (typeof value === 'number')
23
+ return `<c r="${ref}"><v>${value}</v></c>`;
24
+ return `<c r="${ref}" t="inlineStr"><is><t xml:space="preserve">${escape(value)}</t></is></c>`;
25
+ }
26
+ function sheetXml(rows) {
27
+ const data = rows
28
+ .map((row, r) => `<row r="${r + 1}">${row.map((value, c) => cellXml(value, cell(r, c))).join('')}</row>`)
29
+ .join('');
30
+ return `<worksheet xmlns="${SML}"><sheetData>${data}</sheetData></worksheet>`;
31
+ }
32
+ export function writeWorkbook(rows, sheet = 'Sheet1') {
33
+ const pkg = Package.create();
34
+ const workbook = `<workbook xmlns="${SML}" xmlns:r="${xml.ns.r}"><sheets><sheet name="${escape(sheet)}" sheetId="1" r:id="rId1"/></sheets></workbook>`;
35
+ pkg.add('/xl/workbook.xml', xml.parse(workbook), TYPES.workbook);
36
+ pkg.add('/xl/worksheets/sheet1.xml', xml.parse(sheetXml(rows)), TYPES.worksheet);
37
+ pkg.add('/xl/styles.xml', xml.parse(STYLES), TYPES.styles);
38
+ pkg.rels('/').add(REL_BASE + 'officeDocument', '/xl/workbook.xml');
39
+ pkg.rels('/xl/workbook.xml').add(REL_BASE + 'worksheet', '/xl/worksheets/sheet1.xml');
40
+ pkg.rels('/xl/workbook.xml').add(REL_BASE + 'styles', '/xl/styles.xml');
41
+ return pkg.save();
42
+ }
@@ -0,0 +1,45 @@
1
+ import { Element, type Document, type Node } from '@xmldom/xmldom';
2
+ export type { Document, Element, Node };
3
+ export declare const ns: {
4
+ readonly a: 'http://schemas.openxmlformats.org/drawingml/2006/main';
5
+ readonly p: 'http://schemas.openxmlformats.org/presentationml/2006/main';
6
+ readonly r: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
7
+ readonly w: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
8
+ readonly p14: 'http://schemas.microsoft.com/office/powerpoint/2010/main';
9
+ readonly wp: 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';
10
+ readonly pic: 'http://schemas.openxmlformats.org/drawingml/2006/picture';
11
+ readonly c: 'http://schemas.openxmlformats.org/drawingml/2006/chart';
12
+ readonly xdr: 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing';
13
+ readonly x: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
14
+ readonly rels: 'http://schemas.openxmlformats.org/package/2006/relationships';
15
+ readonly ct: 'http://schemas.openxmlformats.org/package/2006/content-types';
16
+ };
17
+ export type Attributes = Record<string, string | number | undefined | null>;
18
+ export type Build = (local: string, attributes?: Attributes) => Element;
19
+ export declare function decode(bytes: Uint8Array): string;
20
+ export declare function parse(input: Uint8Array | string, name?: string): Document;
21
+ export declare function toString(doc: Document): string;
22
+ export declare function serialize(doc: Document): Uint8Array;
23
+ export declare function root(doc: Document): Element;
24
+ export declare function owner(node: Node): Document;
25
+ export declare function isElement(node: Node | null, namespace?: string, local?: string): node is Element;
26
+ export declare function children(el: Node, namespace?: string, local?: string): Element[];
27
+ export declare function child(el: Node, namespace?: string, local?: string): Element | null;
28
+ export declare function descendants(el: Element | Document, namespace: string, local: string): Element[];
29
+ export declare function text(node: Node | null): string;
30
+ export declare function clean(value: string): string;
31
+ export declare function setText(el: Element, value: string): void;
32
+ export declare function attr(el: Element, name: string): string;
33
+ export declare function setAttributes(el: Element, attributes?: Attributes): Element;
34
+ export declare function named(doc: Document, qualifiedName: string, namespace: string): Element;
35
+ export declare function qualify(doc: Document, namespace: string, local: string): string;
36
+ export declare function builder(doc: Document, namespace: string): Build;
37
+ export interface QualifiedName {
38
+ namespace: string;
39
+ local: string;
40
+ }
41
+ export declare function setNsAttribute(el: Element, name: QualifiedName, value: string): void;
42
+ export declare function insertOrdered(parent: Element, el: Element, order: readonly string[]): Element;
43
+ export declare function remove(node: Node): void;
44
+ export declare function append(parent: Node, node: Element): Element;
45
+ export declare function clone(el: Element): Element;
@@ -0,0 +1,258 @@
1
+ import { DOMParser, XMLSerializer, Element } from '@xmldom/xmldom';
2
+ import { DocsError } from './errors.js';
3
+ import { errorMessage } from '../../guards.js';
4
+ import * as utf8 from './utf8.js';
5
+ export const ns = {
6
+ a: 'http://schemas.openxmlformats.org/drawingml/2006/main',
7
+ p: 'http://schemas.openxmlformats.org/presentationml/2006/main',
8
+ r: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
9
+ w: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
10
+ p14: 'http://schemas.microsoft.com/office/powerpoint/2010/main',
11
+ wp: 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
12
+ pic: 'http://schemas.openxmlformats.org/drawingml/2006/picture',
13
+ c: 'http://schemas.openxmlformats.org/drawingml/2006/chart',
14
+ xdr: 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing',
15
+ x: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
16
+ rels: 'http://schemas.openxmlformats.org/package/2006/relationships',
17
+ ct: 'http://schemas.openxmlformats.org/package/2006/content-types'
18
+ };
19
+ const MAX_DEPTH = 256;
20
+ const NOT_XML = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
21
+ const DECLARATION = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
22
+ const UNPREFIXED = [ns.rels, ns.ct, ns.x];
23
+ const PREFIXES = new Map(Object.entries(ns)
24
+ .filter(([, uri]) => !UNPREFIXED.includes(uri))
25
+ .map(([prefix, uri]) => [uri, prefix]));
26
+ const SKIPPED = [
27
+ ['<!--', '-->'],
28
+ ['<![CDATA[', ']]>'],
29
+ ['<?', '?>'],
30
+ ['<!', '>']
31
+ ];
32
+ function skipped(text, at) {
33
+ for (const [open, close] of SKIPPED) {
34
+ if (text.startsWith(open, at)) {
35
+ const end = text.indexOf(close, at + open.length);
36
+ return end === -1 ? -1 : end + close.length;
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ function tagEnd(text, at) {
42
+ let quote = '';
43
+ for (let i = at; i < text.length; i++) {
44
+ const c = text[i];
45
+ if (quote) {
46
+ quote = c === quote ? '' : quote;
47
+ }
48
+ else if (c === '"' || c === "'") {
49
+ quote = c;
50
+ }
51
+ else if (c === '>') {
52
+ return i;
53
+ }
54
+ }
55
+ return -1;
56
+ }
57
+ function checkDepth(text, name) {
58
+ let depth = 0;
59
+ for (let i = text.indexOf('<'); i !== -1; i = text.indexOf('<', i)) {
60
+ const after = skipped(text, i);
61
+ if (after === -1) {
62
+ return;
63
+ }
64
+ if (after !== null) {
65
+ i = after;
66
+ continue;
67
+ }
68
+ const end = tagEnd(text, i + 1);
69
+ if (end === -1) {
70
+ return;
71
+ }
72
+ if (text[i + 1] === '/') {
73
+ depth--;
74
+ }
75
+ else if (text[end - 1] !== '/') {
76
+ depth++;
77
+ }
78
+ if (depth > MAX_DEPTH) {
79
+ throw new DocsError('UNSAFE_XML', `${name} nests elements more than ${MAX_DEPTH} levels deep`);
80
+ }
81
+ i = end + 1;
82
+ }
83
+ }
84
+ function decodeUtf16(bytes, endian) {
85
+ const littleEndian = endian === 'le';
86
+ let out = '';
87
+ for (let i = 2; i + 1 < bytes.length; i += 2) {
88
+ const code = littleEndian ? bytes[i] | (bytes[i + 1] << 8) : (bytes[i] << 8) | bytes[i + 1];
89
+ out += String.fromCharCode(code);
90
+ }
91
+ return out;
92
+ }
93
+ export function decode(bytes) {
94
+ if (bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
95
+ return utf8.decode(bytes.subarray(3));
96
+ }
97
+ if (bytes[0] === 0xff && bytes[1] === 0xfe) {
98
+ return decodeUtf16(bytes, 'le');
99
+ }
100
+ if (bytes[0] === 0xfe && bytes[1] === 0xff) {
101
+ return decodeUtf16(bytes, 'be');
102
+ }
103
+ return utf8.decode(bytes);
104
+ }
105
+ function causeOf(err) {
106
+ return err instanceof Error ? err.cause : undefined;
107
+ }
108
+ export function parse(input, name = 'part') {
109
+ const text = (typeof input === 'string' ? input : decode(input)).replace(/^/, '');
110
+ if (/<!DOCTYPE/i.test(text)) {
111
+ throw new DocsError('UNSAFE_XML', `${name} declares a DOCTYPE, which Office files never do`);
112
+ }
113
+ checkDepth(text, name);
114
+ const invalid = (message) => new DocsError('INVALID_XML', `${name} is not well-formed XML: ${message}`);
115
+ const parser = new DOMParser({
116
+ onError(level, message) {
117
+ if (level !== 'warning') {
118
+ throw invalid(message);
119
+ }
120
+ }
121
+ });
122
+ let doc;
123
+ try {
124
+ doc = parser.parseFromString(text, 'application/xml');
125
+ }
126
+ catch (err) {
127
+ if (err instanceof DocsError) {
128
+ throw err;
129
+ }
130
+ const cause = causeOf(err);
131
+ if (cause instanceof DocsError) {
132
+ throw cause;
133
+ }
134
+ throw invalid(errorMessage(err));
135
+ }
136
+ if (!doc.documentElement) {
137
+ throw new DocsError('INVALID_XML', `${name} has no root element`);
138
+ }
139
+ return doc;
140
+ }
141
+ export function toString(doc) {
142
+ return new XMLSerializer().serializeToString(doc);
143
+ }
144
+ export function serialize(doc) {
145
+ const text = toString(doc);
146
+ if (!text.startsWith('<?xml')) {
147
+ return utf8.encode(DECLARATION + text);
148
+ }
149
+ return utf8.encode(text.replace(/^(<\?xml[^?]*?encoding=)(["'])[^"']*\2/i, '$1$2UTF-8$2'));
150
+ }
151
+ export function root(doc) {
152
+ const el = doc.documentElement;
153
+ if (!el) {
154
+ throw new DocsError('INVALID_XML', 'the part has no root element');
155
+ }
156
+ return el;
157
+ }
158
+ export function owner(node) {
159
+ const doc = node.ownerDocument;
160
+ if (!doc) {
161
+ throw new DocsError('INVALID_XML', 'the element belongs to no document');
162
+ }
163
+ return doc;
164
+ }
165
+ export function isElement(node, namespace, local) {
166
+ return (node instanceof Element &&
167
+ (namespace === undefined || node.namespaceURI === namespace) &&
168
+ (local === undefined || node.localName === local));
169
+ }
170
+ export function children(el, namespace, local) {
171
+ const out = [];
172
+ for (let n = el.firstChild; n; n = n.nextSibling) {
173
+ if (isElement(n, namespace, local)) {
174
+ out.push(n);
175
+ }
176
+ }
177
+ return out;
178
+ }
179
+ export function child(el, namespace, local) {
180
+ for (let n = el.firstChild; n; n = n.nextSibling) {
181
+ if (isElement(n, namespace, local))
182
+ return n;
183
+ }
184
+ return null;
185
+ }
186
+ export function descendants(el, namespace, local) {
187
+ return Array.from(el.getElementsByTagNameNS(namespace, local));
188
+ }
189
+ export function text(node) {
190
+ return node?.textContent ?? '';
191
+ }
192
+ export function clean(value) {
193
+ return value.replace(NOT_XML, '');
194
+ }
195
+ export function setText(el, value) {
196
+ while (el.firstChild) {
197
+ el.removeChild(el.firstChild);
198
+ }
199
+ el.appendChild(owner(el).createTextNode(clean(value)));
200
+ }
201
+ export function attr(el, name) {
202
+ return el.getAttribute(name) ?? '';
203
+ }
204
+ export function setAttributes(el, attributes = {}) {
205
+ for (const [key, value] of Object.entries(attributes)) {
206
+ if (value !== undefined && value !== null) {
207
+ el.setAttribute(key, String(value));
208
+ }
209
+ }
210
+ return el;
211
+ }
212
+ export function named(doc, qualifiedName, namespace) {
213
+ return doc.createElementNS(namespace, qualifiedName);
214
+ }
215
+ export function qualify(doc, namespace, local) {
216
+ const top = root(doc);
217
+ if (top.namespaceURI === namespace && !top.prefix) {
218
+ return local;
219
+ }
220
+ const prefix = top.lookupPrefix(namespace) ?? PREFIXES.get(namespace);
221
+ return prefix ? `${prefix}:${local}` : local;
222
+ }
223
+ export function builder(doc, namespace) {
224
+ return (local, attributes) => setAttributes(named(doc, qualify(doc, namespace, local), namespace), attributes);
225
+ }
226
+ export function setNsAttribute(el, name, value) {
227
+ const doc = owner(el);
228
+ const prefix = root(doc).lookupPrefix(name.namespace) ?? PREFIXES.get(name.namespace) ?? name.local;
229
+ el.setAttributeNS(name.namespace, `${prefix}:${name.local}`, value);
230
+ }
231
+ export function insertOrdered(parent, el, order) {
232
+ const rank = order.indexOf(el.localName ?? '');
233
+ for (let n = parent.firstChild; n; n = n.nextSibling) {
234
+ if (!(n instanceof Element))
235
+ continue;
236
+ const other = order.indexOf(n.localName ?? '');
237
+ if (other > rank || other === -1) {
238
+ parent.insertBefore(el, n);
239
+ return el;
240
+ }
241
+ }
242
+ parent.appendChild(el);
243
+ return el;
244
+ }
245
+ export function remove(node) {
246
+ node.parentNode?.removeChild(node);
247
+ }
248
+ export function append(parent, node) {
249
+ parent.appendChild(node);
250
+ return node;
251
+ }
252
+ export function clone(el) {
253
+ const copy = el.cloneNode(true);
254
+ if (!(copy instanceof Element)) {
255
+ throw new DocsError('INVALID_XML', 'cloning an element produced no element');
256
+ }
257
+ return copy;
258
+ }
@@ -0,0 +1,9 @@
1
+ import type { AbortSignal } from 'bare-abort-controller';
2
+ export type Extract = (bytes: Uint8Array) => string;
3
+ export interface ExtractJob {
4
+ readonly fileName: string;
5
+ readonly signal: AbortSignal | undefined;
6
+ readonly extract: Extract;
7
+ }
8
+ export declare function extractWith(bytes: Uint8Array, { fileName, signal, extract }: ExtractJob): string;
9
+ export declare function cellText(value: unknown): string;
@@ -0,0 +1,19 @@
1
+ import { errorMessage } from '../guards.js';
2
+ const MAX_OFFICE_BYTES = 20 * 1024 * 1024;
3
+ export function extractWith(bytes, { fileName, signal, extract }) {
4
+ if (bytes.byteLength > MAX_OFFICE_BYTES) {
5
+ throw new Error(`document is too large to extract: ${bytes.byteLength} bytes, limit ${MAX_OFFICE_BYTES}`);
6
+ }
7
+ if (signal?.aborted) {
8
+ throw new Error(`${fileName}: extraction aborted`);
9
+ }
10
+ try {
11
+ return extract(bytes);
12
+ }
13
+ catch (err) {
14
+ throw new Error(`${fileName}: ${errorMessage(err)}`);
15
+ }
16
+ }
17
+ export function cellText(value) {
18
+ return value === null || value === undefined ? '' : String(value).replaceAll('\n', ' ');
19
+ }
@@ -1,5 +1,5 @@
1
1
  import type { AbortSignal } from 'bare-abort-controller';
2
- export { closePythonWorker as closeOfficeWorker } from '../tools/exec/adapters/python/worker/active.ts';
2
+ export { closeDocxWorker as closeOfficeWorker } from '../docx/index.ts';
3
3
  export interface OfficeExtractOptions {
4
4
  readonly signal?: AbortSignal | undefined;
5
5
  readonly mimeType?: string | undefined;
@@ -1,14 +1,81 @@
1
1
  import path from 'path';
2
2
  import { extractDocxText } from '../docx/index.js';
3
- import { extractWithPython } from './python.js';
4
- import { XLSX_EXTRACT } from './xlsx.js';
5
- import { PPTX_EXTRACT } from './pptx.js';
6
- export { closePythonWorker as closeOfficeWorker } from '../tools/exec/adapters/python/worker/active.js';
3
+ import { pptx, xlsx } from './engine/index.js';
4
+ import { cellText, extractWith } from './extract.js';
5
+ export { closeDocxWorker as closeOfficeWorker } from '../docx/index.js';
7
6
  const OFFICE_MIME_EXTENSIONS = {
8
7
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx',
9
8
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx',
10
9
  'application/vnd.openxmlformats-officedocument.presentationml.presentation': '.pptx'
11
10
  };
11
+ const EXTRACT_CELL_LIMIT = 1_000_000;
12
+ function columnIndex(letters) {
13
+ let index = 0;
14
+ for (const char of letters) {
15
+ index = index * 26 + char.charCodeAt(0) - 64;
16
+ }
17
+ return index;
18
+ }
19
+ function columnName(index) {
20
+ let name = '';
21
+ for (let n = index; n > 0; n = Math.floor((n - 1) / 26)) {
22
+ name = String.fromCharCode(65 + ((n - 1) % 26)) + name;
23
+ }
24
+ return name;
25
+ }
26
+ function trimmedRow(values) {
27
+ const row = [...values];
28
+ while (row.length && !cellText(row.at(-1)).trim()) {
29
+ row.pop();
30
+ }
31
+ return row;
32
+ }
33
+ function workbookText(bytes) {
34
+ const book = xlsx.open(bytes);
35
+ let output = '';
36
+ let budget = EXTRACT_CELL_LIMIT;
37
+ for (const sheet of book.sheets()) {
38
+ if (sheet.kind !== 'worksheet' || budget <= 0)
39
+ continue;
40
+ const { range, rows, formulas } = book.read(sheet.index, { limit: budget });
41
+ budget -= rows.length * (rows[0]?.length ?? 0);
42
+ const [, letters = 'A', digits = '1'] = /^([A-Z]+)(\d+)/.exec(range ?? 'A1') ?? [];
43
+ const firstColumn = columnIndex(letters);
44
+ const firstRow = Number(digits);
45
+ const lines = rows
46
+ .map((row, r) => trimmedRow(row.map((value, c) => value ?? formulas[`${columnName(firstColumn + c)}${firstRow + r}`] ?? null)))
47
+ .filter((row) => row.length)
48
+ .map((row) => row.map(cellText).join(' | '));
49
+ if (lines.length) {
50
+ output += `Sheet: ${sheet.name}\n${lines.join('\n')}\n`;
51
+ }
52
+ }
53
+ return output;
54
+ }
55
+ function shapeBlocks(shape) {
56
+ if (shape.paragraphs) {
57
+ const text = shape.paragraphs.map((paragraph) => paragraph.text).join('\n');
58
+ return text.trim() ? [text] : [];
59
+ }
60
+ return (shape.rows ?? [])
61
+ .map((row) => row.map(cellText))
62
+ .filter((cells) => cells.some((cell) => cell.trim()))
63
+ .map((cells) => cells.join(' | '));
64
+ }
65
+ function deckText(bytes) {
66
+ let output = '';
67
+ for (const slide of pptx.open(bytes).read()) {
68
+ const blocks = slide.shapes.flatMap(shapeBlocks);
69
+ if (blocks.length) {
70
+ output += `Slide ${slide.index + 1}\n${blocks.join('\n')}\n`;
71
+ }
72
+ }
73
+ return output;
74
+ }
75
+ const EXTRACTORS = new Map([
76
+ ['.xlsx', workbookText],
77
+ ['.pptx', deckText]
78
+ ]);
12
79
  export async function extractOfficeText(bytes, fileName, options = {}) {
13
80
  const mimeType = options.mimeType?.split(';')[0]?.trim().toLowerCase();
14
81
  const suffix = path.extname(fileName).toLowerCase();
@@ -18,21 +85,9 @@ export async function extractOfficeText(bytes, fileName, options = {}) {
18
85
  if (extension === '.docx') {
19
86
  return extractDocxText(bytes, fileName, options);
20
87
  }
21
- if (extension === '.xlsx') {
22
- return extractWithPython(bytes, fileName, {
23
- format: 'XLSX',
24
- packages: ['openpyxl==3.1.5'],
25
- source: XLSX_EXTRACT,
26
- signal: options.signal
27
- });
28
- }
29
- if (extension === '.pptx') {
30
- return extractWithPython(bytes, fileName, {
31
- format: 'PPTX',
32
- packages: ['python-pptx==1.0.2'],
33
- source: PPTX_EXTRACT,
34
- signal: options.signal
35
- });
88
+ const extract = EXTRACTORS.get(extension ?? '');
89
+ if (extract) {
90
+ return extractWith(bytes, { fileName, signal: options.signal, extract });
36
91
  }
37
92
  throw new Error(`Unsupported Office document: ${fileName}`);
38
93
  }
@@ -20,12 +20,10 @@ export const MODULE_DISTRIBUTIONS = {
20
20
  cvxpy: 'cvxpy-base',
21
21
  dateutil: 'python-dateutil',
22
22
  dns: 'dnspython',
23
- docx: 'python-docx',
24
23
  erfa: 'pyerfa',
25
24
  fitz: 'PyMuPDF',
26
25
  flint: 'python-flint',
27
26
  flirt: 'python-flirt',
28
- fpdf: 'fpdf2',
29
27
  google: 'protobuf',
30
28
  gridfs: 'pymongo',
31
29
  isympy: 'sympy',
@@ -33,7 +31,6 @@ export const MODULE_DISTRIBUTIONS = {
33
31
  mpl_toolkits: 'matplotlib',
34
32
  mypyc: 'mypy',
35
33
  nacl: 'pynacl',
36
- pptx: 'python-pptx',
37
34
  pygame: 'pygame-ce',
38
35
  pylab: 'matplotlib',
39
36
  pysat: 'python-sat',
@@ -1,8 +1,7 @@
1
- import type { ExecAttachment } from '../../runner.ts';
2
1
  import type { ExecutionAdapter } from '../adapter.ts';
3
2
  import { type ExecInput } from './attachments.ts';
4
3
  import { type ExecError } from './output-policy.ts';
5
- import { type LoadPyodideFn, type PythonRunResult } from './pyodide.ts';
4
+ import { type LoadPyodideFn } from './pyodide.ts';
6
5
  export declare function isPythonLanguage(language: unknown): boolean;
7
6
  export declare function runsThroughPyodide(language: unknown, disablePyodide: boolean): boolean;
8
7
  export declare function unwrapPythonSource(command: string): string | null;
@@ -20,70 +19,28 @@ export interface PipFromSourceHintOptions {
20
19
  export declare function pipFromSourceHint(stderr: string, source: string, { packages, sandbox }?: PipFromSourceHintOptions): string | null;
21
20
  export declare function stringLiteralProgramHint(source: string): string | null;
22
21
  export declare function checkCollapsedCompound(source: string): string | null;
23
- export declare function mangledPptxApiHint(source: string): string | null;
24
- export declare function wrongRgbColorHint(source: string): string | null;
25
- export declare function fpdfSizeKeywordHint(source: string): string | null;
26
- export declare function fpdfKeywordErrorHint(stderr: string): string | null;
27
- export declare function normalizeFpdfSource(source: string): string;
28
- export declare function fpdfTextCallHint(source: string): string | null;
29
- export declare function fpdfTextErrorHint(stderr: string): string | null;
30
- export declare function fpdfNonLatin1Hint(source: string): string | null;
31
- export declare function fpdfUnicodeErrorHint(stderr: string): string | null;
32
- export declare function fpdfHorizontalSpaceHint(stderr: string): string | null;
33
- export declare function rgbColorImportHint(stderr: string): string | null;
34
22
  export declare function checkPythonSource(command: string): string | null;
35
23
  export declare function syntaxErrorHint(stderr: string, source: string): string | null;
36
- export declare function checkPptxBuildSource(source: string, outputs: readonly string[] | undefined, packages?: readonly string[] | undefined): string | null;
37
- export declare function tripleQuoteAt(source: string, index: number): string | null;
38
- export declare function isEscaped(source: string, index: number): boolean;
39
- export declare function checkBareLengthArgs(source: string, packages?: readonly string[] | undefined): string | null;
40
- export declare function checkPdfBuildSource(source: string, outputs: readonly string[] | undefined, packages?: readonly string[] | undefined): string | null;
41
- export declare function stripCommentsAndDocstrings(source: string): string;
42
- export declare const PDF_READ: RegExp;
43
- export declare const OFFICE_READ: RegExp;
44
- export declare function checkUnstagedRead(source: string, inputs: readonly Pick<ExecInput, 'path'>[] | undefined): string | null;
45
24
  export declare function missingFileHint(stderr: string): string | null;
46
25
  export declare function parsePackages(value: unknown): string[] | ExecError | undefined;
47
26
  export declare function parseInputs(value: unknown): ExecInput[] | ExecError | undefined;
48
27
  export declare function parseOutputs(value: unknown): string[] | ExecError | undefined;
49
28
  export declare function parseWorkdir(value: unknown): string | ExecError | undefined;
29
+ export interface OfficeImportContext {
30
+ readonly packages: readonly string[] | undefined;
31
+ readonly toolNames: readonly string[] | undefined;
32
+ }
33
+ export declare function officeModuleHint(stderr: string, toolNames: readonly string[] | undefined): string | null;
34
+ export declare function officeImportError(source: string, { packages, toolNames }: OfficeImportContext): string | null;
50
35
  export interface MissingModuleHintOptions {
51
36
  readonly packages?: readonly string[] | undefined;
52
37
  readonly sandbox?: boolean;
53
38
  readonly network?: boolean;
54
39
  }
55
40
  export declare function missingModuleHint(stderr: string, { packages, sandbox, network }?: MissingModuleHintOptions): string | null;
56
- export declare function nonePlaceholderHint(stderr: string): string | null;
57
- export declare function slideShapesHint(stderr: string): string | null;
58
- export declare function shapeFontHint(stderr: string): string | null;
59
- export declare function shapesBackgroundHint(stderr: string): string | null;
60
- export declare function paragraphFillHint(stderr: string): string | null;
61
- export declare function readOnlyPropertyHint(stderr: string): string | null;
62
- export declare function paragraphIndexHint(stderr: string, outputs: readonly string[]): string | null;
63
41
  export declare function shellNameHint(stderr: string): string | null;
64
42
  export declare function noProcessHint(stderr: string, sandbox?: boolean): string | null;
65
43
  export declare function noNetworkHint(stderr: string, tools?: readonly string[], network?: boolean): string | null;
66
44
  export declare function nativeWheelHint(stderr: string): string | null;
67
45
  export declare function packageFetchFailedHint(stderr: string): string | null;
68
- export declare const IMAGE_INPUT: RegExp;
69
- export declare function pptxHasEmbeddedMedia(bytes: Uint8Array): boolean;
70
- export declare function softFailedDeckHint(stdout: string, exitCode: number, source: string): string | null;
71
- export interface DeckImagesOptions {
72
- readonly inputs: readonly {
73
- path: string;
74
- }[] | undefined;
75
- readonly outputs: readonly string[] | undefined;
76
- readonly source: string;
77
- }
78
- export declare function stagedImagesMissingFromDeck(result: Pick<PythonRunResult, 'exitCode' | 'files'>, { inputs, outputs, source }: DeckImagesOptions): string | null;
79
- export declare function checkStagedImagesUsed(source: string, inputs: readonly Pick<ExecInput, 'path'>[] | undefined, outputs: readonly string[] | undefined): string | null;
80
- export interface TurnImagesStagedOptions {
81
- readonly inputs: readonly ExecInput[] | undefined;
82
- readonly outputs: readonly string[] | undefined;
83
- readonly turnImages: readonly {
84
- path: string;
85
- }[] | undefined;
86
- }
87
- export declare function checkTurnImagesStaged(source: string, { inputs, outputs, turnImages }: TurnImagesStagedOptions): string | null;
88
- export declare function deckDeliveredStop(attachments: readonly Pick<ExecAttachment, 'fileName'>[] | undefined, exitCode: number, source?: string): string | null;
89
46
  export declare function createPythonAdapter(disabled: boolean, loadPyodide?: LoadPyodideFn, network?: boolean): ExecutionAdapter;