@larkup/tool-doc-editor 0.2.15 → 0.2.16
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/dist/editor.js +13 -29
- package/dist/parsers.js +0 -22
- package/dist/sandbox-scripts.js +0 -21
- package/dist/types.js +0 -3
- package/package.json +6 -6
- package/src/editor.ts +14 -38
- package/src/parsers.ts +0 -29
- package/src/sandbox-scripts.ts +0 -28
- package/src/types.ts +0 -4
- package/tool.manifest.json +19 -4
package/dist/editor.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { PDFDocument, PDFTextField, PDFCheckBox, PDFDropdown, PDFRadioGroup, rgb, StandardFonts, } from 'pdf-lib';
|
|
10
10
|
import { SandboxManager } from '@larkup/sandbox';
|
|
11
|
+
import { readConfig } from '@larkup/core/config-store';
|
|
11
12
|
import { parseDocument, enrichPDFWithText } from './parsers.js';
|
|
12
13
|
import { generateFillDOCXScript, generateFillPPTXScript, generateEditDOCXScript, generateEditPPTXScript, generateExtractPDFTextScript, } from './sandbox-scripts.js';
|
|
13
14
|
const sessions = new Map();
|
|
@@ -23,9 +24,6 @@ export function deleteSession(sessionId) {
|
|
|
23
24
|
export function restoreSession(session) {
|
|
24
25
|
sessions.set(session.id, session);
|
|
25
26
|
}
|
|
26
|
-
/* ------------------------------------------------------------------ */
|
|
27
|
-
/* Create session — parse and store document */
|
|
28
|
-
/* ------------------------------------------------------------------ */
|
|
29
27
|
export async function createSession(buffer, fileName, mimeType) {
|
|
30
28
|
// Parse the document
|
|
31
29
|
let parsed = await parseDocument(buffer, fileName, mimeType);
|
|
@@ -80,9 +78,6 @@ export async function createSession(buffer, fileName, mimeType) {
|
|
|
80
78
|
sessions.set(session.id, session);
|
|
81
79
|
return session;
|
|
82
80
|
}
|
|
83
|
-
/* ------------------------------------------------------------------ */
|
|
84
|
-
/* Apply field edits */
|
|
85
|
-
/* ------------------------------------------------------------------ */
|
|
86
81
|
export async function applyFieldEdits(sessionId, edits) {
|
|
87
82
|
const session = sessions.get(sessionId);
|
|
88
83
|
if (!session) {
|
|
@@ -235,9 +230,6 @@ export async function applyFieldEdits(sessionId, edits) {
|
|
|
235
230
|
};
|
|
236
231
|
}
|
|
237
232
|
}
|
|
238
|
-
/* ------------------------------------------------------------------ */
|
|
239
|
-
/* Apply content edits (text-level) */
|
|
240
|
-
/* ------------------------------------------------------------------ */
|
|
241
233
|
export async function applyContentEdits(sessionId, edits) {
|
|
242
234
|
const session = sessions.get(sessionId);
|
|
243
235
|
if (!session) {
|
|
@@ -333,9 +325,6 @@ export async function applyContentEdits(sessionId, edits) {
|
|
|
333
325
|
};
|
|
334
326
|
}
|
|
335
327
|
}
|
|
336
|
-
/* ------------------------------------------------------------------ */
|
|
337
|
-
/* Export the current document */
|
|
338
|
-
/* ------------------------------------------------------------------ */
|
|
339
328
|
export function exportDocument(sessionId) {
|
|
340
329
|
const session = sessions.get(sessionId);
|
|
341
330
|
if (!session)
|
|
@@ -346,9 +335,6 @@ export function exportDocument(sessionId) {
|
|
|
346
335
|
mimeType: session.mimeType,
|
|
347
336
|
};
|
|
348
337
|
}
|
|
349
|
-
/* ------------------------------------------------------------------ */
|
|
350
|
-
/* Native PDF form filling using pdf-lib (no sandbox needed) */
|
|
351
|
-
/* ------------------------------------------------------------------ */
|
|
352
338
|
async function fillPDFNatively(buffer, edits) {
|
|
353
339
|
const pdfDoc = await PDFDocument.load(buffer, { ignoreEncryption: true });
|
|
354
340
|
const form = pdfDoc.getForm();
|
|
@@ -434,9 +420,6 @@ async function fillPDFNatively(buffer, edits) {
|
|
|
434
420
|
const modifiedBytes = await pdfDoc.save();
|
|
435
421
|
return { buffer: Buffer.from(modifiedBytes), matchedFields };
|
|
436
422
|
}
|
|
437
|
-
/* ------------------------------------------------------------------ */
|
|
438
|
-
/* Apply signature using pdf-lib (no sandbox needed) */
|
|
439
|
-
/* ------------------------------------------------------------------ */
|
|
440
423
|
export async function applySignature(sessionId, data) {
|
|
441
424
|
const session = sessions.get(sessionId);
|
|
442
425
|
if (!session) {
|
|
@@ -567,9 +550,6 @@ export async function applySignature(sessionId, data) {
|
|
|
567
550
|
return { success: false, error: err.message || 'Failed to apply signature' };
|
|
568
551
|
}
|
|
569
552
|
}
|
|
570
|
-
/* ------------------------------------------------------------------ */
|
|
571
|
-
/* Find text position on a PDF page using sandbox PyPDF */
|
|
572
|
-
/* ------------------------------------------------------------------ */
|
|
573
553
|
async function findTextPositionOnPage(pdfBuffer, pageIndex, searchText) {
|
|
574
554
|
try {
|
|
575
555
|
const code = `
|
|
@@ -618,7 +598,12 @@ except Exception as e:
|
|
|
618
598
|
print("__RESULT__:null")
|
|
619
599
|
print(f"Error: {e}", file=sys.stderr)
|
|
620
600
|
`;
|
|
621
|
-
const
|
|
601
|
+
const config = await readConfig();
|
|
602
|
+
const backend = config.defaultSandboxProvider || 'local';
|
|
603
|
+
const sandboxManager = new SandboxManager({
|
|
604
|
+
backend,
|
|
605
|
+
credentials: config.sandboxProviderConfigs?.[backend],
|
|
606
|
+
});
|
|
622
607
|
const result = await sandboxManager.execute({
|
|
623
608
|
code,
|
|
624
609
|
language: 'python',
|
|
@@ -646,11 +631,13 @@ except Exception as e:
|
|
|
646
631
|
}
|
|
647
632
|
return null;
|
|
648
633
|
}
|
|
649
|
-
/* ------------------------------------------------------------------ */
|
|
650
|
-
/* Sandbox execution helper */
|
|
651
|
-
/* ------------------------------------------------------------------ */
|
|
652
634
|
async function runSandboxScript(code, fileBuffer, inputFileName) {
|
|
653
|
-
const
|
|
635
|
+
const config = await readConfig();
|
|
636
|
+
const backend = config.defaultSandboxProvider || 'local';
|
|
637
|
+
const sandboxManager = new SandboxManager({
|
|
638
|
+
backend,
|
|
639
|
+
credentials: config.sandboxProviderConfigs?.[backend],
|
|
640
|
+
});
|
|
654
641
|
const result = await sandboxManager.execute({
|
|
655
642
|
code,
|
|
656
643
|
language: 'python',
|
|
@@ -674,9 +661,6 @@ async function runSandboxScript(code, fileBuffer, inputFileName) {
|
|
|
674
661
|
})),
|
|
675
662
|
};
|
|
676
663
|
}
|
|
677
|
-
/* ------------------------------------------------------------------ */
|
|
678
|
-
/* Helpers */
|
|
679
|
-
/* ------------------------------------------------------------------ */
|
|
680
664
|
function escapeRegExp(string) {
|
|
681
665
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
682
666
|
}
|
package/dist/parsers.js
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
import { PDFDocument, PDFTextField, PDFCheckBox, PDFDropdown, PDFRadioGroup } from 'pdf-lib';
|
|
5
5
|
import mammoth from 'mammoth';
|
|
6
6
|
import { randomUUID } from 'node:crypto';
|
|
7
|
-
/* ------------------------------------------------------------------ */
|
|
8
|
-
/* Detect document type from MIME / extension */
|
|
9
|
-
/* ------------------------------------------------------------------ */
|
|
10
7
|
const MIME_MAP = {
|
|
11
8
|
'application/pdf': 'pdf',
|
|
12
9
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
@@ -27,9 +24,6 @@ export function detectDocumentType(fileName, mimeType) {
|
|
|
27
24
|
const ext = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
|
|
28
25
|
return EXT_MAP[ext] ?? null;
|
|
29
26
|
}
|
|
30
|
-
/* ------------------------------------------------------------------ */
|
|
31
|
-
/* PDF Parser — using pdf-lib (MIT) */
|
|
32
|
-
/* ------------------------------------------------------------------ */
|
|
33
27
|
export async function parsePDF(buffer, fileName) {
|
|
34
28
|
const sessionId = randomUUID();
|
|
35
29
|
const pdfDoc = await PDFDocument.load(buffer, { ignoreEncryption: true });
|
|
@@ -157,9 +151,6 @@ export function enrichPDFWithText(parsed, extractedText) {
|
|
|
157
151
|
rawText: extractedText,
|
|
158
152
|
};
|
|
159
153
|
}
|
|
160
|
-
/* ------------------------------------------------------------------ */
|
|
161
|
-
/* DOCX Parser — using mammoth (MIT) */
|
|
162
|
-
/* ------------------------------------------------------------------ */
|
|
163
154
|
export async function parseDOCX(buffer, fileName) {
|
|
164
155
|
const sessionId = randomUUID();
|
|
165
156
|
// Extract HTML (for preview rendering)
|
|
@@ -192,10 +183,6 @@ export async function parseDOCX(buffer, fileName) {
|
|
|
192
183
|
totalPages: 1,
|
|
193
184
|
};
|
|
194
185
|
}
|
|
195
|
-
/* ------------------------------------------------------------------ */
|
|
196
|
-
/* PPTX Parser — uses sandbox python-pptx for real parsing */
|
|
197
|
-
/* Fallback: JSZip to extract basic slide text */
|
|
198
|
-
/* ------------------------------------------------------------------ */
|
|
199
186
|
export async function parsePPTX(buffer, fileName) {
|
|
200
187
|
const sessionId = randomUUID();
|
|
201
188
|
// Basic extraction using JSZip (already in web app deps)
|
|
@@ -249,9 +236,6 @@ export async function parsePPTX(buffer, fileName) {
|
|
|
249
236
|
};
|
|
250
237
|
}
|
|
251
238
|
}
|
|
252
|
-
/* ------------------------------------------------------------------ */
|
|
253
|
-
/* TXT Parser — native passthrough */
|
|
254
|
-
/* ------------------------------------------------------------------ */
|
|
255
239
|
export async function parseTXT(buffer, fileName) {
|
|
256
240
|
const sessionId = randomUUID();
|
|
257
241
|
const rawText = buffer.toString('utf-8');
|
|
@@ -275,9 +259,6 @@ export async function parseTXT(buffer, fileName) {
|
|
|
275
259
|
totalPages: 1,
|
|
276
260
|
};
|
|
277
261
|
}
|
|
278
|
-
/* ------------------------------------------------------------------ */
|
|
279
|
-
/* Unified parser */
|
|
280
|
-
/* ------------------------------------------------------------------ */
|
|
281
262
|
export async function parseDocument(buffer, fileName, mimeType) {
|
|
282
263
|
const type = detectDocumentType(fileName, mimeType);
|
|
283
264
|
if (!type) {
|
|
@@ -308,9 +289,6 @@ export async function parseDocument(buffer, fileName, mimeType) {
|
|
|
308
289
|
};
|
|
309
290
|
}
|
|
310
291
|
}
|
|
311
|
-
/* ------------------------------------------------------------------ */
|
|
312
|
-
/* Heuristic form field detection from unstructured text */
|
|
313
|
-
/* ------------------------------------------------------------------ */
|
|
314
292
|
/**
|
|
315
293
|
* Detects form-like patterns in text:
|
|
316
294
|
* - "Name: ___________"
|
package/dist/sandbox-scripts.js
CHANGED
|
@@ -9,9 +9,6 @@
|
|
|
9
9
|
*
|
|
10
10
|
* All scripts expect input files in /sandbox/input/ and output to /sandbox/output/
|
|
11
11
|
*/
|
|
12
|
-
/* ------------------------------------------------------------------ */
|
|
13
|
-
/* PDF — Fill form fields using pypdf */
|
|
14
|
-
/* ------------------------------------------------------------------ */
|
|
15
12
|
export function generateFillPDFScript(edits) {
|
|
16
13
|
const editsJson = JSON.stringify(edits);
|
|
17
14
|
return `
|
|
@@ -60,9 +57,6 @@ with open("/sandbox/output/document.pdf", "wb") as f:
|
|
|
60
57
|
print(f"SUCCESS: Updated {len(field_map)} fields")
|
|
61
58
|
`;
|
|
62
59
|
}
|
|
63
|
-
/* ------------------------------------------------------------------ */
|
|
64
|
-
/* PDF — Extract full text using pypdf */
|
|
65
|
-
/* ------------------------------------------------------------------ */
|
|
66
60
|
export function generateExtractPDFTextScript() {
|
|
67
61
|
return `
|
|
68
62
|
import json
|
|
@@ -116,9 +110,6 @@ result = {
|
|
|
116
110
|
print("__RESULT__:" + json.dumps(result, default=str))
|
|
117
111
|
`;
|
|
118
112
|
}
|
|
119
|
-
/* ------------------------------------------------------------------ */
|
|
120
|
-
/* DOCX — Edit content using python-docx */
|
|
121
|
-
/* ------------------------------------------------------------------ */
|
|
122
113
|
export function generateEditDOCXScript(edits) {
|
|
123
114
|
const editsJson = JSON.stringify(edits);
|
|
124
115
|
return `
|
|
@@ -181,9 +172,6 @@ doc.save("/sandbox/output/document.docx")
|
|
|
181
172
|
print(f"SUCCESS: Applied {updated} edits")
|
|
182
173
|
`;
|
|
183
174
|
}
|
|
184
|
-
/* ------------------------------------------------------------------ */
|
|
185
|
-
/* DOCX — Fill form fields (content controls / placeholder text) */
|
|
186
|
-
/* ------------------------------------------------------------------ */
|
|
187
175
|
export function generateFillDOCXScript(edits) {
|
|
188
176
|
const editsJson = JSON.stringify(edits);
|
|
189
177
|
return `
|
|
@@ -233,9 +221,6 @@ doc.save("/sandbox/output/document.docx")
|
|
|
233
221
|
print(f"SUCCESS: Filled {updated} fields")
|
|
234
222
|
`;
|
|
235
223
|
}
|
|
236
|
-
/* ------------------------------------------------------------------ */
|
|
237
|
-
/* PPTX — Extract text from slides */
|
|
238
|
-
/* ------------------------------------------------------------------ */
|
|
239
224
|
export function generateExtractPPTXScript() {
|
|
240
225
|
return `
|
|
241
226
|
import json
|
|
@@ -288,9 +273,6 @@ result = {
|
|
|
288
273
|
print("__RESULT__:" + json.dumps(result, default=str))
|
|
289
274
|
`;
|
|
290
275
|
}
|
|
291
|
-
/* ------------------------------------------------------------------ */
|
|
292
|
-
/* PPTX — Edit slide text */
|
|
293
|
-
/* ------------------------------------------------------------------ */
|
|
294
276
|
export function generateEditPPTXScript(edits) {
|
|
295
277
|
const editsJson = JSON.stringify(edits);
|
|
296
278
|
return `
|
|
@@ -325,9 +307,6 @@ prs.save("/sandbox/output/document.pptx")
|
|
|
325
307
|
print(f"SUCCESS: Applied {updated} edits")
|
|
326
308
|
`;
|
|
327
309
|
}
|
|
328
|
-
/* ------------------------------------------------------------------ */
|
|
329
|
-
/* PPTX — Fill form fields in slides */
|
|
330
|
-
/* ------------------------------------------------------------------ */
|
|
331
310
|
export function generateFillPPTXScript(edits) {
|
|
332
311
|
const editsJson = JSON.stringify(edits);
|
|
333
312
|
return `
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@larkup/tool-doc-editor",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"jszip": "^3.10.1",
|
|
41
41
|
"mammoth": "^1.12.0",
|
|
42
42
|
"pdf-lib": "^1.17.1",
|
|
43
|
-
"@larkup/core": "0.
|
|
44
|
-
"@larkup/sandbox": "0.1.
|
|
43
|
+
"@larkup/core": "0.5.0",
|
|
44
|
+
"@larkup/sandbox": "0.1.3"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@larkup/marketplace": ">=0.1.0"
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"typescript": "^
|
|
56
|
-
"@larkup/marketplace": "0.
|
|
55
|
+
"typescript": "^7.0.2",
|
|
56
|
+
"@larkup/marketplace": "0.2.0"
|
|
57
57
|
},
|
|
58
58
|
"license": "Apache-2.0",
|
|
59
59
|
"repository": {
|
|
60
60
|
"type": "git",
|
|
61
61
|
"url": "https://github.com/Larkup-AI/larkup",
|
|
62
|
-
"directory": "packages/tools/doc-editor"
|
|
62
|
+
"directory": "packages/marketplace-tools/doc-editor"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"build": "tsc --outDir dist",
|
package/src/editor.ts
CHANGED
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
StandardFonts,
|
|
18
18
|
} from 'pdf-lib';
|
|
19
19
|
import { SandboxManager } from '@larkup/sandbox';
|
|
20
|
+
import { readConfig } from '@larkup/core/config-store';
|
|
21
|
+
import type { SandboxBackend } from '@larkup/sandbox';
|
|
20
22
|
import type { EditorSession, FieldEdit, ContentEdit, EditResult, SignatureData } from './types.js';
|
|
21
23
|
import { parseDocument, enrichPDFWithText } from './parsers.js';
|
|
22
24
|
import {
|
|
@@ -47,10 +49,6 @@ export function restoreSession(session: EditorSession): void {
|
|
|
47
49
|
sessions.set(session.id, session);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
/* ------------------------------------------------------------------ */
|
|
51
|
-
/* Create session — parse and store document */
|
|
52
|
-
/* ------------------------------------------------------------------ */
|
|
53
|
-
|
|
54
52
|
export async function createSession(
|
|
55
53
|
buffer: Buffer,
|
|
56
54
|
fileName: string,
|
|
@@ -118,10 +116,6 @@ export async function createSession(
|
|
|
118
116
|
return session;
|
|
119
117
|
}
|
|
120
118
|
|
|
121
|
-
/* ------------------------------------------------------------------ */
|
|
122
|
-
/* Apply field edits */
|
|
123
|
-
/* ------------------------------------------------------------------ */
|
|
124
|
-
|
|
125
119
|
export async function applyFieldEdits(sessionId: string, edits: FieldEdit[]): Promise<EditResult> {
|
|
126
120
|
const session = sessions.get(sessionId);
|
|
127
121
|
if (!session) {
|
|
@@ -304,10 +298,6 @@ export async function applyFieldEdits(sessionId: string, edits: FieldEdit[]): Pr
|
|
|
304
298
|
}
|
|
305
299
|
}
|
|
306
300
|
|
|
307
|
-
/* ------------------------------------------------------------------ */
|
|
308
|
-
/* Apply content edits (text-level) */
|
|
309
|
-
/* ------------------------------------------------------------------ */
|
|
310
|
-
|
|
311
301
|
export async function applyContentEdits(
|
|
312
302
|
sessionId: string,
|
|
313
303
|
edits: ContentEdit[],
|
|
@@ -418,10 +408,6 @@ export async function applyContentEdits(
|
|
|
418
408
|
}
|
|
419
409
|
}
|
|
420
410
|
|
|
421
|
-
/* ------------------------------------------------------------------ */
|
|
422
|
-
/* Export the current document */
|
|
423
|
-
/* ------------------------------------------------------------------ */
|
|
424
|
-
|
|
425
411
|
export function exportDocument(
|
|
426
412
|
sessionId: string,
|
|
427
413
|
): { buffer: Buffer; fileName: string; mimeType: string } | null {
|
|
@@ -435,10 +421,6 @@ export function exportDocument(
|
|
|
435
421
|
};
|
|
436
422
|
}
|
|
437
423
|
|
|
438
|
-
/* ------------------------------------------------------------------ */
|
|
439
|
-
/* Native PDF form filling using pdf-lib (no sandbox needed) */
|
|
440
|
-
/* ------------------------------------------------------------------ */
|
|
441
|
-
|
|
442
424
|
async function fillPDFNatively(
|
|
443
425
|
buffer: Buffer,
|
|
444
426
|
edits: FieldEdit[],
|
|
@@ -539,10 +521,6 @@ async function fillPDFNatively(
|
|
|
539
521
|
return { buffer: Buffer.from(modifiedBytes), matchedFields };
|
|
540
522
|
}
|
|
541
523
|
|
|
542
|
-
/* ------------------------------------------------------------------ */
|
|
543
|
-
/* Apply signature using pdf-lib (no sandbox needed) */
|
|
544
|
-
/* ------------------------------------------------------------------ */
|
|
545
|
-
|
|
546
524
|
export async function applySignature(sessionId: string, data: SignatureData): Promise<EditResult> {
|
|
547
525
|
const session = sessions.get(sessionId);
|
|
548
526
|
if (!session) {
|
|
@@ -689,10 +667,6 @@ export async function applySignature(sessionId: string, data: SignatureData): Pr
|
|
|
689
667
|
}
|
|
690
668
|
}
|
|
691
669
|
|
|
692
|
-
/* ------------------------------------------------------------------ */
|
|
693
|
-
/* Find text position on a PDF page using sandbox PyPDF */
|
|
694
|
-
/* ------------------------------------------------------------------ */
|
|
695
|
-
|
|
696
670
|
async function findTextPositionOnPage(
|
|
697
671
|
pdfBuffer: Buffer,
|
|
698
672
|
pageIndex: number,
|
|
@@ -746,7 +720,12 @@ except Exception as e:
|
|
|
746
720
|
print(f"Error: {e}", file=sys.stderr)
|
|
747
721
|
`;
|
|
748
722
|
|
|
749
|
-
const
|
|
723
|
+
const config = await readConfig();
|
|
724
|
+
const backend = (config.defaultSandboxProvider as SandboxBackend) || 'local';
|
|
725
|
+
const sandboxManager = new SandboxManager({
|
|
726
|
+
backend,
|
|
727
|
+
credentials: config.sandboxProviderConfigs?.[backend],
|
|
728
|
+
});
|
|
750
729
|
const result = await sandboxManager.execute({
|
|
751
730
|
code,
|
|
752
731
|
language: 'python',
|
|
@@ -776,10 +755,6 @@ except Exception as e:
|
|
|
776
755
|
return null;
|
|
777
756
|
}
|
|
778
757
|
|
|
779
|
-
/* ------------------------------------------------------------------ */
|
|
780
|
-
/* Sandbox execution helper */
|
|
781
|
-
/* ------------------------------------------------------------------ */
|
|
782
|
-
|
|
783
758
|
async function runSandboxScript(
|
|
784
759
|
code: string,
|
|
785
760
|
fileBuffer: Buffer,
|
|
@@ -790,7 +765,12 @@ async function runSandboxScript(
|
|
|
790
765
|
exitCode: number;
|
|
791
766
|
artifacts: { name: string; mimeType: string; data: string }[];
|
|
792
767
|
}> {
|
|
793
|
-
const
|
|
768
|
+
const config = await readConfig();
|
|
769
|
+
const backend = (config.defaultSandboxProvider as SandboxBackend) || 'local';
|
|
770
|
+
const sandboxManager = new SandboxManager({
|
|
771
|
+
backend,
|
|
772
|
+
credentials: config.sandboxProviderConfigs?.[backend],
|
|
773
|
+
});
|
|
794
774
|
|
|
795
775
|
const result = await sandboxManager.execute({
|
|
796
776
|
code,
|
|
@@ -817,10 +797,6 @@ async function runSandboxScript(
|
|
|
817
797
|
};
|
|
818
798
|
}
|
|
819
799
|
|
|
820
|
-
/* ------------------------------------------------------------------ */
|
|
821
|
-
/* Helpers */
|
|
822
|
-
/* ------------------------------------------------------------------ */
|
|
823
|
-
|
|
824
800
|
function escapeRegExp(string: string): string {
|
|
825
801
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
826
802
|
}
|
package/src/parsers.ts
CHANGED
|
@@ -7,10 +7,6 @@ import mammoth from 'mammoth';
|
|
|
7
7
|
import { randomUUID } from 'node:crypto';
|
|
8
8
|
import type { DocumentType, DocumentField, DocumentPage, ParsedDocument } from './types.js';
|
|
9
9
|
|
|
10
|
-
/* ------------------------------------------------------------------ */
|
|
11
|
-
/* Detect document type from MIME / extension */
|
|
12
|
-
/* ------------------------------------------------------------------ */
|
|
13
|
-
|
|
14
10
|
const MIME_MAP: Record<string, DocumentType> = {
|
|
15
11
|
'application/pdf': 'pdf',
|
|
16
12
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
@@ -33,10 +29,6 @@ export function detectDocumentType(fileName: string, mimeType?: string): Documen
|
|
|
33
29
|
return EXT_MAP[ext] ?? null;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
/* ------------------------------------------------------------------ */
|
|
37
|
-
/* PDF Parser — using pdf-lib (MIT) */
|
|
38
|
-
/* ------------------------------------------------------------------ */
|
|
39
|
-
|
|
40
32
|
export async function parsePDF(buffer: Buffer, fileName: string): Promise<ParsedDocument> {
|
|
41
33
|
const sessionId = randomUUID();
|
|
42
34
|
const pdfDoc = await PDFDocument.load(buffer, { ignoreEncryption: true });
|
|
@@ -176,10 +168,6 @@ export function enrichPDFWithText(parsed: ParsedDocument, extractedText: string)
|
|
|
176
168
|
};
|
|
177
169
|
}
|
|
178
170
|
|
|
179
|
-
/* ------------------------------------------------------------------ */
|
|
180
|
-
/* DOCX Parser — using mammoth (MIT) */
|
|
181
|
-
/* ------------------------------------------------------------------ */
|
|
182
|
-
|
|
183
171
|
export async function parseDOCX(buffer: Buffer, fileName: string): Promise<ParsedDocument> {
|
|
184
172
|
const sessionId = randomUUID();
|
|
185
173
|
|
|
@@ -218,11 +206,6 @@ export async function parseDOCX(buffer: Buffer, fileName: string): Promise<Parse
|
|
|
218
206
|
};
|
|
219
207
|
}
|
|
220
208
|
|
|
221
|
-
/* ------------------------------------------------------------------ */
|
|
222
|
-
/* PPTX Parser — uses sandbox python-pptx for real parsing */
|
|
223
|
-
/* Fallback: JSZip to extract basic slide text */
|
|
224
|
-
/* ------------------------------------------------------------------ */
|
|
225
|
-
|
|
226
209
|
export async function parsePPTX(buffer: Buffer, fileName: string): Promise<ParsedDocument> {
|
|
227
210
|
const sessionId = randomUUID();
|
|
228
211
|
|
|
@@ -282,10 +265,6 @@ export async function parsePPTX(buffer: Buffer, fileName: string): Promise<Parse
|
|
|
282
265
|
}
|
|
283
266
|
}
|
|
284
267
|
|
|
285
|
-
/* ------------------------------------------------------------------ */
|
|
286
|
-
/* TXT Parser — native passthrough */
|
|
287
|
-
/* ------------------------------------------------------------------ */
|
|
288
|
-
|
|
289
268
|
export async function parseTXT(buffer: Buffer, fileName: string): Promise<ParsedDocument> {
|
|
290
269
|
const sessionId = randomUUID();
|
|
291
270
|
const rawText = buffer.toString('utf-8');
|
|
@@ -312,10 +291,6 @@ export async function parseTXT(buffer: Buffer, fileName: string): Promise<Parsed
|
|
|
312
291
|
};
|
|
313
292
|
}
|
|
314
293
|
|
|
315
|
-
/* ------------------------------------------------------------------ */
|
|
316
|
-
/* Unified parser */
|
|
317
|
-
/* ------------------------------------------------------------------ */
|
|
318
|
-
|
|
319
294
|
export async function parseDocument(
|
|
320
295
|
buffer: Buffer,
|
|
321
296
|
fileName: string,
|
|
@@ -354,10 +329,6 @@ export async function parseDocument(
|
|
|
354
329
|
}
|
|
355
330
|
}
|
|
356
331
|
|
|
357
|
-
/* ------------------------------------------------------------------ */
|
|
358
|
-
/* Heuristic form field detection from unstructured text */
|
|
359
|
-
/* ------------------------------------------------------------------ */
|
|
360
|
-
|
|
361
332
|
/**
|
|
362
333
|
* Detects form-like patterns in text:
|
|
363
334
|
* - "Name: ___________"
|
package/src/sandbox-scripts.ts
CHANGED
|
@@ -12,10 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
import type { FieldEdit, ContentEdit } from './types.js';
|
|
14
14
|
|
|
15
|
-
/* ------------------------------------------------------------------ */
|
|
16
|
-
/* PDF — Fill form fields using pypdf */
|
|
17
|
-
/* ------------------------------------------------------------------ */
|
|
18
|
-
|
|
19
15
|
export function generateFillPDFScript(edits: FieldEdit[]): string {
|
|
20
16
|
const editsJson = JSON.stringify(edits);
|
|
21
17
|
|
|
@@ -66,10 +62,6 @@ print(f"SUCCESS: Updated {len(field_map)} fields")
|
|
|
66
62
|
`;
|
|
67
63
|
}
|
|
68
64
|
|
|
69
|
-
/* ------------------------------------------------------------------ */
|
|
70
|
-
/* PDF — Extract full text using pypdf */
|
|
71
|
-
/* ------------------------------------------------------------------ */
|
|
72
|
-
|
|
73
65
|
export function generateExtractPDFTextScript(): string {
|
|
74
66
|
return `
|
|
75
67
|
import json
|
|
@@ -124,10 +116,6 @@ print("__RESULT__:" + json.dumps(result, default=str))
|
|
|
124
116
|
`;
|
|
125
117
|
}
|
|
126
118
|
|
|
127
|
-
/* ------------------------------------------------------------------ */
|
|
128
|
-
/* DOCX — Edit content using python-docx */
|
|
129
|
-
/* ------------------------------------------------------------------ */
|
|
130
|
-
|
|
131
119
|
export function generateEditDOCXScript(edits: ContentEdit[]): string {
|
|
132
120
|
const editsJson = JSON.stringify(edits);
|
|
133
121
|
|
|
@@ -192,10 +180,6 @@ print(f"SUCCESS: Applied {updated} edits")
|
|
|
192
180
|
`;
|
|
193
181
|
}
|
|
194
182
|
|
|
195
|
-
/* ------------------------------------------------------------------ */
|
|
196
|
-
/* DOCX — Fill form fields (content controls / placeholder text) */
|
|
197
|
-
/* ------------------------------------------------------------------ */
|
|
198
|
-
|
|
199
183
|
export function generateFillDOCXScript(edits: FieldEdit[]): string {
|
|
200
184
|
const editsJson = JSON.stringify(edits);
|
|
201
185
|
|
|
@@ -247,10 +231,6 @@ print(f"SUCCESS: Filled {updated} fields")
|
|
|
247
231
|
`;
|
|
248
232
|
}
|
|
249
233
|
|
|
250
|
-
/* ------------------------------------------------------------------ */
|
|
251
|
-
/* PPTX — Extract text from slides */
|
|
252
|
-
/* ------------------------------------------------------------------ */
|
|
253
|
-
|
|
254
234
|
export function generateExtractPPTXScript(): string {
|
|
255
235
|
return `
|
|
256
236
|
import json
|
|
@@ -304,10 +284,6 @@ print("__RESULT__:" + json.dumps(result, default=str))
|
|
|
304
284
|
`;
|
|
305
285
|
}
|
|
306
286
|
|
|
307
|
-
/* ------------------------------------------------------------------ */
|
|
308
|
-
/* PPTX — Edit slide text */
|
|
309
|
-
/* ------------------------------------------------------------------ */
|
|
310
|
-
|
|
311
287
|
export function generateEditPPTXScript(edits: ContentEdit[]): string {
|
|
312
288
|
const editsJson = JSON.stringify(edits);
|
|
313
289
|
|
|
@@ -344,10 +320,6 @@ print(f"SUCCESS: Applied {updated} edits")
|
|
|
344
320
|
`;
|
|
345
321
|
}
|
|
346
322
|
|
|
347
|
-
/* ------------------------------------------------------------------ */
|
|
348
|
-
/* PPTX — Fill form fields in slides */
|
|
349
|
-
/* ------------------------------------------------------------------ */
|
|
350
|
-
|
|
351
323
|
export function generateFillPPTXScript(edits: FieldEdit[]): string {
|
|
352
324
|
const editsJson = JSON.stringify(edits);
|
|
353
325
|
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/* ------------------------------------------------------------------ */
|
|
2
|
-
/* Types for the Document Editor / Form Filling tool */
|
|
3
|
-
/* ------------------------------------------------------------------ */
|
|
4
|
-
|
|
5
1
|
/** Supported document types */
|
|
6
2
|
export type DocumentType = 'pdf' | 'docx' | 'pptx' | 'txt' | 'xlsx';
|
|
7
3
|
|
package/tool.manifest.json
CHANGED
|
@@ -5,16 +5,31 @@
|
|
|
5
5
|
"description": "AI-powered form filling and document editing with Canvas-style live preview.",
|
|
6
6
|
"longDescription": "Open PDF, Word, PowerPoint, and text files in a split-view Canvas. AI fills forms using your knowledge base, edits content on request, and previews changes live. Supports PDF form fields (AcroForm), DOCX paragraphs/tables, PPTX slide text, and plain text editing. Uses pdf-lib (native) for PDF and the Docker sandbox for DOCX/PPTX via python-docx/python-pptx.",
|
|
7
7
|
"category": "utility",
|
|
8
|
-
"version": "0.2.
|
|
8
|
+
"version": "0.2.16",
|
|
9
9
|
"pricing": "free",
|
|
10
10
|
"emoji": "📝",
|
|
11
11
|
"icon": "FileEdit",
|
|
12
12
|
"packageName": "@larkup/tool-doc-editor",
|
|
13
13
|
"installSize": "~5 MB",
|
|
14
|
-
"systemDeps": [
|
|
14
|
+
"systemDeps": [
|
|
15
|
+
"docker"
|
|
16
|
+
],
|
|
17
|
+
"requiresSandbox": true,
|
|
15
18
|
"author": "Larkup",
|
|
16
|
-
"capabilities": [
|
|
17
|
-
|
|
19
|
+
"capabilities": [
|
|
20
|
+
"document-editing",
|
|
21
|
+
"form-filling",
|
|
22
|
+
"document-preview"
|
|
23
|
+
],
|
|
24
|
+
"tags": [
|
|
25
|
+
"pdf",
|
|
26
|
+
"docx",
|
|
27
|
+
"pptx",
|
|
28
|
+
"form",
|
|
29
|
+
"canvas",
|
|
30
|
+
"editor",
|
|
31
|
+
"fill"
|
|
32
|
+
],
|
|
18
33
|
"downloads": 0,
|
|
19
34
|
"repositoryUrl": "https://github.com/Larkup-AI/larkup",
|
|
20
35
|
"license": "Apache-2.0",
|