pi-lean-dimension 0.3.2 → 0.4.0
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 +18 -3
- package/node_modules/pi-lean-portal/README.md +21 -6
- package/node_modules/pi-lean-portal/__tests__/browser-toggle.test.ts +24 -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/browser-toggle.ts +23 -26
- package/node_modules/pi-lean-portal/package.json +2 -2
- package/node_modules/pi-lean-search/__tests__/web-search.test.ts +22 -3
- package/node_modules/pi-lean-search/index.ts +11 -1
- package/node_modules/pi-lean-search/package.json +2 -2
- package/node_modules/pi-tool-masking/LICENSE +21 -661
- package/node_modules/pi-tool-masking/README.md +104 -14
- package/node_modules/pi-tool-masking/index.ts +767 -43
- package/node_modules/pi-tool-masking/package.json +6 -4
- package/node_modules/playwright/lib/common/index.js +3 -6
- package/node_modules/playwright/lib/common/index.js.txt +2 -2
- package/node_modules/playwright/lib/transform/esmLoader.js +3 -6
- package/node_modules/playwright/lib/transform/esmLoader.js.txt +2 -2
- package/node_modules/playwright/package.json +2 -2
- package/node_modules/playwright-core/lib/coreBundle.js +1 -1
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-By56iMx7.js → codeMirrorModule-rXmQmLUY.js} +1 -1
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-B-dXF5JN.js +181 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/{xtermModule-COQkjINf.js → xtermModule-BuZfJS5v.js} +1 -1
- package/node_modules/playwright-core/lib/vite/traceViewer/{index.Dl36UVQT.js → index.KZ4wOW1K.js} +1 -1
- package/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
- package/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.D962mr9b.js → uiMode.Dzuouizj.js} +2 -2
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
- package/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright-core/types/structs.d.ts +8 -3
- package/package.json +3 -3
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-B34OrIms.js +0 -181
package/README.md
CHANGED
|
@@ -21,13 +21,28 @@ npx playwright install chromium firefox
|
|
|
21
21
|
That's it — the tools are registered and start enabled by default. Control
|
|
22
22
|
them with `/web on|off|learn` (`on` = browser tools, `learn` = browser tools
|
|
23
23
|
plus guide-saving via `web-learn`, `off` = everything off). The state persists
|
|
24
|
-
per session. To set a different default for **new** sessions, add
|
|
25
|
-
Pi settings (`~/.pi/agent/settings.json` or
|
|
24
|
+
per session. To set a different default for **new** sessions, add a
|
|
25
|
+
`toolsetDefaults` block to your Pi settings (`~/.pi/agent/settings.json` or
|
|
26
|
+
`.pi/settings.json`):
|
|
26
27
|
|
|
27
28
|
```json
|
|
28
|
-
{
|
|
29
|
+
{
|
|
30
|
+
"toolsetDefaults": {
|
|
31
|
+
"toolset-state:pi-lean-dimension.web": { "enabled": false },
|
|
32
|
+
"toolset-state:pi-lean-dimension.web-learn": { "enabled": false },
|
|
33
|
+
"toolset-state:pi-lean-dimension.search": { "enabled": false }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
29
36
|
```
|
|
30
37
|
|
|
38
|
+
`toolsetDefaults` is read by the [`pi-tool-masking`](https://github.com/coreyryanhanson/pi-tool-masking/) library on restore, before
|
|
39
|
+
the toolset's packaged default. Omit a key to use the packaged default; the
|
|
40
|
+
`search` key only applies when `pi-lean-search` is installed.
|
|
41
|
+
|
|
42
|
+
> The legacy `browserToggle.defaultEnabled` key is **removed in 0.4.0** and
|
|
43
|
+
> no longer read. If you pinned it, move the value into the matching
|
|
44
|
+
> `toolsetDefaults` entry above.
|
|
45
|
+
|
|
31
46
|
---
|
|
32
47
|
|
|
33
48
|
## Install options
|
|
@@ -115,8 +115,10 @@ toggles guide-saving mode, and manages browser profiles.
|
|
|
115
115
|
### Persistence
|
|
116
116
|
|
|
117
117
|
The toggle state is stored in the conversation's branch history. A fresh
|
|
118
|
-
conversation starts with the default from `settings.json`
|
|
119
|
-
|
|
118
|
+
conversation starts with the default from `settings.json` — the
|
|
119
|
+
`pi-tool-masking` library's `toolsetDefaults` block (see
|
|
120
|
+
[Configuration (`settings.json`)](#configuration-settingsjson)), falling back
|
|
121
|
+
to the toolset's packaged default (`true` for `web`).
|
|
120
122
|
|
|
121
123
|
---
|
|
122
124
|
|
|
@@ -606,18 +608,31 @@ a `profile` parameter:
|
|
|
606
608
|
}
|
|
607
609
|
```
|
|
608
610
|
|
|
609
|
-
### `
|
|
611
|
+
### `toolsetDefaults` *(settings-based toolset defaults)*
|
|
610
612
|
|
|
611
|
-
Whether browser tools are enabled on fresh conversations
|
|
613
|
+
Whether browser tools are enabled on fresh conversations. Read by the
|
|
614
|
+
`pi-tool-masking` library at restore time, between the chat-branch tier and
|
|
615
|
+
the toolset's packaged default:
|
|
612
616
|
|
|
613
617
|
```jsonc
|
|
614
618
|
{
|
|
615
|
-
"
|
|
616
|
-
"
|
|
619
|
+
"toolsetDefaults": {
|
|
620
|
+
"toolset-state:pi-lean-dimension.web": { "enabled": true },
|
|
621
|
+
"toolset-state:pi-lean-dimension.web-learn": { "enabled": false },
|
|
622
|
+
"toolset-state:pi-lean-dimension.search": { "enabled": true }
|
|
617
623
|
}
|
|
618
624
|
}
|
|
619
625
|
```
|
|
620
626
|
|
|
627
|
+
- Keys are the toolsets' `persistKey` values (`toolset-state:<id>`).
|
|
628
|
+
- Omit a `toolsetDefaults` key to use the toolset's packaged default (`web`
|
|
629
|
+
and `search` default `true`; `web-learn` defaults `false`).
|
|
630
|
+
- The `search` key only applies when `pi-lean-search` is installed.
|
|
631
|
+
|
|
632
|
+
> The legacy `browserToggle.defaultEnabled` key is **removed in 0.4.0** — it
|
|
633
|
+
> is no longer read. If you pinned it, move the value into the matching
|
|
634
|
+
> `toolsetDefaults` entry above.
|
|
635
|
+
|
|
621
636
|
### `browser.maxStorageStateSize`
|
|
622
637
|
|
|
623
638
|
Size threshold for profile state warnings (default: 10 MB):
|
|
@@ -371,6 +371,30 @@ describe("/web focus-mode guard", () => {
|
|
|
371
371
|
expect(finalActive).toContain(name);
|
|
372
372
|
}
|
|
373
373
|
});
|
|
374
|
+
|
|
375
|
+
// Allowlist focus (an upstream pi-tool-masking consumer) holds the line
|
|
376
|
+
// the same way inclusion does. The published library type doesn't name
|
|
377
|
+
// "allowlist", so we set the shared module state directly — mirroring what
|
|
378
|
+
// an allowlist-capable consumer's restore writes into globalThis.
|
|
379
|
+
it("refuses /web on/off/learn while allowlist focus is active", async () => {
|
|
380
|
+
const { pi } = mockPi([]);
|
|
381
|
+
browserToggle(pi);
|
|
382
|
+
(globalThis as any)[MODULE_STATE_KEY] = {
|
|
383
|
+
defaultResolutionMode: "allowlist",
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
for (const sub of ["on", "off", "learn"]) {
|
|
387
|
+
(pi.setActiveTools as any).mockClear();
|
|
388
|
+
const ctx = mockCtx();
|
|
389
|
+
await captureWebHandler(pi)(sub, ctx);
|
|
390
|
+
|
|
391
|
+
expect(ctx.ui.notify).toHaveBeenCalledWith(
|
|
392
|
+
expect.stringContaining("Focus mode (allowlist) is active"),
|
|
393
|
+
"warning",
|
|
394
|
+
);
|
|
395
|
+
expect(pi.setActiveTools).not.toHaveBeenCalled();
|
|
396
|
+
}
|
|
397
|
+
});
|
|
374
398
|
});
|
|
375
399
|
|
|
376
400
|
// ==================================================================
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ExtensionAPI,
|
|
3
|
-
ExtensionCommandContext,
|
|
4
3
|
ExtensionContext,
|
|
5
4
|
ThemeColor,
|
|
6
5
|
} from "@earendil-works/pi-coding-agent";
|
|
@@ -10,7 +9,14 @@ import {
|
|
|
10
9
|
getDefaultResolutionMode,
|
|
11
10
|
} from "pi-tool-masking";
|
|
12
11
|
import type { ToolsetSpec } from "pi-tool-masking";
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
// Focus-mode guard: refuse actuating subcommands while the library holds the
|
|
14
|
+
// line — inclusion mode or allowlist focus (an upstream pi-tool-masking
|
|
15
|
+
// consumer).
|
|
16
|
+
function isFocusHolding(): boolean {
|
|
17
|
+
const mode = getDefaultResolutionMode();
|
|
18
|
+
return mode === "inclusion" || mode === "allowlist";
|
|
19
|
+
}
|
|
14
20
|
|
|
15
21
|
// ---- Toolset specs -----------------------------------------------
|
|
16
22
|
|
|
@@ -139,21 +145,10 @@ function renderBrowserGlyph(
|
|
|
139
145
|
// ---- Toggle initializer ------------------------------------------
|
|
140
146
|
|
|
141
147
|
export default function initBrowserToggle(pi: ExtensionAPI) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const webDefault =
|
|
147
|
-
browserToggleSegment &&
|
|
148
|
-
typeof browserToggleSegment["defaultEnabled"] === "boolean"
|
|
149
|
-
? (browserToggleSegment["defaultEnabled"] as boolean)
|
|
150
|
-
: true;
|
|
151
|
-
|
|
152
|
-
const webSpec: ToolsetSpec = {
|
|
153
|
-
...PORTAL_WEB_SPEC,
|
|
154
|
-
defaultEnabled: webDefault,
|
|
155
|
-
};
|
|
156
|
-
const webToolset = defineToolset(pi, webSpec);
|
|
148
|
+
// Settings-based toolset defaults (`toolsetDefaults` tier) are read by
|
|
149
|
+
// pi-tool-masking itself inside defineToolset/restore — pass the packaged
|
|
150
|
+
// spec straight through.
|
|
151
|
+
const webToolset = defineToolset(pi, PORTAL_WEB_SPEC);
|
|
157
152
|
const learnToolset = defineToolset(pi, PORTAL_LEARN_SPEC);
|
|
158
153
|
|
|
159
154
|
// ── Keep cached state in sync with library events ─────────
|
|
@@ -180,16 +175,18 @@ export default function initBrowserToggle(pi: ExtensionAPI) {
|
|
|
180
175
|
const cmd = args.trim().toLowerCase();
|
|
181
176
|
|
|
182
177
|
// Focus-mode guard (§13.2): refuse actuating subcommands while the
|
|
183
|
-
// library holds the line
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
178
|
+
// library holds the line — either inclusion mode or allowlist focus
|
|
179
|
+
// (an upstream pi-tool-masking consumer). Either way a sibling
|
|
180
|
+
// toggle must not write a focus-indistinguishable {enabled} entry.
|
|
181
|
+
// Read-only subcommands (status/profile/cookies/bare /web) stay
|
|
182
|
+
// unguarded, matching the focus controller's treatment of its own
|
|
183
|
+
// read-only commands.
|
|
184
|
+
if (["on", "off", "learn"].includes(cmd) && isFocusHolding()) {
|
|
185
|
+
const inInclusion = getDefaultResolutionMode() === "inclusion";
|
|
191
186
|
ctx.ui.notify(
|
|
192
|
-
|
|
187
|
+
inInclusion
|
|
188
|
+
? "Another plugin has active inclusion mode — this toolset can't be toggled while inclusion is holding the line. Deactivate it there first."
|
|
189
|
+
: "Focus mode (allowlist) is active — this toolset can't be toggled while focus is holding the line. Exit focus there first.",
|
|
193
190
|
"warning",
|
|
194
191
|
);
|
|
195
192
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lean-portal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"node-html-parser": "^6.1.0",
|
|
59
|
-
"pi-tool-masking": "^1.
|
|
59
|
+
"pi-tool-masking": "^1.2.0",
|
|
60
60
|
"playwright": "^1.60.0",
|
|
61
61
|
"turndown": "^7.2.0"
|
|
62
62
|
},
|
|
@@ -80,9 +80,7 @@ describe("readSearxngUrl", () => {
|
|
|
80
80
|
vi.mocked(existsSync).mockImplementation(
|
|
81
81
|
(path) => typeof path === "string" && path.includes(".pi"),
|
|
82
82
|
);
|
|
83
|
-
vi.mocked(readFileSync).mockReturnValue(
|
|
84
|
-
JSON.stringify({ theme: "dark", browserToggle: {} }),
|
|
85
|
-
);
|
|
83
|
+
vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ theme: "dark" }));
|
|
86
84
|
expect(readSearxngUrl()).toBeUndefined();
|
|
87
85
|
});
|
|
88
86
|
|
|
@@ -444,6 +442,7 @@ describe("execute answer rendering", () => {
|
|
|
444
442
|
beforeEach(() => {
|
|
445
443
|
_resetStateForTest();
|
|
446
444
|
delete (globalThis as any)[REGISTRY_KEY];
|
|
445
|
+
delete (globalThis as any)["__piToolMaskingModuleState"];
|
|
447
446
|
});
|
|
448
447
|
|
|
449
448
|
// ==================================================================
|
|
@@ -477,4 +476,24 @@ describe("pi-lean-dimension.web co-activation mirror", () => {
|
|
|
477
476
|
expect.arrayContaining(["web-search"]),
|
|
478
477
|
);
|
|
479
478
|
});
|
|
479
|
+
|
|
480
|
+
// Allowlist focus (an upstream pi-tool-masking consumer) holds the line —
|
|
481
|
+
// the mirror must not co-activate, so a stale library `doRestore` emitting
|
|
482
|
+
// a web `changed` during resume can't disable search or write a {enabled}
|
|
483
|
+
// entry. Set the shared module state directly.
|
|
484
|
+
it("skips co-activation while allowlist focus is active", async () => {
|
|
485
|
+
const { pi, events } = mockSearchPi(["web-search"]);
|
|
486
|
+
searchExtension(pi);
|
|
487
|
+
(globalThis as any)["__piToolMaskingModuleState"] = {
|
|
488
|
+
defaultResolutionMode: "allowlist",
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
(pi.setActiveTools as any).mockClear();
|
|
492
|
+
events.emit(TOOLSET_EVENTS.changed, {
|
|
493
|
+
id: "pi-lean-dimension.web",
|
|
494
|
+
enabled: false,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
expect(pi.setActiveTools).not.toHaveBeenCalled();
|
|
498
|
+
});
|
|
480
499
|
});
|
|
@@ -16,7 +16,11 @@ import type {
|
|
|
16
16
|
ExtensionContext,
|
|
17
17
|
ThemeColor,
|
|
18
18
|
} from "@earendil-works/pi-coding-agent";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
defineToolset,
|
|
21
|
+
TOOLSET_EVENTS,
|
|
22
|
+
getDefaultResolutionMode,
|
|
23
|
+
} from "pi-tool-masking";
|
|
20
24
|
import type { ToolsetSpec, ToolsetChangedEvent } from "pi-tool-masking";
|
|
21
25
|
import { readSearxngUrl } from "./search-config.js";
|
|
22
26
|
import { webSearchTool } from "./web-search-tool.js";
|
|
@@ -199,9 +203,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
199
203
|
|
|
200
204
|
// ── Co-activation: mirror pi-lean-dimension.web changed events ─
|
|
201
205
|
// Listen on changed ONLY, not restored (§10.1).
|
|
206
|
+
//
|
|
207
|
+
// Focus-mode guard: while allowlist focus holds the line, skip
|
|
208
|
+
// co-activation. The focus set is authoritative, so a web `changed` event
|
|
209
|
+
// — including one a stale library `doRestore` emits during resume — must
|
|
210
|
+
// not disable search or write a focus-indistinguishable {enabled} entry.
|
|
202
211
|
pi.events.on(TOOLSET_EVENTS.changed, (data: unknown) => {
|
|
203
212
|
const event = data as ToolsetChangedEvent;
|
|
204
213
|
if (event.id === "pi-lean-dimension.web") {
|
|
214
|
+
if (getDefaultResolutionMode() === "allowlist") return;
|
|
205
215
|
if (event.enabled) {
|
|
206
216
|
searchToolset.enable(pi);
|
|
207
217
|
} else {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lean-search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"test": "vitest run"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"pi-tool-masking": "^1.
|
|
41
|
+
"pi-tool-masking": "^1.2.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@earendil-works/pi-ai": "*",
|