@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.
- package/CHANGELOG.md +87 -1
- package/NOTICE.md +16 -0
- package/dist-lib/lib/capabilities/completion.d.ts +1 -0
- package/dist-lib/lib/capabilities/completion.js +28 -8
- package/dist-lib/lib/capabilities/tool-turns.d.ts +3 -0
- package/dist-lib/lib/capabilities/tool-turns.js +7 -0
- package/dist-lib/lib/context-window.js +2 -2
- package/dist-lib/lib/docx/index.d.ts +1 -1
- package/dist-lib/lib/docx/index.js +16 -24
- package/dist-lib/lib/helpers/run-outcome.d.ts +4 -1
- package/dist-lib/lib/helpers/run-outcome.js +14 -8
- package/dist-lib/lib/helpers/tool-call-markup.js +4 -4
- package/dist-lib/lib/hooks/built-in/arg-repair.js +7 -0
- package/dist-lib/lib/office/engine/codes.d.ts +62 -0
- package/dist-lib/lib/office/engine/codes.js +61 -0
- package/dist-lib/lib/office/engine/docx/document.d.ts +216 -0
- package/dist-lib/lib/office/engine/docx/document.js +1152 -0
- package/dist-lib/lib/office/engine/docx/index.d.ts +7 -0
- package/dist-lib/lib/office/engine/docx/index.js +8 -0
- package/dist-lib/lib/office/engine/docx/styles.d.ts +31 -0
- package/dist-lib/lib/office/engine/docx/styles.js +173 -0
- package/dist-lib/lib/office/engine/docx/template.d.ts +18 -0
- package/dist-lib/lib/office/engine/docx/template.js +133 -0
- package/dist-lib/lib/office/engine/docx/text.d.ts +55 -0
- package/dist-lib/lib/office/engine/docx/text.js +538 -0
- package/dist-lib/lib/office/engine/drawingml/chart.d.ts +63 -0
- package/dist-lib/lib/office/engine/drawingml/chart.js +539 -0
- package/dist-lib/lib/office/engine/drawingml/text.d.ts +35 -0
- package/dist-lib/lib/office/engine/drawingml/text.js +352 -0
- package/dist-lib/lib/office/engine/errors.d.ts +6 -0
- package/dist-lib/lib/office/engine/errors.js +12 -0
- package/dist-lib/lib/office/engine/image.d.ts +8 -0
- package/dist-lib/lib/office/engine/image.js +48 -0
- package/dist-lib/lib/office/engine/index.d.ts +12 -0
- package/dist-lib/lib/office/engine/index.js +7 -0
- package/dist-lib/lib/office/engine/opc/content-types.d.ts +17 -0
- package/dist-lib/lib/office/engine/opc/content-types.js +74 -0
- package/dist-lib/lib/office/engine/opc/media.d.ts +13 -0
- package/dist-lib/lib/office/engine/opc/media.js +11 -0
- package/dist-lib/lib/office/engine/opc/package.d.ts +51 -0
- package/dist-lib/lib/office/engine/opc/package.js +324 -0
- package/dist-lib/lib/office/engine/opc/paths.d.ts +7 -0
- package/dist-lib/lib/office/engine/opc/paths.js +46 -0
- package/dist-lib/lib/office/engine/opc/properties.d.ts +7 -0
- package/dist-lib/lib/office/engine/opc/properties.js +75 -0
- package/dist-lib/lib/office/engine/opc/relationships.d.ts +23 -0
- package/dist-lib/lib/office/engine/opc/relationships.js +65 -0
- package/dist-lib/lib/office/engine/opc/zip.d.ts +15 -0
- package/dist-lib/lib/office/engine/opc/zip.js +264 -0
- package/dist-lib/lib/office/engine/pptx/fit.d.ts +12 -0
- package/dist-lib/lib/office/engine/pptx/fit.js +37 -0
- package/dist-lib/lib/office/engine/pptx/index.d.ts +8 -0
- package/dist-lib/lib/office/engine/pptx/index.js +8 -0
- package/dist-lib/lib/office/engine/pptx/inherit.d.ts +29 -0
- package/dist-lib/lib/office/engine/pptx/inherit.js +155 -0
- package/dist-lib/lib/office/engine/pptx/notes.d.ts +5 -0
- package/dist-lib/lib/office/engine/pptx/notes.js +85 -0
- package/dist-lib/lib/office/engine/pptx/presentation.d.ts +54 -0
- package/dist-lib/lib/office/engine/pptx/presentation.js +749 -0
- package/dist-lib/lib/office/engine/pptx/read.d.ts +9 -0
- package/dist-lib/lib/office/engine/pptx/read.js +66 -0
- package/dist-lib/lib/office/engine/pptx/shapes.d.ts +52 -0
- package/dist-lib/lib/office/engine/pptx/shapes.js +276 -0
- package/dist-lib/lib/office/engine/pptx/slides.d.ts +27 -0
- package/dist-lib/lib/office/engine/pptx/slides.js +123 -0
- package/dist-lib/lib/office/engine/pptx/template.d.ts +20 -0
- package/dist-lib/lib/office/engine/pptx/template.js +391 -0
- package/dist-lib/lib/office/engine/pptx/types.d.ts +120 -0
- package/dist-lib/lib/office/engine/pptx/types.js +1 -0
- package/dist-lib/lib/office/engine/units.d.ts +3 -0
- package/dist-lib/lib/office/engine/units.js +12 -0
- package/dist-lib/lib/office/engine/utf8.d.ts +2 -0
- package/dist-lib/lib/office/engine/utf8.js +103 -0
- package/dist-lib/lib/office/engine/xlsx/formula.d.ts +49 -0
- package/dist-lib/lib/office/engine/xlsx/formula.js +381 -0
- package/dist-lib/lib/office/engine/xlsx/index.d.ts +8 -0
- package/dist-lib/lib/office/engine/xlsx/index.js +8 -0
- package/dist-lib/lib/office/engine/xlsx/refs.d.ts +22 -0
- package/dist-lib/lib/office/engine/xlsx/refs.js +82 -0
- package/dist-lib/lib/office/engine/xlsx/reshape.d.ts +21 -0
- package/dist-lib/lib/office/engine/xlsx/reshape.js +424 -0
- package/dist-lib/lib/office/engine/xlsx/sheet.d.ts +108 -0
- package/dist-lib/lib/office/engine/xlsx/sheet.js +662 -0
- package/dist-lib/lib/office/engine/xlsx/strings.d.ts +15 -0
- package/dist-lib/lib/office/engine/xlsx/strings.js +93 -0
- package/dist-lib/lib/office/engine/xlsx/styles.d.ts +38 -0
- package/dist-lib/lib/office/engine/xlsx/styles.js +369 -0
- package/dist-lib/lib/office/engine/xlsx/template.d.ts +7 -0
- package/dist-lib/lib/office/engine/xlsx/template.js +54 -0
- package/dist-lib/lib/office/engine/xlsx/workbook.d.ts +161 -0
- package/dist-lib/lib/office/engine/xlsx/workbook.js +850 -0
- package/dist-lib/lib/office/engine/xlsx/write.d.ts +2 -0
- package/dist-lib/lib/office/engine/xlsx/write.js +42 -0
- package/dist-lib/lib/office/engine/xml.d.ts +45 -0
- package/dist-lib/lib/office/engine/xml.js +258 -0
- package/dist-lib/lib/office/extract.d.ts +9 -0
- package/dist-lib/lib/office/extract.js +19 -0
- package/dist-lib/lib/office/index.d.ts +1 -1
- package/dist-lib/lib/office/index.js +74 -19
- package/dist-lib/lib/tools/exec/adapters/python/module-distributions.js +0 -3
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +7 -50
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +38 -695
- package/dist-lib/lib/tools/exec/adapters/python/run-session.js +1 -85
- package/dist-lib/lib/tools/exec/scope.d.ts +2 -0
- package/dist-lib/lib/tools/exec/scope.js +33 -2
- package/dist-lib/lib/tools/exec.js +9 -20
- package/dist-lib/lib/tools/office/ops.d.ts +13 -0
- package/dist-lib/lib/tools/office/ops.js +100 -0
- package/dist-lib/lib/tools/office.d.ts +12 -0
- package/dist-lib/lib/tools/office.js +486 -0
- package/dist-lib/lib/tools/pdf/build.d.ts +43 -0
- package/dist-lib/lib/tools/pdf/build.js +150 -0
- package/dist-lib/lib/tools/pdf/images.d.ts +7 -0
- package/dist-lib/lib/tools/pdf/images.js +82 -0
- package/dist-lib/lib/tools/pdf/request.d.ts +63 -0
- package/dist-lib/lib/tools/pdf/request.js +335 -0
- package/dist-lib/lib/tools/pdf.d.ts +6 -0
- package/dist-lib/lib/tools/pdf.js +302 -0
- package/dist-lib/lib/tools/skill.js +14 -0
- package/package.json +34 -6
- package/wheels/manifest.json +1 -160
- package/worker/harness-sidecar.mjs +5 -1
- package/dist-lib/lib/office/pptx.d.ts +0 -1
- package/dist-lib/lib/office/pptx.js +0 -26
- package/dist-lib/lib/office/python.d.ts +0 -8
- package/dist-lib/lib/office/python.js +0 -32
- package/dist-lib/lib/office/xlsx.d.ts +0 -1
- package/dist-lib/lib/office/xlsx.js +0 -26
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +0 -7
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +0 -318
- package/wheels/cffi-2.0.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl +0 -0
- package/wheels/cryptography-47.0.0-cp314-abi3-pyemscripten_2026_0_wasm32.whl +0 -0
- package/wheels/defusedxml-0.7.1-py2.py3-none-any.whl +0 -0
- package/wheels/et_xmlfile-2.0.0-py3-none-any.whl +0 -0
- package/wheels/fonttools-4.62.1-py3-none-any.whl +0 -0
- package/wheels/fpdf2-2.8.8-py3-none-any.whl +0 -0
- package/wheels/lxml-6.0.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl +0 -0
- package/wheels/openpyxl-3.1.5-py2.py3-none-any.whl +0 -0
- package/wheels/pillow-12.2.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl +0 -0
- package/wheels/pycparser-3.0-py3-none-any.whl +0 -0
- package/wheels/pypdf-6.15.0-py3-none-any.whl +0 -0
- package/wheels/python_docx-1.2.0-py3-none-any.whl +0 -0
- package/wheels/python_pptx-1.0.2-py3-none-any.whl +0 -0
- package/wheels/six-1.17.0-py2.py3-none-any.whl +0 -0
- package/wheels/typing_extensions-4.15.0-py3-none-any.whl +0 -0
- package/wheels/xlsxwriter-3.2.9-py3-none-any.whl +0 -0
|
@@ -105,72 +105,6 @@ async function runOnce(py, code, opts) {
|
|
|
105
105
|
}
|
|
106
106
|
return retry;
|
|
107
107
|
}
|
|
108
|
-
const FIT_DECKS = `
|
|
109
|
-
def _qvac_fit_decks(names):
|
|
110
|
-
try:
|
|
111
|
-
from pptx import Presentation
|
|
112
|
-
from pptx.oxml.ns import qn
|
|
113
|
-
except Exception:
|
|
114
|
-
return
|
|
115
|
-
for name in names:
|
|
116
|
-
if not name.lower().endswith('.pptx'):
|
|
117
|
-
continue
|
|
118
|
-
try:
|
|
119
|
-
prs = Presentation(name)
|
|
120
|
-
except Exception:
|
|
121
|
-
continue
|
|
122
|
-
slide_height = prs.slide_height
|
|
123
|
-
changed = False
|
|
124
|
-
for slide in prs.slides:
|
|
125
|
-
for shape in slide.shapes:
|
|
126
|
-
if not shape.has_text_frame:
|
|
127
|
-
continue
|
|
128
|
-
tf = shape.text_frame
|
|
129
|
-
text = tf.text or ''
|
|
130
|
-
if not text.strip():
|
|
131
|
-
continue
|
|
132
|
-
tf.word_wrap = True
|
|
133
|
-
# Estimated wrapped lines against the box: a character at N pt is
|
|
134
|
-
# about 0.5 N wide and a line about 1.2 N tall. Rough on purpose —
|
|
135
|
-
# it only has to pick a scale, and the renderer does the real layout.
|
|
136
|
-
width_pt = (shape.width or 0) / 12700.0
|
|
137
|
-
height_pt = (shape.height or slide_height) / 12700.0
|
|
138
|
-
lines = 0
|
|
139
|
-
tallest = 0.0
|
|
140
|
-
for p in tf.paragraphs:
|
|
141
|
-
# An unsized paragraph inherits from the layout, and the bundled
|
|
142
|
-
# template's body is 28pt — assuming something smaller here is
|
|
143
|
-
# what let a seven-bullet slide measure as fitting.
|
|
144
|
-
size = p.font.size.pt if p.font.size is not None else 28.0
|
|
145
|
-
tallest = max(tallest, size)
|
|
146
|
-
per_line = max(1.0, width_pt / (size * 0.5))
|
|
147
|
-
lines += max(1, int(len(p.text or '') / per_line) + 1)
|
|
148
|
-
needed = lines * max(tallest, 12.0) * 1.2
|
|
149
|
-
scale = 1.0 if needed <= height_pt or height_pt <= 0 else height_pt / needed
|
|
150
|
-
# 55% is the floor: below that the deck is unreadable from a room and
|
|
151
|
-
# the honest answer is fewer bullets, not smaller type.
|
|
152
|
-
scale = max(0.55, min(1.0, scale))
|
|
153
|
-
bodyPr = tf._txBody.bodyPr
|
|
154
|
-
for tag in ('a:normAutofit', 'a:spAutoFit', 'a:noAutofit'):
|
|
155
|
-
found = bodyPr.find(qn(tag))
|
|
156
|
-
if found is not None:
|
|
157
|
-
bodyPr.remove(found)
|
|
158
|
-
bodyPr.append(
|
|
159
|
-
bodyPr.makeelement(
|
|
160
|
-
qn('a:normAutofit'),
|
|
161
|
-
{
|
|
162
|
-
'fontScale': str(int(scale * 100000)),
|
|
163
|
-
'lnSpcReduction': '0' if scale >= 1.0 else '10000'
|
|
164
|
-
}
|
|
165
|
-
)
|
|
166
|
-
)
|
|
167
|
-
changed = True
|
|
168
|
-
if changed:
|
|
169
|
-
try:
|
|
170
|
-
prs.save(name)
|
|
171
|
-
except Exception:
|
|
172
|
-
pass
|
|
173
|
-
`;
|
|
174
108
|
class InstallTimeoutError extends Error {
|
|
175
109
|
}
|
|
176
110
|
function installSource(py, packages) {
|
|
@@ -213,21 +147,6 @@ function listFiles(py, dir) {
|
|
|
213
147
|
function newDeliverables(before, after) {
|
|
214
148
|
return [...after].filter((name) => !before.has(name) && DELIVERABLE.test(name));
|
|
215
149
|
}
|
|
216
|
-
function fitDecks(py, outputs) {
|
|
217
|
-
if (!outputs.some((name) => name.toLowerCase().endsWith('.pptx'))) {
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
try {
|
|
221
|
-
py.runPython(`${FIT_DECKS}\n_qvac_fit_decks(${JSON.stringify(outputs)})`);
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
hlog('python: deck fit skipped', {
|
|
226
|
-
err: errorMessage(error)
|
|
227
|
-
});
|
|
228
|
-
return isPyodideFatal(error);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
150
|
export async function performRun(py, spec, opts = {}) {
|
|
232
151
|
const isCancelled = opts.isCancelled ?? (() => false);
|
|
233
152
|
const ask = opts.askConnect ?? (async () => false);
|
|
@@ -297,10 +216,7 @@ export async function performRun(py, spec, opts = {}) {
|
|
|
297
216
|
maxOutputChars: spec.maxOutputChars,
|
|
298
217
|
access
|
|
299
218
|
});
|
|
300
|
-
|
|
301
|
-
if (result.exitCode === 0) {
|
|
302
|
-
evict = fitDecks(py, spec.outputs ?? []);
|
|
303
|
-
}
|
|
219
|
+
const evict = fatal;
|
|
304
220
|
if (evict) {
|
|
305
221
|
return { result: { ...result, missing: spec.outputs ?? [] }, evict };
|
|
306
222
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare function bareBin(token: string): string | null;
|
|
2
2
|
export declare function firstCommandToken(command: string): string;
|
|
3
|
+
export declare function escapeLiteralDollars(command: string): string;
|
|
4
|
+
export declare const SHELL_EXPANSION_ERROR: string;
|
|
3
5
|
export declare function sanitizeCommand(command: string): string | null;
|
|
@@ -50,12 +50,43 @@ function skipDoubleQuoted(chars, open) {
|
|
|
50
50
|
return 'command must not use backtick substitution';
|
|
51
51
|
}
|
|
52
52
|
if (chars[i] === '$') {
|
|
53
|
-
return
|
|
53
|
+
return SHELL_EXPANSION_ERROR;
|
|
54
54
|
}
|
|
55
55
|
i++;
|
|
56
56
|
}
|
|
57
57
|
return i + 1;
|
|
58
58
|
}
|
|
59
|
+
const EXPANDS = /[A-Za-z_{(?#@*!$-]/;
|
|
60
|
+
export function escapeLiteralDollars(command) {
|
|
61
|
+
const chars = [...command];
|
|
62
|
+
let out = '';
|
|
63
|
+
let quoted = false;
|
|
64
|
+
for (let i = 0; i < chars.length; i++) {
|
|
65
|
+
const c = chars[i] ?? '';
|
|
66
|
+
if (c === "'" && !quoted) {
|
|
67
|
+
const end = chars.indexOf("'", i + 1);
|
|
68
|
+
const stop = end === -1 ? chars.length : end + 1;
|
|
69
|
+
out += chars.slice(i, stop).join('');
|
|
70
|
+
i = stop - 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (c === '\\') {
|
|
74
|
+
out += c + (chars[i + 1] ?? '');
|
|
75
|
+
i++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (c === '"') {
|
|
79
|
+
quoted = !quoted;
|
|
80
|
+
}
|
|
81
|
+
if (c === '$' && !EXPANDS.test(chars[i + 1] ?? '')) {
|
|
82
|
+
out += '\\';
|
|
83
|
+
}
|
|
84
|
+
out += c;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
export const SHELL_EXPANSION_ERROR = 'command must not use shell expansion: $ outside single quotes is expanded by the shell. ' +
|
|
89
|
+
"Put text containing $ (prices, amounts) in single quotes, e.g. content='Total: $1,348'";
|
|
59
90
|
export function sanitizeCommand(command) {
|
|
60
91
|
const chars = [...command];
|
|
61
92
|
let i = 0;
|
|
@@ -98,7 +129,7 @@ export function sanitizeCommand(command) {
|
|
|
98
129
|
return 'command must not use backtick substitution';
|
|
99
130
|
}
|
|
100
131
|
if (c === '$') {
|
|
101
|
-
return
|
|
132
|
+
return SHELL_EXPANSION_ERROR;
|
|
102
133
|
}
|
|
103
134
|
if (c === ';') {
|
|
104
135
|
return 'command must not chain with ;';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { AbortedError } from '../helpers/race-abort.js';
|
|
4
|
-
import {
|
|
5
|
-
import { pythonCreateEffect } from './exec/adapters/python/create-effect.js';
|
|
4
|
+
import { checkPythonSource, createPythonAdapter, isPythonLanguage, officeImportError, parseInputs, parseOutputs, parsePackages, parseWorkdir, pinned, runsThroughPyodide, sandboxInstallError, unwrapPythonSource } from './exec/adapters/python/python-adapter.js';
|
|
6
5
|
import { namedHosts } from './exec/adapters/python/named-hosts.js';
|
|
7
6
|
import { pythonReachesNetwork } from './exec/adapters/python/net-shim.js';
|
|
8
7
|
import { createShellAdapter } from './exec/adapters/shell/shell-adapter.js';
|
|
@@ -422,7 +421,7 @@ export function createExecTool({ spawn, killProcess, loadPyodide, disablePyodide
|
|
|
422
421
|
return 'read';
|
|
423
422
|
}
|
|
424
423
|
if (runsThroughPyodide(args.language, disablePyodide)) {
|
|
425
|
-
return
|
|
424
|
+
return 'write';
|
|
426
425
|
}
|
|
427
426
|
return shellEffect(String(args.command ?? '').trim(), ctx?.toolOps);
|
|
428
427
|
},
|
|
@@ -459,6 +458,13 @@ export function createExecTool({ spawn, killProcess, loadPyodide, disablePyodide
|
|
|
459
458
|
if (packages && 'error' in packages) {
|
|
460
459
|
return packages.error;
|
|
461
460
|
}
|
|
461
|
+
const office = officeImportError(unwrapPythonSource(command) ?? command, {
|
|
462
|
+
packages,
|
|
463
|
+
toolNames: ctx?.toolNames
|
|
464
|
+
});
|
|
465
|
+
if (office) {
|
|
466
|
+
return office;
|
|
467
|
+
}
|
|
462
468
|
const refusal = ctx?.sandboxMode === true ? sandboxInstallError(command, packages) : null;
|
|
463
469
|
if (refusal) {
|
|
464
470
|
return refusal;
|
|
@@ -468,23 +474,6 @@ export function createExecTool({ spawn, killProcess, loadPyodide, disablePyodide
|
|
|
468
474
|
if (sourceError) {
|
|
469
475
|
return sourceError;
|
|
470
476
|
}
|
|
471
|
-
const pptxError = checkPptxBuildSource(unwrapPythonSource(command) ?? command, outputs, packages);
|
|
472
|
-
if (pptxError) {
|
|
473
|
-
return pptxError;
|
|
474
|
-
}
|
|
475
|
-
const pdfError = checkPdfBuildSource(unwrapPythonSource(command) ?? command, outputs, packages);
|
|
476
|
-
if (pdfError) {
|
|
477
|
-
return pdfError;
|
|
478
|
-
}
|
|
479
|
-
const bareLength = checkBareLengthArgs(unwrapPythonSource(command) ?? command, packages);
|
|
480
|
-
if (bareLength) {
|
|
481
|
-
return bareLength;
|
|
482
|
-
}
|
|
483
|
-
const inputs = parseInputs(rawArgs.inputs);
|
|
484
|
-
const unstagedRead = checkUnstagedRead(unwrapPythonSource(command) ?? command, Array.isArray(inputs) ? inputs : undefined);
|
|
485
|
-
if (unstagedRead) {
|
|
486
|
-
return unstagedRead;
|
|
487
|
-
}
|
|
488
477
|
}
|
|
489
478
|
}
|
|
490
479
|
const parsed = parsePackages(rawArgs.packages);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Slot = string | readonly string[];
|
|
2
|
+
export interface OpSpec {
|
|
3
|
+
readonly slots: readonly Slot[];
|
|
4
|
+
readonly inches?: boolean;
|
|
5
|
+
readonly query?: boolean;
|
|
6
|
+
readonly aliases?: Readonly<Record<string, string>>;
|
|
7
|
+
}
|
|
8
|
+
export declare const PPTX_OPS: Readonly<Record<string, OpSpec>>;
|
|
9
|
+
export declare const DOCX_OPS: Readonly<Record<string, OpSpec>>;
|
|
10
|
+
export declare const XLSX_OPS: Readonly<Record<string, OpSpec>>;
|
|
11
|
+
export declare function opKeys(spec: OpSpec): string[];
|
|
12
|
+
export declare function withAliases(spec: OpSpec, op: Readonly<Record<string, unknown>>): Record<string, unknown>;
|
|
13
|
+
export declare function opArguments(spec: OpSpec, op: Readonly<Record<string, unknown>>, toEmu: (inches: number) => number): unknown[];
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const TABLE_INDEX = { index: 'table' };
|
|
2
|
+
const BOX = ['x', 'y', 'width', 'height'];
|
|
3
|
+
const CHART = ['type', 'categories', 'series', 'title', 'stacked', 'legend', 'name'];
|
|
4
|
+
export const PPTX_OPS = {
|
|
5
|
+
read: { slots: [], query: true },
|
|
6
|
+
layouts: { slots: [], query: true },
|
|
7
|
+
setText: { slots: [['slide', 'shape'], 'text'] },
|
|
8
|
+
setCellText: { slots: [['slide', 'shape', 'row', 'column'], 'text'] },
|
|
9
|
+
setStyle: { slots: [['slide', 'shape'], 'style', ['paragraph']] },
|
|
10
|
+
addSlide: { slots: [['like', 'layout', 'at', 'title', 'body']] },
|
|
11
|
+
addPicture: { slots: ['slide', 'image', [...BOX, 'name', 'description']], inches: true },
|
|
12
|
+
addTextBox: { slots: ['slide', [...BOX, 'text', 'style', 'fill', 'name']], inches: true },
|
|
13
|
+
addTable: { slots: ['slide', [...BOX, 'rows', 'header', 'name']], inches: true },
|
|
14
|
+
addChart: { slots: ['slide', [...BOX, ...CHART]], inches: true },
|
|
15
|
+
setChartData: {
|
|
16
|
+
slots: [
|
|
17
|
+
['slide', 'shape'],
|
|
18
|
+
['categories', 'series']
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
setChartTitle: { slots: [['slide', 'shape'], 'title'] },
|
|
22
|
+
setBackground: { slots: ['slide', 'color'] },
|
|
23
|
+
deleteSlide: { slots: ['slide'] },
|
|
24
|
+
moveSlide: { slots: ['from', ['to']] }
|
|
25
|
+
};
|
|
26
|
+
export const DOCX_OPS = {
|
|
27
|
+
read: { slots: [], query: true },
|
|
28
|
+
sections: { slots: [], query: true },
|
|
29
|
+
paragraphStyles: { slots: [], query: true },
|
|
30
|
+
setText: { slots: ['index', 'text'] },
|
|
31
|
+
insertParagraphs: { slots: ['at', 'paragraphs'] },
|
|
32
|
+
appendParagraphs: { slots: ['paragraphs'] },
|
|
33
|
+
replaceSection: { slots: ['index', ['title', 'body']] },
|
|
34
|
+
deleteSection: { slots: ['index'] },
|
|
35
|
+
deleteBlocks: { slots: ['index', ['count']] },
|
|
36
|
+
formatParagraph: { slots: ['index', 'format'] },
|
|
37
|
+
formatStyle: { slots: ['name', 'format'] },
|
|
38
|
+
addTable: { slots: ['at', ['rows', 'header', 'style']] },
|
|
39
|
+
setCell: { slots: [['table', 'row', 'column'], 'text'], aliases: TABLE_INDEX },
|
|
40
|
+
addRow: { slots: ['table', 'values', ['at']], aliases: TABLE_INDEX },
|
|
41
|
+
deleteRow: { slots: [['table', 'row']], aliases: TABLE_INDEX },
|
|
42
|
+
addImage: {
|
|
43
|
+
slots: ['at', 'image', ['width', 'height', 'align', 'name', 'description']],
|
|
44
|
+
inches: true
|
|
45
|
+
},
|
|
46
|
+
addChart: { slots: ['at', ['width', 'height', ...CHART]], inches: true },
|
|
47
|
+
setChartData: { slots: ['index', ['categories', 'series'], ['chart']] },
|
|
48
|
+
setChartTitle: { slots: ['index', 'title', ['chart']] }
|
|
49
|
+
};
|
|
50
|
+
export const XLSX_OPS = {
|
|
51
|
+
sheets: { slots: [], query: true },
|
|
52
|
+
read: { slots: ['sheet', ['range', 'limit']], query: true },
|
|
53
|
+
get: { slots: ['sheet', 'ref'], query: true },
|
|
54
|
+
setCells: { slots: ['sheet', 'cells'] },
|
|
55
|
+
appendRows: { slots: ['sheet', 'rows'] },
|
|
56
|
+
insertRows: { slots: ['sheet', ['at', 'rows', 'count']] },
|
|
57
|
+
deleteRows: { slots: ['sheet', ['at', 'count']] },
|
|
58
|
+
deleteColumns: { slots: ['sheet', ['column', 'count']] },
|
|
59
|
+
setColumnWidth: { slots: ['sheet', ['column', 'width']] },
|
|
60
|
+
addSheet: { slots: ['name', ['at']] },
|
|
61
|
+
renameSheet: { slots: ['sheet', 'name'] },
|
|
62
|
+
deleteSheet: { slots: ['sheet'] },
|
|
63
|
+
addImage: {
|
|
64
|
+
slots: ['sheet', 'image', ['cell', 'width', 'height', 'name', 'description']],
|
|
65
|
+
inches: true
|
|
66
|
+
},
|
|
67
|
+
removeMacros: { slots: [] }
|
|
68
|
+
};
|
|
69
|
+
const LENGTHS = new Set(BOX);
|
|
70
|
+
export function opKeys(spec) {
|
|
71
|
+
const keys = spec.slots.flatMap((slot) => (typeof slot === 'string' ? [slot] : [...slot]));
|
|
72
|
+
return [...keys, ...Object.keys(spec.aliases ?? {})];
|
|
73
|
+
}
|
|
74
|
+
export function withAliases(spec, op) {
|
|
75
|
+
const named = { ...op };
|
|
76
|
+
for (const [alias, key] of Object.entries(spec.aliases ?? {})) {
|
|
77
|
+
if (alias in named && named[key] === undefined) {
|
|
78
|
+
named[key] = named[alias];
|
|
79
|
+
}
|
|
80
|
+
delete named[alias];
|
|
81
|
+
}
|
|
82
|
+
return named;
|
|
83
|
+
}
|
|
84
|
+
export function opArguments(spec, op, toEmu) {
|
|
85
|
+
const value = (key) => {
|
|
86
|
+
const raw = op[key];
|
|
87
|
+
return spec.inches && LENGTHS.has(key) && typeof raw === 'number' ? toEmu(raw) : raw;
|
|
88
|
+
};
|
|
89
|
+
const args = spec.slots.map((slot) => {
|
|
90
|
+
if (typeof slot === 'string') {
|
|
91
|
+
return value(slot);
|
|
92
|
+
}
|
|
93
|
+
const present = slot.filter((key) => op[key] !== undefined);
|
|
94
|
+
return present.length ? Object.fromEntries(present.map((key) => [key, value(key)])) : undefined;
|
|
95
|
+
});
|
|
96
|
+
while (args.length && args.at(-1) === undefined) {
|
|
97
|
+
args.pop();
|
|
98
|
+
}
|
|
99
|
+
return args;
|
|
100
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolDefinition } from '../capabilities/completion.ts';
|
|
2
|
+
import { pptx, xlsx } from '../office/engine/index.ts';
|
|
3
|
+
type Deck = ReturnType<typeof pptx.open>;
|
|
4
|
+
type Workbook = ReturnType<typeof xlsx.open>;
|
|
5
|
+
type FormatName = 'pptx' | 'docx' | 'xlsx';
|
|
6
|
+
type Args = Record<string, unknown>;
|
|
7
|
+
export declare function shapeFor(deck: Deck, op: Args): Args;
|
|
8
|
+
export declare function sheetFor(book: Workbook, op: Args, created: boolean): Args;
|
|
9
|
+
export declare function normalizeArgs(args: Args): Args;
|
|
10
|
+
export declare function revisedName(format: FormatName, fileName: string): string;
|
|
11
|
+
export declare function createOfficeTools(): ToolDefinition[];
|
|
12
|
+
export {};
|