@underactive/pi-topping-web-tools 0.2.2 → 0.2.3
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 +11 -0
- package/package.json +4 -4
- package/src/pdf-extract.ts +8 -8
- package/src/web-browser/index.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.2.3] - 2026-09-20
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Bumped the pinned `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` devDependencies from 0.82.1 to 0.86.0 so `npm run typecheck` matches the 0.86.0 runtime API.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `web_browser`, `pdf_extract`: tool result `details` no longer carry undefined-valued properties, keeping them JSON-compatible as pi 0.86.0's `ToolResultMessage.details` requires. `web_browser` omits `statusCode` for same-document navigations; `pdf_extract` omits `firstPage`/`lastPage` for a zero-page PDF and no longer prints "pages undefined-undefined" in its no-text-layer message.
|
|
14
|
+
- `pdf_extract`: strip `</untrusted-content` fence breaks case-insensitively so mixed-case closing tags cannot bypass sanitization.
|
|
15
|
+
|
|
5
16
|
## [0.2.2] - 2026-09-02
|
|
6
17
|
|
|
7
18
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@underactive/pi-topping-web-tools",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Pi extensions for the web: fetch_markdown (URL to markdown, cached, keyless), pdf_extract (PDF text extraction) and web_browser (headless Playwright automation), sharing a preapproved-host allowlist.",
|
|
5
5
|
"keywords": ["pi-package", "pi-extension"],
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"typebox": "*"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@earendil-works/pi-ai": "0.
|
|
57
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
58
|
-
"@earendil-works/pi-tui": "0.
|
|
56
|
+
"@earendil-works/pi-ai": "0.86.0",
|
|
57
|
+
"@earendil-works/pi-coding-agent": "0.86.0",
|
|
58
|
+
"@earendil-works/pi-tui": "0.86.0",
|
|
59
59
|
"@types/node": "^24.0.0",
|
|
60
60
|
"@types/turndown": "^5.0.5",
|
|
61
61
|
"typebox": "^1.3.3",
|
package/src/pdf-extract.ts
CHANGED
|
@@ -48,10 +48,6 @@ export function clearPdfExtractCache(): void {
|
|
|
48
48
|
|
|
49
49
|
const _activeFetches = new Set<AbortController>();
|
|
50
50
|
|
|
51
|
-
export function _activeFetchCountForTests(): number {
|
|
52
|
-
return _activeFetches.size;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
51
|
export function _cleanup(): void {
|
|
56
52
|
PDF_CACHE.clear();
|
|
57
53
|
for (const controller of _activeFetches) {
|
|
@@ -342,12 +338,14 @@ Usage notes:
|
|
|
342
338
|
.join("\n\n");
|
|
343
339
|
|
|
344
340
|
const hasText = trimmed.some((text) => text.length > 0);
|
|
341
|
+
const range =
|
|
342
|
+
selected.length > 0 ? { firstPage: selected[0], lastPage: selected[selected.length - 1] } : undefined;
|
|
345
343
|
const baseDetails = {
|
|
346
344
|
source,
|
|
347
345
|
totalPages: loaded.totalPages,
|
|
348
346
|
pageCount: selected.length,
|
|
349
|
-
|
|
350
|
-
|
|
347
|
+
// Empty only for a zero-page PDF; omit the keys rather than storing undefined.
|
|
348
|
+
...(range ?? {}),
|
|
351
349
|
bytes: loaded.bytes,
|
|
352
350
|
durationMs: Date.now() - start,
|
|
353
351
|
cached: loaded.cached,
|
|
@@ -358,7 +356,9 @@ Usage notes:
|
|
|
358
356
|
content: [
|
|
359
357
|
{
|
|
360
358
|
type: "text" as const,
|
|
361
|
-
text: `No extractable text layer found in ${source}
|
|
359
|
+
text: `No extractable text layer found in ${source}${
|
|
360
|
+
range ? ` (pages ${range.firstPage}-${range.lastPage} of ${loaded.totalPages})` : ` (0 of ${loaded.totalPages} page(s))`
|
|
361
|
+
}. The PDF is likely scanned or image-only. This tool does not perform OCR.`,
|
|
362
362
|
},
|
|
363
363
|
],
|
|
364
364
|
details: baseDetails satisfies PdfExtractDetails,
|
|
@@ -367,7 +367,7 @@ Usage notes:
|
|
|
367
367
|
|
|
368
368
|
const offset = Math.max(0, Math.floor(params.offset ?? 0));
|
|
369
369
|
const slice = sliceContent(body, offset);
|
|
370
|
-
const sanitizedText = slice.text.replaceAll(
|
|
370
|
+
const sanitizedText = slice.text.replaceAll(/<\/untrusted-content/gi, "");
|
|
371
371
|
const safeSource = source.replaceAll('"', "%22");
|
|
372
372
|
|
|
373
373
|
return {
|
package/src/web-browser/index.ts
CHANGED
|
@@ -516,7 +516,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
516
516
|
action,
|
|
517
517
|
url: result.url,
|
|
518
518
|
title: result.title,
|
|
519
|
-
|
|
519
|
+
// A same-document navigation has no response; omit the key rather than storing undefined.
|
|
520
|
+
...(result.statusCode !== undefined ? { statusCode: result.statusCode } : {}),
|
|
520
521
|
bytes: Buffer.byteLength(text),
|
|
521
522
|
} satisfies WebBrowserDetails,
|
|
522
523
|
};
|