pi-lean-portal 0.6.0 → 0.7.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 CHANGED
@@ -331,8 +331,8 @@ the toolset's packaged default:
331
331
  - Omit a `toolsetDefaults` key to use the toolset's packaged default (`web`
332
332
  and `search` default `true`; `web-learn` defaults `false`).
333
333
  - The `search` key only applies when `pi-lean-search` is installed.
334
- - Pins do not apply in spawned subagent children (see pi-tool-masking
335
- 1.3.0's `piToolMasking.childPolicy` for the opt-out).
334
+ - Pins do not apply in spawned subagent children (see pi-tool-masking's
335
+ `piToolMasking.childPolicy` for the opt-out).
336
336
 
337
337
  ### `browser.maxStorageStateSize`
338
338
 
@@ -1260,7 +1260,7 @@ class PlaywrightBridge:
1260
1260
 
1261
1261
  try:
1262
1262
  locator.click(timeout=5_000) # Focus first
1263
- locator.fill(text)
1263
+ locator.fill(text, timeout=5_000)
1264
1264
 
1265
1265
  result = self._build_interaction_result(task_id, page)
1266
1266
  except Exception as exc:
package/browser-toggle.ts CHANGED
@@ -3,17 +3,26 @@ import type {
3
3
  ExtensionContext,
4
4
  } from "@earendil-works/pi-coding-agent";
5
5
  import { updateFooterStatus, getLastCtx, setLastCtx } from "./tools/utils.js";
6
- import {
7
- defineToolset,
8
- TOOLSET_EVENTS,
9
- getDefaultResolutionMode,
10
- } from "pi-tool-masking";
6
+ import { defineToolset, TOOLSET_EVENTS } from "pi-tool-masking";
11
7
  import type { ToolsetSpec } from "pi-tool-masking";
12
8
 
13
- // Focus-mode guard: refuse actuating subcommands while allowlist focus is
14
- // holding the line (an upstream pi-tool-masking consumer).
15
- function isFocusHolding(): boolean {
16
- return getDefaultResolutionMode() === "allowlist";
9
+ // Catch AllowlistModeError by name, never `instanceof` — the handle may come
10
+ // from a different library copy via the shared registry. Returns true when
11
+ // the toggle ran, false when it was refused (nothing changed).
12
+ function refuseOnAllowlist(ctx: ExtensionContext, toggle: () => unknown): boolean {
13
+ try {
14
+ toggle();
15
+ return true;
16
+ } catch (err) {
17
+ if ((err as { name?: string } | undefined)?.name === "AllowlistModeError") {
18
+ ctx.ui.notify(
19
+ "Focus mode (allowlist) is active — this toolset can't be toggled while focus is holding the line. Exit focus there first.",
20
+ "warning",
21
+ );
22
+ return false;
23
+ }
24
+ throw err;
25
+ }
17
26
  }
18
27
 
19
28
  // ---- Toolset specs -----------------------------------------------
@@ -138,36 +147,38 @@ export default function initBrowserToggle(pi: ExtensionAPI) {
138
147
  handler: async (args, ctx) => {
139
148
  const cmd = args.trim().toLowerCase();
140
149
 
141
- // Focus-mode guard: refuse actuating subcommands while allowlist
142
- // focus holds the line (an upstream pi-tool-masking consumer) —
143
- // a sibling toggle must not write a focus-indistinguishable
144
- // {enabled} entry.
145
- // Read-only subcommands (status/profile/cookies/bare /web) stay
146
- // unguarded, matching the focus controller's treatment of its own
147
- // read-only commands.
148
- if (["on", "off", "learn"].includes(cmd) && isFocusHolding()) {
149
- ctx.ui.notify(
150
- "Focus mode (allowlist) is active — this toolset can't be toggled while focus is holding the line. Exit focus there first.",
151
- "warning",
152
- );
153
- return;
154
- }
155
-
156
150
  if (cmd === "on") {
157
- webToolset.enable(pi);
158
- learnToolset.disable(pi);
151
+ if (
152
+ !refuseOnAllowlist(ctx, () => {
153
+ webToolset.enable(pi, ctx.sessionManager);
154
+ learnToolset.disable(pi, ctx.sessionManager);
155
+ })
156
+ )
157
+ return;
159
158
  ctx.ui.notify(
160
159
  "🌐 Browser tools enabled. /web learn to make web-learn available.",
161
160
  "info",
162
161
  );
163
162
  } else if (cmd === "learn") {
164
- learnToolset.enable(pi); // cascades web on via requires
163
+ if (
164
+ !refuseOnAllowlist(
165
+ ctx,
166
+ () => learnToolset.enable(pi, ctx.sessionManager), // cascades web on via requires
167
+ )
168
+ )
169
+ return;
165
170
  ctx.ui.notify(
166
171
  "📖 web-learn tool is now available. Agent will save/update guides when asked.",
167
172
  "info",
168
173
  );
169
174
  } else if (cmd === "off") {
170
- webToolset.disable(pi); // cascades learn off via requires
175
+ if (
176
+ !refuseOnAllowlist(
177
+ ctx,
178
+ () => webToolset.disable(pi, ctx.sessionManager), // cascades learn off via requires
179
+ )
180
+ )
181
+ return;
171
182
  ctx.ui.notify("🌐 Browser tools disabled. /web on to re-enable.", "info");
172
183
  } else if (cmd === "profile" || cmd.startsWith("profile ")) {
173
184
  const sub = cmd.slice("profile".length).trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lean-portal",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Interactive Playwright web browsing for Pi. Chromium and Firefox built in; author stealth backends on either engine. Snapshots and screenshots cache to disk, saving context. Configurable profiles/cookies. Agents write site guides, auto-matched by domain.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "node-html-parser": "^6.1.0",
58
- "pi-tool-masking": "^1.3.0",
58
+ "pi-tool-masking": "^2.0.1",
59
59
  "playwright": "^1.60.0",
60
60
  "turndown": "^7.2.0"
61
61
  },