@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
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { errorCode, errorMessage } from '../guards.js';
|
|
2
|
+
import { checkOutputBytes, RUN_OUTPUT_BUDGET_BYTES } from './exec/adapters/python/output-policy.js';
|
|
3
|
+
import { build, pagesLabel, readDocs } from './pdf/build.js';
|
|
4
|
+
import { placeImages } from './pdf/images.js';
|
|
5
|
+
import { PAGE_SIZES, parseRequest, PDF_ACTIONS, WHERE_IDS_ARE } from './pdf/request.js';
|
|
6
|
+
export { parsePages, parseRequest } from './pdf/request.js';
|
|
7
|
+
const SUFFIXES = {
|
|
8
|
+
create: 'revised',
|
|
9
|
+
merge: 'merged',
|
|
10
|
+
split: 'pages',
|
|
11
|
+
rotate: 'rotated',
|
|
12
|
+
watermark: 'watermarked',
|
|
13
|
+
fill: 'filled',
|
|
14
|
+
encrypt: 'locked',
|
|
15
|
+
decrypt: 'unlocked',
|
|
16
|
+
text: 'text',
|
|
17
|
+
read: 'copy'
|
|
18
|
+
};
|
|
19
|
+
const attachedThisTurn = new WeakMap();
|
|
20
|
+
let loaded = null;
|
|
21
|
+
function loadPdfium() {
|
|
22
|
+
loaded ??= import('bare-pdfium').then((pdfium) => pdfium, () => null);
|
|
23
|
+
return loaded;
|
|
24
|
+
}
|
|
25
|
+
function stemOf(fileName) {
|
|
26
|
+
const base = fileName.replace(/^.*[\\/]/, '');
|
|
27
|
+
const dot = base.lastIndexOf('.');
|
|
28
|
+
return dot > 0 ? base.slice(0, dot) : base;
|
|
29
|
+
}
|
|
30
|
+
function slug(markdown) {
|
|
31
|
+
const heading = /^#{1,6}\s+(.+)$/m.exec(markdown)?.[1] ?? '';
|
|
32
|
+
const name = heading
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.replace(/[*_`[\]]/g, '')
|
|
35
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
36
|
+
.replace(/^_+|_+$/g, '')
|
|
37
|
+
.slice(0, 48);
|
|
38
|
+
return name || 'document';
|
|
39
|
+
}
|
|
40
|
+
function extensionOf(request) {
|
|
41
|
+
return request.action === 'text' ? 'txt' : 'pdf';
|
|
42
|
+
}
|
|
43
|
+
function defaultName(request, first) {
|
|
44
|
+
if (!first) {
|
|
45
|
+
return `${request.action === 'create' ? slug(request.markdown) : 'document'}.pdf`;
|
|
46
|
+
}
|
|
47
|
+
if (request.action === 'text') {
|
|
48
|
+
return `${stemOf(first.fileName)}.txt`;
|
|
49
|
+
}
|
|
50
|
+
return `${stemOf(first.fileName)}_${SUFFIXES[request.action]}.pdf`;
|
|
51
|
+
}
|
|
52
|
+
export function outputName(request, inputs) {
|
|
53
|
+
const extension = extensionOf(request);
|
|
54
|
+
const { output } = request;
|
|
55
|
+
let wanted = defaultName(request, inputs[0]);
|
|
56
|
+
if (output && /\.[a-z0-9]{2,4}$/i.test(output)) {
|
|
57
|
+
wanted = output.replace(/\.pdf$/i, `.${extension}`);
|
|
58
|
+
}
|
|
59
|
+
else if (output) {
|
|
60
|
+
wanted = `${output}.${extension}`;
|
|
61
|
+
}
|
|
62
|
+
const taken = inputs.some((input) => input.fileName.toLowerCase() === wanted.toLowerCase());
|
|
63
|
+
return taken ? `${stemOf(wanted)}_${SUFFIXES[request.action]}.${extension}` : wanted;
|
|
64
|
+
}
|
|
65
|
+
async function fetchSources(ids, ctx) {
|
|
66
|
+
if (!ctx.fetchAttachment) {
|
|
67
|
+
return { error: 'this device cannot read chat attachments' };
|
|
68
|
+
}
|
|
69
|
+
const sources = [];
|
|
70
|
+
for (const attachmentId of ids) {
|
|
71
|
+
const found = await ctx.fetchAttachment({ attachmentId, signal: ctx.signal });
|
|
72
|
+
if (!found || !('bytes' in found)) {
|
|
73
|
+
return { error: `attachment ${attachmentId} not found in this chat; ${WHERE_IDS_ARE}` };
|
|
74
|
+
}
|
|
75
|
+
sources.push({ attachmentId, fileName: found.fileName, bytes: found.bytes });
|
|
76
|
+
}
|
|
77
|
+
return sources;
|
|
78
|
+
}
|
|
79
|
+
function openError(err, source, password) {
|
|
80
|
+
const code = errorCode(err);
|
|
81
|
+
if (code === 'PASSWORD' && password) {
|
|
82
|
+
return `the password is wrong for ${source.fileName}; ask the user for the right one, never guess`;
|
|
83
|
+
}
|
|
84
|
+
if (code === 'PASSWORD') {
|
|
85
|
+
return `${source.fileName} is locked; ask the user for its password and pass it as password`;
|
|
86
|
+
}
|
|
87
|
+
if (code === 'FORMAT' || code === 'FILE') {
|
|
88
|
+
return `${source.fileName} is not a PDF that opens`;
|
|
89
|
+
}
|
|
90
|
+
return `${source.fileName}: ${errorMessage(err)}`;
|
|
91
|
+
}
|
|
92
|
+
function openAll(pdfium, sources, request) {
|
|
93
|
+
const password = request.action === 'encrypt' ? undefined : request.password;
|
|
94
|
+
const opened = [];
|
|
95
|
+
for (const source of sources) {
|
|
96
|
+
try {
|
|
97
|
+
opened.push({ source, doc: pdfium.open(source.bytes, { password }) });
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
return { opened, error: openError(err, source, password) };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { opened, error: null };
|
|
104
|
+
}
|
|
105
|
+
async function attachOutput(fileName, bytes, ctx) {
|
|
106
|
+
if (!ctx.attach) {
|
|
107
|
+
return { error: 'this device cannot attach a file to the chat' };
|
|
108
|
+
}
|
|
109
|
+
const delivered = attachedThisTurn.get(ctx.attach) ?? new Map();
|
|
110
|
+
const earlier = delivered.get(fileName.toLowerCase());
|
|
111
|
+
if (earlier) {
|
|
112
|
+
return { attachment: earlier, repeated: true };
|
|
113
|
+
}
|
|
114
|
+
const verdict = checkOutputBytes(fileName, bytes, 0);
|
|
115
|
+
if ('error' in verdict) {
|
|
116
|
+
return verdict;
|
|
117
|
+
}
|
|
118
|
+
const budget = ctx.runBudget;
|
|
119
|
+
if (budget && budget.outputBytesUsed + bytes.byteLength > RUN_OUTPUT_BUDGET_BYTES) {
|
|
120
|
+
return { error: 'run output budget exceeded' };
|
|
121
|
+
}
|
|
122
|
+
const record = await ctx.attach({ fileName, mimeType: verdict.mimeType, bytes, raw: true });
|
|
123
|
+
if (budget) {
|
|
124
|
+
budget.outputBytesUsed += bytes.byteLength;
|
|
125
|
+
}
|
|
126
|
+
const attachment = {
|
|
127
|
+
attachmentId: record.id,
|
|
128
|
+
fileName: record.fileName,
|
|
129
|
+
byteLength: record.byteLength
|
|
130
|
+
};
|
|
131
|
+
delivered.set(fileName.toLowerCase(), attachment);
|
|
132
|
+
attachedThisTurn.set(ctx.attach, delivered);
|
|
133
|
+
return { attachment, repeated: false };
|
|
134
|
+
}
|
|
135
|
+
const UNDRAWABLE = /^('[^']+' \(U\+[0-9A-F]+\)(?:, '[^']+' \(U\+[0-9A-F]+\))*) cannot be drawn by the built-in fonts/;
|
|
136
|
+
function buildError(err) {
|
|
137
|
+
const message = errorMessage(err);
|
|
138
|
+
const characters = UNDRAWABLE.exec(message)?.[1];
|
|
139
|
+
if (!characters) {
|
|
140
|
+
return message;
|
|
141
|
+
}
|
|
142
|
+
return (`${characters} cannot be drawn: a PDF made here takes Western European text only. ` +
|
|
143
|
+
'Leave those characters out, or tell the user this text cannot go in a PDF');
|
|
144
|
+
}
|
|
145
|
+
function buildSafely({ pdfium, request, opened }) {
|
|
146
|
+
try {
|
|
147
|
+
return build(pdfium, request, opened);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
return buildError(err);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function reply(request, { output, built, delivered }) {
|
|
154
|
+
const { attachment, repeated } = delivered;
|
|
155
|
+
const summary = request.action === 'text'
|
|
156
|
+
? `text of ${pagesLabel(built.pageCount)}`
|
|
157
|
+
: pagesLabel(built.pageCount);
|
|
158
|
+
const renamed = request.output && output !== request.output
|
|
159
|
+
? `Saved as ${output}, so the attached file keeps its own name. `
|
|
160
|
+
: '';
|
|
161
|
+
return {
|
|
162
|
+
attachments: [attachment],
|
|
163
|
+
pageCount: built.pageCount,
|
|
164
|
+
reply: `${attachment.fileName} — ${summary}`,
|
|
165
|
+
next: renamed +
|
|
166
|
+
`Done: ${attachment.fileName} ${repeated ? 'was already' : 'is'} attached to the chat and shown to the user. ` +
|
|
167
|
+
'Do not call pdf again for it. Your answer is the reply value alone, word for word.'
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function deliver(job, ctx) {
|
|
171
|
+
const { request, opened } = job;
|
|
172
|
+
const output = outputName(request, opened.map((one) => one.source));
|
|
173
|
+
const extension = `.${extensionOf(request)}`;
|
|
174
|
+
if (!output.toLowerCase().endsWith(extension)) {
|
|
175
|
+
return { error: `output must end in ${extension}, got "${output}"` };
|
|
176
|
+
}
|
|
177
|
+
const built = buildSafely(job);
|
|
178
|
+
if (typeof built === 'string') {
|
|
179
|
+
return { error: built };
|
|
180
|
+
}
|
|
181
|
+
const delivered = await attachOutput(output, built.bytes, ctx);
|
|
182
|
+
return 'error' in delivered ? delivered : reply(request, { output, built, delivered });
|
|
183
|
+
}
|
|
184
|
+
function isLocked(pdfium, source) {
|
|
185
|
+
try {
|
|
186
|
+
pdfium.open(source.bytes).close();
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
return errorCode(err) === 'PASSWORD';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function lockOrUnlock(pdfium, request, sources) {
|
|
194
|
+
const [only] = sources;
|
|
195
|
+
const wantsFile = request.output?.toLowerCase().endsWith('.pdf') === true;
|
|
196
|
+
if (request.action !== 'read' || !request.password || !wantsFile || !only || sources.length > 1) {
|
|
197
|
+
return request;
|
|
198
|
+
}
|
|
199
|
+
if (isLocked(pdfium, only)) {
|
|
200
|
+
return { ...request, action: 'decrypt' };
|
|
201
|
+
}
|
|
202
|
+
return { ...request, action: 'encrypt', ownerPassword: undefined, permissions: undefined };
|
|
203
|
+
}
|
|
204
|
+
async function run(pdfium, asked, ctx) {
|
|
205
|
+
if (asked.action === 'create') {
|
|
206
|
+
const placed = await placeImages(asked, ctx);
|
|
207
|
+
return 'error' in placed ? placed : deliver({ pdfium, request: placed, opened: [] }, ctx);
|
|
208
|
+
}
|
|
209
|
+
const sources = asked.ids.length ? await fetchSources(asked.ids, ctx) : [];
|
|
210
|
+
if ('error' in sources) {
|
|
211
|
+
return sources;
|
|
212
|
+
}
|
|
213
|
+
const request = lockOrUnlock(pdfium, asked, sources);
|
|
214
|
+
const { opened, error } = openAll(pdfium, sources, request);
|
|
215
|
+
try {
|
|
216
|
+
if (error) {
|
|
217
|
+
return { error };
|
|
218
|
+
}
|
|
219
|
+
if (request.action === 'read') {
|
|
220
|
+
return readDocs(opened);
|
|
221
|
+
}
|
|
222
|
+
return await deliver({ pdfium, request, opened }, ctx);
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
for (const { doc } of opened) {
|
|
226
|
+
doc.close();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const DESCRIPTION = 'Create, read or change PDF files. With attachmentId and no action it returns the page ' +
|
|
231
|
+
'count, each page’s text and the form fields (name, type, value, options). An action saves ' +
|
|
232
|
+
'a new file named output and attaches it to the chat: create (markdown, where ' +
|
|
233
|
+
' on its own line places a chat image and the file name of the ' +
|
|
234
|
+
"user's upload places that upload; optional pageSize, " +
|
|
235
|
+
'landscape, pageNumbers, password), merge (attachmentIds in order), split (pages), rotate ' +
|
|
236
|
+
'(degrees 90, 180 or 270, optional pages), watermark (text, optional opacity, position, ' +
|
|
237
|
+
'pages), fill (values keyed by field name), encrypt (password, optional ownerPassword, ' +
|
|
238
|
+
'permissions), decrypt (password), text (a .txt of the text). Pages count from 1. A locked ' +
|
|
239
|
+
'PDF needs its password on every action. A failing call saves nothing and its error names ' +
|
|
240
|
+
'what exists, so fix the call from it.';
|
|
241
|
+
const PARAMETERS = {
|
|
242
|
+
type: 'object',
|
|
243
|
+
properties: {
|
|
244
|
+
action: {
|
|
245
|
+
type: 'string',
|
|
246
|
+
enum: [...PDF_ACTIONS],
|
|
247
|
+
description: 'What to do; leave it out to read the PDF'
|
|
248
|
+
},
|
|
249
|
+
attachmentId: { type: 'string', description: 'The PDF in this chat' },
|
|
250
|
+
attachmentIds: {
|
|
251
|
+
type: 'array',
|
|
252
|
+
items: { type: 'string' },
|
|
253
|
+
description: 'merge: the PDFs to join, in order'
|
|
254
|
+
},
|
|
255
|
+
markdown: { type: 'string', description: 'create: the whole document as Markdown' },
|
|
256
|
+
pages: {
|
|
257
|
+
type: 'array',
|
|
258
|
+
items: { type: 'integer' },
|
|
259
|
+
description: 'Page numbers counted from 1'
|
|
260
|
+
},
|
|
261
|
+
degrees: { type: 'integer', description: 'rotate: 90, 180 or 270, clockwise' },
|
|
262
|
+
text: { type: 'string', description: 'watermark: the text to stamp' },
|
|
263
|
+
opacity: { type: 'number', description: 'watermark: 0 to 1' },
|
|
264
|
+
position: { type: 'string', enum: ['over', 'under'], description: 'watermark' },
|
|
265
|
+
values: { type: 'object', description: 'fill: { "field name": value }' },
|
|
266
|
+
password: {
|
|
267
|
+
type: 'string',
|
|
268
|
+
description: 'encrypt: the new password; otherwise the password of a locked PDF'
|
|
269
|
+
},
|
|
270
|
+
ownerPassword: { type: 'string', description: 'encrypt' },
|
|
271
|
+
permissions: { type: 'object', description: 'encrypt: { print, copy, modify, ... }' },
|
|
272
|
+
pageSize: { type: 'string', enum: [...PAGE_SIZES], description: 'create' },
|
|
273
|
+
landscape: { type: 'boolean', description: 'create' },
|
|
274
|
+
pageNumbers: { type: 'boolean', description: 'create' },
|
|
275
|
+
output: { type: 'string', description: 'File name for the saved file' }
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
export function createPdfTool(load = loadPdfium) {
|
|
279
|
+
return {
|
|
280
|
+
name: 'pdf',
|
|
281
|
+
toolset: null,
|
|
282
|
+
skillGated: true,
|
|
283
|
+
description: DESCRIPTION,
|
|
284
|
+
parameters: PARAMETERS,
|
|
285
|
+
effect: () => 'read',
|
|
286
|
+
validate(args) {
|
|
287
|
+
const request = parseRequest(args);
|
|
288
|
+
return typeof request === 'string' ? request : null;
|
|
289
|
+
},
|
|
290
|
+
async execute(args, ctx = {}) {
|
|
291
|
+
const request = parseRequest(args);
|
|
292
|
+
if (typeof request === 'string') {
|
|
293
|
+
return { error: request };
|
|
294
|
+
}
|
|
295
|
+
const pdfium = await load();
|
|
296
|
+
if (!pdfium) {
|
|
297
|
+
return { error: 'this device cannot open PDFs' };
|
|
298
|
+
}
|
|
299
|
+
return run(pdfium, request, ctx);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
@@ -158,6 +158,14 @@ export function createSkillTool({ skillsDir, overlayDir = resolveSkillsOverlayDi
|
|
|
158
158
|
content: notes.length ? [content.trim(), ...notes].join('\n\n') : content
|
|
159
159
|
};
|
|
160
160
|
};
|
|
161
|
+
const mainInstead = async (asked, available) => {
|
|
162
|
+
const main = await load(MAIN_FILE);
|
|
163
|
+
const others = available.length ? ` Its other files: ${available.join(', ')}.` : '';
|
|
164
|
+
return {
|
|
165
|
+
...main,
|
|
166
|
+
content: `There is no file ${asked} in this skill; these are its instructions.${others}\n\n${main.content}`
|
|
167
|
+
};
|
|
168
|
+
};
|
|
161
169
|
try {
|
|
162
170
|
return await load(file);
|
|
163
171
|
}
|
|
@@ -173,6 +181,12 @@ export function createSkillTool({ skillsDir, overlayDir = resolveSkillsOverlayDi
|
|
|
173
181
|
}
|
|
174
182
|
catch { }
|
|
175
183
|
}
|
|
184
|
+
if (!ctx?.skillsLoadedThisTurn?.includes(name)) {
|
|
185
|
+
try {
|
|
186
|
+
return await mainInstead(file, available);
|
|
187
|
+
}
|
|
188
|
+
catch { }
|
|
189
|
+
}
|
|
176
190
|
const rest = available.length
|
|
177
191
|
? ` — files this skill has: ${available.join(', ')}`
|
|
178
192
|
: '. This skill has no other files; you already have its full instructions — act now.';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qvac/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"bare": ">=1.34.0"
|
|
@@ -210,10 +210,6 @@
|
|
|
210
210
|
"types": "./dist-lib/lib/tools/exec/adapters/python/attachments.d.ts",
|
|
211
211
|
"default": "./dist-lib/lib/tools/exec/adapters/python/attachments.js"
|
|
212
212
|
},
|
|
213
|
-
"./lib/tools/exec/adapters/python/create-effect.ts": {
|
|
214
|
-
"types": "./dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts",
|
|
215
|
-
"default": "./dist-lib/lib/tools/exec/adapters/python/create-effect.js"
|
|
216
|
-
},
|
|
217
213
|
"./lib/tools/exec/adapters/python/deadline-state.ts": {
|
|
218
214
|
"types": "./dist-lib/lib/tools/exec/adapters/python/deadline-state.d.ts",
|
|
219
215
|
"default": "./dist-lib/lib/tools/exec/adapters/python/deadline-state.js"
|
|
@@ -454,6 +450,14 @@
|
|
|
454
450
|
"types": "./dist-lib/lib/tools/model-args.d.ts",
|
|
455
451
|
"default": "./dist-lib/lib/tools/model-args.js"
|
|
456
452
|
},
|
|
453
|
+
"./lib/tools/office.ts": {
|
|
454
|
+
"types": "./dist-lib/lib/tools/office.d.ts",
|
|
455
|
+
"default": "./dist-lib/lib/tools/office.js"
|
|
456
|
+
},
|
|
457
|
+
"./lib/tools/office/ops.ts": {
|
|
458
|
+
"types": "./dist-lib/lib/tools/office/ops.d.ts",
|
|
459
|
+
"default": "./dist-lib/lib/tools/office/ops.js"
|
|
460
|
+
},
|
|
457
461
|
"./lib/tools/operations/builders.ts": {
|
|
458
462
|
"types": "./dist-lib/lib/tools/operations/builders.d.ts",
|
|
459
463
|
"default": "./dist-lib/lib/tools/operations/builders.js"
|
|
@@ -478,6 +482,22 @@
|
|
|
478
482
|
"types": "./dist-lib/lib/tools/outbound-guard.d.ts",
|
|
479
483
|
"default": "./dist-lib/lib/tools/outbound-guard.js"
|
|
480
484
|
},
|
|
485
|
+
"./lib/tools/pdf.ts": {
|
|
486
|
+
"types": "./dist-lib/lib/tools/pdf.d.ts",
|
|
487
|
+
"default": "./dist-lib/lib/tools/pdf.js"
|
|
488
|
+
},
|
|
489
|
+
"./lib/tools/pdf/build.ts": {
|
|
490
|
+
"types": "./dist-lib/lib/tools/pdf/build.d.ts",
|
|
491
|
+
"default": "./dist-lib/lib/tools/pdf/build.js"
|
|
492
|
+
},
|
|
493
|
+
"./lib/tools/pdf/images.ts": {
|
|
494
|
+
"types": "./dist-lib/lib/tools/pdf/images.d.ts",
|
|
495
|
+
"default": "./dist-lib/lib/tools/pdf/images.js"
|
|
496
|
+
},
|
|
497
|
+
"./lib/tools/pdf/request.ts": {
|
|
498
|
+
"types": "./dist-lib/lib/tools/pdf/request.d.ts",
|
|
499
|
+
"default": "./dist-lib/lib/tools/pdf/request.js"
|
|
500
|
+
},
|
|
481
501
|
"./lib/tools/private-ip.ts": {
|
|
482
502
|
"types": "./dist-lib/lib/tools/private-ip.d.ts",
|
|
483
503
|
"default": "./dist-lib/lib/tools/private-ip.js"
|
|
@@ -716,13 +736,19 @@
|
|
|
716
736
|
"types": "@qvac/sdk",
|
|
717
737
|
"bare": "@qvac/inference",
|
|
718
738
|
"default": "@qvac/sdk"
|
|
739
|
+
},
|
|
740
|
+
"#zlib": {
|
|
741
|
+
"types": "bare-zlib",
|
|
742
|
+
"bare": "bare-zlib",
|
|
743
|
+
"default": "zlib"
|
|
719
744
|
}
|
|
720
745
|
},
|
|
721
746
|
"dependencies": {
|
|
722
747
|
"@qvac/inference": "0.20.0",
|
|
723
748
|
"@qvac/langdetect-text": "0.1.2",
|
|
724
749
|
"@qvac/sdk": "0.20.0",
|
|
725
|
-
"@qvac/skills": "0.1.
|
|
750
|
+
"@qvac/skills": "0.1.12",
|
|
751
|
+
"@xmldom/xmldom": "^0.9.12",
|
|
726
752
|
"asenion": "^0.1.0",
|
|
727
753
|
"b4a": "^1.9.0",
|
|
728
754
|
"bare-abort-controller": "^1.1.2",
|
|
@@ -743,6 +769,7 @@
|
|
|
743
769
|
"bare-net": "^2.3.2",
|
|
744
770
|
"bare-os": "^3.9.1",
|
|
745
771
|
"bare-path": "^3.0.1",
|
|
772
|
+
"bare-pdfium": "^1.6.0",
|
|
746
773
|
"bare-process": "4.4.1",
|
|
747
774
|
"bare-sidecar": "0.5.7",
|
|
748
775
|
"bare-storage": "^1.1.0",
|
|
@@ -754,6 +781,7 @@
|
|
|
754
781
|
"bare-tty": "^5.1.2",
|
|
755
782
|
"bare-url": "^2.4.5",
|
|
756
783
|
"bare-worker": "^4.5.0",
|
|
784
|
+
"bare-zlib": "^1.4.1",
|
|
757
785
|
"compact-encoding": "^3.4.0",
|
|
758
786
|
"hrpc": "^4.3.0",
|
|
759
787
|
"hyperschema": "^1.23.0",
|
package/wheels/manifest.json
CHANGED
|
@@ -1,170 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"pyodide": "314.0.2",
|
|
3
|
-
"packages": {
|
|
4
|
-
"fpdf2": {
|
|
5
|
-
"version": "2.8.8",
|
|
6
|
-
"imports": [
|
|
7
|
-
"fpdf"
|
|
8
|
-
],
|
|
9
|
-
"pypi": [
|
|
10
|
-
"defusedxml-0.7.1-py2.py3-none-any.whl",
|
|
11
|
-
"fpdf2-2.8.8-py3-none-any.whl"
|
|
12
|
-
],
|
|
13
|
-
"pyodide": [
|
|
14
|
-
"pillow",
|
|
15
|
-
"fonttools"
|
|
16
|
-
]
|
|
17
|
-
},
|
|
18
|
-
"pypdf": {
|
|
19
|
-
"version": "6.15.0",
|
|
20
|
-
"imports": [
|
|
21
|
-
"pypdf"
|
|
22
|
-
],
|
|
23
|
-
"pypi": [
|
|
24
|
-
"pypdf-6.15.0-py3-none-any.whl"
|
|
25
|
-
],
|
|
26
|
-
"pyodide": []
|
|
27
|
-
},
|
|
28
|
-
"openpyxl": {
|
|
29
|
-
"version": "3.1.5",
|
|
30
|
-
"imports": [
|
|
31
|
-
"openpyxl"
|
|
32
|
-
],
|
|
33
|
-
"pypi": [
|
|
34
|
-
"et_xmlfile-2.0.0-py3-none-any.whl",
|
|
35
|
-
"openpyxl-3.1.5-py2.py3-none-any.whl"
|
|
36
|
-
],
|
|
37
|
-
"pyodide": []
|
|
38
|
-
},
|
|
39
|
-
"python-docx": {
|
|
40
|
-
"version": "1.2.0",
|
|
41
|
-
"imports": [
|
|
42
|
-
"docx"
|
|
43
|
-
],
|
|
44
|
-
"pypi": [
|
|
45
|
-
"python_docx-1.2.0-py3-none-any.whl"
|
|
46
|
-
],
|
|
47
|
-
"pyodide": [
|
|
48
|
-
"typing-extensions",
|
|
49
|
-
"lxml"
|
|
50
|
-
]
|
|
51
|
-
},
|
|
52
|
-
"python-pptx": {
|
|
53
|
-
"version": "1.0.2",
|
|
54
|
-
"imports": [
|
|
55
|
-
"pptx"
|
|
56
|
-
],
|
|
57
|
-
"pypi": [
|
|
58
|
-
"xlsxwriter-3.2.9-py3-none-any.whl",
|
|
59
|
-
"python_pptx-1.0.2-py3-none-any.whl"
|
|
60
|
-
],
|
|
61
|
-
"pyodide": [
|
|
62
|
-
"typing-extensions",
|
|
63
|
-
"pillow",
|
|
64
|
-
"lxml"
|
|
65
|
-
]
|
|
66
|
-
},
|
|
67
|
-
"cryptography": {
|
|
68
|
-
"pypi": [],
|
|
69
|
-
"pyodide": [
|
|
70
|
-
"six",
|
|
71
|
-
"pycparser",
|
|
72
|
-
"cffi",
|
|
73
|
-
"cryptography"
|
|
74
|
-
]
|
|
75
|
-
},
|
|
76
|
-
"pillow": {
|
|
77
|
-
"pypi": [],
|
|
78
|
-
"pyodide": [
|
|
79
|
-
"pillow"
|
|
80
|
-
]
|
|
81
|
-
}
|
|
82
|
-
},
|
|
3
|
+
"packages": {},
|
|
83
4
|
"files": {
|
|
84
5
|
"micropip-0.11.1-py3-none-any.whl": {
|
|
85
6
|
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/micropip-0.11.1-py3-none-any.whl",
|
|
86
7
|
"sha256": "668cd1270f480ac9f93da4a2b4873a252743e4ad3da723d37a7e4c637c4f2314",
|
|
87
8
|
"channel": "pyodide"
|
|
88
|
-
},
|
|
89
|
-
"defusedxml-0.7.1-py2.py3-none-any.whl": {
|
|
90
|
-
"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl",
|
|
91
|
-
"sha256": "a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61",
|
|
92
|
-
"channel": "pypi"
|
|
93
|
-
},
|
|
94
|
-
"fpdf2-2.8.8-py3-none-any.whl": {
|
|
95
|
-
"url": "https://files.pythonhosted.org/packages/f5/be/af012eda9507494f28b99b077423806c43a11573eb6225dd46f19ae2d263/fpdf2-2.8.8-py3-none-any.whl",
|
|
96
|
-
"sha256": "3557a478fc577a929c94aace9666aed4dcc432b5ab6764232e6a59f1ccd75f17",
|
|
97
|
-
"channel": "pypi"
|
|
98
|
-
},
|
|
99
|
-
"pillow-12.2.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl": {
|
|
100
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/pillow-12.2.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl",
|
|
101
|
-
"sha256": "a50d83a8a76d646768e99e93ed5bf365d0b83563fd8b597e77562e75c8f575a9",
|
|
102
|
-
"channel": "pyodide"
|
|
103
|
-
},
|
|
104
|
-
"fonttools-4.62.1-py3-none-any.whl": {
|
|
105
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/fonttools-4.62.1-py3-none-any.whl",
|
|
106
|
-
"sha256": "6d8caa09c191f26c47403499d6cff62f3fb9685b978baa047bf791862bcb298a",
|
|
107
|
-
"channel": "pyodide"
|
|
108
|
-
},
|
|
109
|
-
"pypdf-6.15.0-py3-none-any.whl": {
|
|
110
|
-
"url": "https://files.pythonhosted.org/packages/af/72/ce3067ac31e214a66388159f8462ddb8c13dd00170f24d555a1f1ae8ee91/pypdf-6.15.0-py3-none-any.whl",
|
|
111
|
-
"sha256": "14e001d6504822cb1ca9c7ed9a69bccb320f59b320730f55af804361abe4d5ee",
|
|
112
|
-
"channel": "pypi"
|
|
113
|
-
},
|
|
114
|
-
"et_xmlfile-2.0.0-py3-none-any.whl": {
|
|
115
|
-
"url": "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl",
|
|
116
|
-
"sha256": "7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa",
|
|
117
|
-
"channel": "pypi"
|
|
118
|
-
},
|
|
119
|
-
"openpyxl-3.1.5-py2.py3-none-any.whl": {
|
|
120
|
-
"url": "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl",
|
|
121
|
-
"sha256": "5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2",
|
|
122
|
-
"channel": "pypi"
|
|
123
|
-
},
|
|
124
|
-
"python_docx-1.2.0-py3-none-any.whl": {
|
|
125
|
-
"url": "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl",
|
|
126
|
-
"sha256": "3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7",
|
|
127
|
-
"channel": "pypi"
|
|
128
|
-
},
|
|
129
|
-
"typing_extensions-4.15.0-py3-none-any.whl": {
|
|
130
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/typing_extensions-4.15.0-py3-none-any.whl",
|
|
131
|
-
"sha256": "213fc049fb8bbea5f8369b06c7270cdddd634c2c000f721ce445e22473d66fd5",
|
|
132
|
-
"channel": "pyodide"
|
|
133
|
-
},
|
|
134
|
-
"lxml-6.0.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl": {
|
|
135
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/lxml-6.0.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl",
|
|
136
|
-
"sha256": "f37f82e09f6d7957aa167440db7ef683439cc3ce1befac1d2ca27e35bd7c95d4",
|
|
137
|
-
"channel": "pyodide"
|
|
138
|
-
},
|
|
139
|
-
"xlsxwriter-3.2.9-py3-none-any.whl": {
|
|
140
|
-
"url": "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl",
|
|
141
|
-
"sha256": "9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3",
|
|
142
|
-
"channel": "pypi"
|
|
143
|
-
},
|
|
144
|
-
"python_pptx-1.0.2-py3-none-any.whl": {
|
|
145
|
-
"url": "https://files.pythonhosted.org/packages/d9/4f/00be2196329ebbff56ce564aa94efb0fbc828d00de250b1980de1a34ab49/python_pptx-1.0.2-py3-none-any.whl",
|
|
146
|
-
"sha256": "160838e0b8565a8b1f67947675886e9fea18aa5e795db7ae531606d68e785cba",
|
|
147
|
-
"channel": "pypi"
|
|
148
|
-
},
|
|
149
|
-
"six-1.17.0-py2.py3-none-any.whl": {
|
|
150
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/six-1.17.0-py2.py3-none-any.whl",
|
|
151
|
-
"sha256": "c6681057bd87fdec57e811b8e4007bad38deea284052817fa400d542c6423e2d",
|
|
152
|
-
"channel": "pyodide"
|
|
153
|
-
},
|
|
154
|
-
"pycparser-3.0-py3-none-any.whl": {
|
|
155
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/pycparser-3.0-py3-none-any.whl",
|
|
156
|
-
"sha256": "fab73d094251fa60eef1b744db416f4f1fae95b18741b207870b65aa2f3479ed",
|
|
157
|
-
"channel": "pyodide"
|
|
158
|
-
},
|
|
159
|
-
"cffi-2.0.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl": {
|
|
160
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/cffi-2.0.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl",
|
|
161
|
-
"sha256": "757845812fc8d2c94b0f0fb664d542e7d6e098263fbb5cda3b89dca5d7eff6d3",
|
|
162
|
-
"channel": "pyodide"
|
|
163
|
-
},
|
|
164
|
-
"cryptography-47.0.0-cp314-abi3-pyemscripten_2026_0_wasm32.whl": {
|
|
165
|
-
"url": "https://cdn.jsdelivr.net/pyodide/v314.0.2/full/cryptography-47.0.0-cp314-abi3-pyemscripten_2026_0_wasm32.whl",
|
|
166
|
-
"sha256": "4e0e7e8e47613dd96110c640b15ee525db72a47946b8b06f8bcd0377c403fc5a",
|
|
167
|
-
"channel": "pyodide"
|
|
168
9
|
}
|
|
169
10
|
}
|
|
170
11
|
}
|
|
@@ -20,7 +20,9 @@ import { deniedRootsFor } from '../dist-lib/lib/tools/fs/scope.js'
|
|
|
20
20
|
import { createGrepTool } from '../dist-lib/lib/tools/grep.js'
|
|
21
21
|
import { createHttpRequestTool } from '../dist-lib/lib/tools/http-request.js'
|
|
22
22
|
import { createMcpCallTool } from '../dist-lib/lib/tools/mcp-call.js'
|
|
23
|
+
import { createOfficeTools } from '../dist-lib/lib/tools/office.js'
|
|
23
24
|
import { compileOperationTools } from '../dist-lib/lib/tools/operations/compile.js'
|
|
25
|
+
import { createPdfTool } from '../dist-lib/lib/tools/pdf.js'
|
|
24
26
|
import { createReadFilesTool } from '../dist-lib/lib/tools/read-files.js'
|
|
25
27
|
import { createSkillTool } from '../dist-lib/lib/tools/skill.js'
|
|
26
28
|
import { ensureBundledSkillsDir } from '../dist-lib/lib/tools/skills/bundled-dir.js'
|
|
@@ -132,7 +134,9 @@ export default async function start(ipc, ready) {
|
|
|
132
134
|
createFileGlobTool({ deniedRoots }),
|
|
133
135
|
createGrepTool({ deniedRoots }),
|
|
134
136
|
createCreateDocumentsTool({ deniedRoots }),
|
|
135
|
-
createEditDocumentsTool({ deniedRoots })
|
|
137
|
+
createEditDocumentsTool({ deniedRoots }),
|
|
138
|
+
createPdfTool(),
|
|
139
|
+
...createOfficeTools()
|
|
136
140
|
]
|
|
137
141
|
if (skillCatalog) {
|
|
138
142
|
tools.push(...compileOperationTools(skillCatalog, { httpRequestTool, mcpCallTool }))
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const PPTX_EXTRACT: string;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export const PPTX_EXTRACT = `from pptx import Presentation
|
|
2
|
-
from pptx.enum.shapes import MSO_SHAPE_TYPE
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
def text(shapes):
|
|
6
|
-
for shape in shapes:
|
|
7
|
-
if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
|
|
8
|
-
yield from text(shape.shapes)
|
|
9
|
-
elif shape.has_text_frame:
|
|
10
|
-
if shape.text.strip():
|
|
11
|
-
yield shape.text
|
|
12
|
-
elif shape.has_table:
|
|
13
|
-
for row in shape.table.rows:
|
|
14
|
-
cells = ["" if cell.is_spanned else cell.text.replace("\\n", " ") for cell in row.cells]
|
|
15
|
-
if any(cell.strip() for cell in cells):
|
|
16
|
-
yield " | ".join(cells)
|
|
17
|
-
|
|
18
|
-
with Path("extracted.txt").open("w", encoding="utf-8") as output:
|
|
19
|
-
for number, slide in enumerate(Presentation("input.pptx").slides, 1):
|
|
20
|
-
heading = False
|
|
21
|
-
for block in text(slide.shapes):
|
|
22
|
-
if not heading:
|
|
23
|
-
output.write("Slide " + str(number) + "\\n")
|
|
24
|
-
heading = True
|
|
25
|
-
output.write(block + "\\n")
|
|
26
|
-
`;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { AbortSignal } from 'bare-abort-controller';
|
|
2
|
-
export interface PythonExtractOptions {
|
|
3
|
-
readonly format: string;
|
|
4
|
-
readonly packages: readonly string[];
|
|
5
|
-
readonly source: string;
|
|
6
|
-
readonly signal?: AbortSignal | undefined;
|
|
7
|
-
}
|
|
8
|
-
export declare function extractWithPython(bytes: Uint8Array, fileName: string, { format, packages, source, signal }: PythonExtractOptions): Promise<string>;
|