pi-lean-dimension 0.2.2 → 0.2.4
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/README.md +3 -3
- package/node_modules/pi-lean-portal/README.md +2 -2
- package/node_modules/pi-lean-portal/__tests__/browser-toggle.test.ts +24 -0
- package/node_modules/pi-lean-portal/__tests__/fetch-backend.test.ts +15 -0
- package/node_modules/pi-lean-portal/backends/chromium-py/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/firefox-py/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/__init__.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/__init__.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bridge.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/playwright_base.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/playwright_base.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/conftest.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_accessibility.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_browser_data.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_playwright_base_quirks.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_py_bridges.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/browser-toggle.ts +8 -3
- package/node_modules/pi-lean-portal/contributed/invisible-py/bridge.py +1 -1
- package/node_modules/pi-lean-portal/core/fetch-backend.ts +2 -8
- package/node_modules/pi-lean-portal/package.json +1 -1
- package/node_modules/pi-lean-search/package.json +1 -1
- package/node_modules/pi-lean-search/web-search-tool.ts +1 -0
- package/package.json +3 -3
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/patch_playwright.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_accessibility.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_browser_data.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_chromium_py_bridge.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_firefox_py_bridge.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_playwright_base_quirks.cpython-313.pyc +0 -0
package/README.md
CHANGED
|
@@ -36,9 +36,9 @@ Pi settings (`~/.pi/agent/settings.json` or `.pi/settings.json`):
|
|
|
36
36
|
|---|---|---|---|
|
|
37
37
|
| **A — Browser** (recommended) | `pi install npm:pi-lean-portal` | 12 browser tools + `/web` command | `npx playwright install chromium firefox` |
|
|
38
38
|
| **B — Full suite** | `pi install npm:pi-lean-dimension` | 13 tools (browser + search) + `/web` | Playwright browsers + SearXNG server |
|
|
39
|
-
| **
|
|
39
|
+
| **C — Search only** | `pi install npm:pi-lean-search` | `web-search` tool only | SearXNG server |
|
|
40
40
|
|
|
41
|
-
Notes the table doesn't
|
|
41
|
+
Notes the table doesn't cover:
|
|
42
42
|
|
|
43
43
|
- **Browser binaries aren't downloaded during `npm install`** (configured via `.npmrc`). The first `browser-navigate` call prompts you to run `npx playwright install chromium firefox` if they're missing.
|
|
44
44
|
- **SearXNG is optional for Mode B.** The browser works immediately without it; `web-search` returns a clear setup message on first call. When you do run it, point the suite at your instance in Pi settings:
|
|
@@ -100,7 +100,7 @@ When search is installed, two independent glyphs appear:
|
|
|
100
100
|
Beyond the `/web` toggle, two surfaces are user-driven rather than hardcoded:
|
|
101
101
|
|
|
102
102
|
- **Navigation guides** — `web-learn` saves site-specific playbooks that auto-match by domain and resurface in later sessions.
|
|
103
|
-
- **Custom browser backends** — if a site blocks the shipped Chromium/Firefox, drop a `bridge.py` subclass into `~/.pi/agent/pi-lean-portal/user-backends/` and drive a patched engine like [Camoufox](https://github.com/daijro/camoufox) yourself. A quirks schema declares how the engine diverges from base Playwright, and `launch` options flow from `settings.json` to the subprocess at runtime. This is user-authored, user-audited code that the extension never auto-downloads
|
|
103
|
+
- **Custom browser backends** — if a site blocks the shipped Chromium/Firefox, drop a `bridge.py` subclass into `~/.pi/agent/pi-lean-portal/user-backends/` and drive a patched engine like [Camoufox](https://github.com/daijro/camoufox) yourself. A quirks schema declares how the engine diverges from base Playwright, and `launch` options flow from `settings.json` to the subprocess at runtime. This is user-authored, user-audited code that the extension never auto-downloads. Most installs never need it; the [portal README](packages/pi-lean-portal/README.md#stealth--custom-browser-backends) and [`contributed/README.md`](packages/pi-lean-portal/contributed/README.md) cover the full flow when you do.
|
|
104
104
|
|
|
105
105
|
---
|
|
106
106
|
|
|
@@ -284,7 +284,7 @@ navigation guidance for specific sites using `web-learn`.
|
|
|
284
284
|
web-learn domain="reddit.com" content="…guidance text…"
|
|
285
285
|
```
|
|
286
286
|
|
|
287
|
-
This creates a `.md` file with YAML frontmatter in
|
|
287
|
+
This creates a `.md` file with YAML frontmatter in `~/.pi/agent/pi-lean-portal/web-guides/`.
|
|
288
288
|
The guide becomes available immediately via `web-guide` and appears in the guide footer on
|
|
289
289
|
future navigations to that domain.
|
|
290
290
|
|
|
@@ -595,7 +595,7 @@ Size threshold for profile state warnings (default: 10 MB):
|
|
|
595
595
|
```jsonc
|
|
596
596
|
{
|
|
597
597
|
"browser": {
|
|
598
|
-
"maxStorageStateSize": 10485760
|
|
598
|
+
"maxStorageStateSize": 10485760
|
|
599
599
|
}
|
|
600
600
|
}
|
|
601
601
|
```
|
|
@@ -381,6 +381,30 @@ describe("applyBrowserState(false) — disable", () => {
|
|
|
381
381
|
expect(calledWith).not.toContain(tool);
|
|
382
382
|
}
|
|
383
383
|
});
|
|
384
|
+
|
|
385
|
+
it("does not re-enable tools that were already inactive", () => {
|
|
386
|
+
// /web off must only remove portal's own tools. Any other tool that
|
|
387
|
+
// was inactive (disabled by a peer toggle, a config default, etc.)
|
|
388
|
+
// must stay inactive — a toggle affects no tools outside its own set.
|
|
389
|
+
// Regression guard: the previous implementation rebuilt the set from
|
|
390
|
+
// getAllTools(), silently re-activating every registered non-browser
|
|
391
|
+
// tool. We now filter from getActiveTools() so peer toggles compose.
|
|
392
|
+
const OTHER_TOOL = { name: "peer-ext-tool", description: "x" };
|
|
393
|
+
const pi = mockPi({
|
|
394
|
+
tools: [...ALL_BROWSER_TOOLS, OTHER_TOOL, ...NON_BROWSER_TOOLS],
|
|
395
|
+
activeTools: [
|
|
396
|
+
...ALL_BROWSER_TOOLS.map((t) => t.name),
|
|
397
|
+
...NON_BROWSER_TOOLS.map((t) => t.name),
|
|
398
|
+
], // OTHER_TOOL intentionally absent (off)
|
|
399
|
+
});
|
|
400
|
+
applyBrowserState(pi, false);
|
|
401
|
+
const setActive = pi.setActiveTools as ReturnType<typeof vi.fn>;
|
|
402
|
+
const calledWith: string[] = setActive.mock.calls[0]![0] as string[];
|
|
403
|
+
expect(calledWith).not.toContain("peer-ext-tool");
|
|
404
|
+
for (const name of ALL_BROWSER_TOOLS.map((t) => t.name)) {
|
|
405
|
+
expect(calledWith).not.toContain(name);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
384
408
|
});
|
|
385
409
|
|
|
386
410
|
// ==================================================================
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
10
11
|
import { webFetch, cleanupFetchTempFiles } from "../core/fetch-backend.js";
|
|
11
12
|
|
|
12
13
|
// ─── Setup / Teardown ────────────────────────────────────────
|
|
@@ -312,6 +313,20 @@ describe("webFetch — content capping", () => {
|
|
|
312
313
|
expect(result.content).toContain("Full content saved to");
|
|
313
314
|
});
|
|
314
315
|
|
|
316
|
+
it("preserves both temp files when two large fetches share a taskId", async () => {
|
|
317
|
+
mockFetch({ body: `<p>${longText(6000)}</p>` });
|
|
318
|
+
const a = await webFetch({ url: "http://example.com/a", taskId: "shared" });
|
|
319
|
+
|
|
320
|
+
mockFetch({ body: `<p>${"B".repeat(6000)}</p>` });
|
|
321
|
+
const b = await webFetch({ url: "http://example.com/b", taskId: "shared" });
|
|
322
|
+
|
|
323
|
+
expect(a.filePath).toBeTruthy();
|
|
324
|
+
expect(b.filePath).toBeTruthy();
|
|
325
|
+
expect(a.filePath).not.toBe(b.filePath);
|
|
326
|
+
expect(existsSync(a.filePath!)).toBe(true);
|
|
327
|
+
expect(existsSync(b.filePath!)).toBe(true);
|
|
328
|
+
});
|
|
329
|
+
|
|
315
330
|
it("reports totalChars even for small content", async () => {
|
|
316
331
|
mockFetch({ body: "<p>Hello</p>" });
|
|
317
332
|
const result = await webFetch({ url: "http://example.com/small" });
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -142,9 +142,14 @@ function applyBrowserState(pi: ExtensionAPI, enable: boolean): void {
|
|
|
142
142
|
const current = pi.getActiveTools();
|
|
143
143
|
pi.setActiveTools([...new Set([...current, ...registered])]);
|
|
144
144
|
} else {
|
|
145
|
-
// Keep everything that is NOT a browser+sibling tool
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
// Keep everything that is NOT a browser+sibling tool — but only
|
|
146
|
+
// within the *currently active* set. Using getActiveTools() (not
|
|
147
|
+
// getAllTools()) is critical for peer-toggle composition: /web off
|
|
148
|
+
// must not re-enable tools that another toggle (e.g. host's /api off)
|
|
149
|
+
// has already disabled. getAllTools() would silently re-activate
|
|
150
|
+
// every registered tool outside our own set.
|
|
151
|
+
const current = pi.getActiveTools();
|
|
152
|
+
pi.setActiveTools(current.filter((name) => !registered.has(name)));
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
@@ -85,7 +85,7 @@ import time
|
|
|
85
85
|
from typing import Any
|
|
86
86
|
|
|
87
87
|
from pi_browser_bridge.playwright_base import PlaywrightBridge
|
|
88
|
-
from pi_browser_bridge.
|
|
88
|
+
from pi_browser_bridge.playwright_base import SessionNotFoundError
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
class InvisiblePyBridge(PlaywrightBridge):
|
|
@@ -250,14 +250,8 @@ function writeFetchTempFile(content: string, taskId: string): string {
|
|
|
250
250
|
|
|
251
251
|
function trackFetchFile(taskId: string, filePath: string): void {
|
|
252
252
|
const existing = activeFetchFiles.get(taskId) ?? [];
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
rmSync(oldPath, { force: true });
|
|
256
|
-
} catch {
|
|
257
|
-
/* best-effort */
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
activeFetchFiles.set(taskId, [filePath]);
|
|
253
|
+
if (!existing.includes(filePath)) existing.push(filePath);
|
|
254
|
+
activeFetchFiles.set(taskId, existing);
|
|
261
255
|
}
|
|
262
256
|
|
|
263
257
|
interface CappedFetchContent {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lean-portal",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Pi extension. Interactive web browsing for Pi — a /web toggle removes the tools from context when switched off, Playwright Chromium/Firefox deliver accessibility-tree snapshots, persistent profiles, cookies, and domain-matched guides; custom/stealth backends (Camoufox) plug in when a site blocks the shipped browsers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lean-search",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Pi extension. SearXNG search tool for Pi — pairs with pi-lean-portal's /web toggle; search-only installs are valid, or add it to a portal install for the full web-tools suite.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -247,6 +247,7 @@ export const webSearchTool = defineTool({
|
|
|
247
247
|
'Use when you need recent/current information not already known. Increase `count` for broad research; keep it small for quick lookups. Filter by time_range="day" for breaking news, category="news" for journalism. Set language to match the query (e.g. "de" for German, "es" for Spanish).',
|
|
248
248
|
"Use `pageno` (1-indexed) to fetch deeper pages when `count` results are not enough.",
|
|
249
249
|
"Instant answers (calculator, unit convert, random uuid, hashes, weather, translations) appear above results \u2014 phrase queries like `avg 1 2 3` or `weather berlin` to trigger them.",
|
|
250
|
+
'Target results precisely: prefix the query with a bang to route to a specific source \u2014 `!wp <term>` (Wikipedia), `!images <term>`, `!map <term>`, or `:<lang> !<bang> <term>` (e.g. `:fr !wp paris`). Use the `engines` param to restrict upstreams (e.g. engines="google,bing"). For site-scoped queries put the operator inside `query` \u2014 `site:github.com foo`, `inurl:`, `intitle:`, `filetype:pdf` \u2014 but note these only work with engines that support them (Google, Bing, DuckDuckGo) and are silently ignored by others.',
|
|
250
251
|
],
|
|
251
252
|
|
|
252
253
|
parameters: Type.Object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lean-dimension",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Pi extension. The full Pi web-tools suite in one install — interactive browsing (pi-lean-portal) plus SearXNG search (pi-lean-search), unified under a /web toggle that removes the tools from context when switched off.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
]
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"pi-lean-portal": "^0.2.
|
|
36
|
-
"pi-lean-search": "^0.2.
|
|
35
|
+
"pi-lean-portal": "^0.2.4",
|
|
36
|
+
"pi-lean-search": "^0.2.4"
|
|
37
37
|
},
|
|
38
38
|
"bundledDependencies": [
|
|
39
39
|
"pi-lean-portal",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|