pi-lean-portal 0.3.2 → 0.3.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/README.md CHANGED
@@ -118,6 +118,15 @@ The toggle state is stored in the conversation's branch history. A fresh
118
118
  conversation starts with the default from `settings.json` (`browserToggle.defaultEnabled`,
119
119
  which defaults to `true`).
120
120
 
121
+ > ⚠️ `browserToggle.defaultEnabled` is still read today but is scheduled to be
122
+ > replaced by the `pi-tool-masking` library's `toolsetDefaults` block in an
123
+ > upcoming release — **that block is not read yet**, so keep the legacy key
124
+ > until the replacement ships. See
125
+ > [Configuration (`settings.json`)](#configuration-settingsjson) for the
126
+ > future shape and how to pre-add it harmlessly. A migration warning fires on
127
+ > session start once the legacy key is present and the web default hasn't yet
128
+ > been mirrored into `toolsetDefaults`.
129
+
121
130
  ---
122
131
 
123
132
  ## All 12 Tools
@@ -606,9 +615,12 @@ a `profile` parameter:
606
615
  }
607
616
  ```
608
617
 
609
- ### `browserToggle.defaultEnabled`
618
+ ### `browserToggle.defaultEnabled` *(deprecated — not yet replaced)*
610
619
 
611
- Whether browser tools are enabled on fresh conversations:
620
+ Whether browser tools are enabled on fresh conversations. **This key is still
621
+ read today and works as shown.** It is *scheduled* to be replaced by the
622
+ `pi-tool-masking` library's `toolsetDefaults` block in an upcoming release —
623
+ **that block is not read yet**, so keep this key until the replacement ships.
612
624
 
613
625
  ```jsonc
614
626
  {
@@ -618,6 +630,34 @@ Whether browser tools are enabled on fresh conversations:
618
630
  }
619
631
  ```
620
632
 
633
+ > ⚠️ **Preparing for the offload.** Settings-based toolset defaults are being
634
+ > offloaded to the `pi-tool-masking` library, which will read a new
635
+ > `toolsetDefaults` block keyed by persist key. **The new block is not read
636
+ > by the current release** — it's harmless to add now and will take effect
637
+ > automatically once the offload ships, at which point the legacy key stops
638
+ > being read. To pre-stage the migration, set both:
639
+ >
640
+ > ```jsonc
641
+ > {
642
+ > "browserToggle": { "defaultEnabled": true },
643
+ > "toolsetDefaults": {
644
+ > "toolset-state:pi-lean-dimension.web": { "enabled": true },
645
+ > "toolset-state:pi-lean-dimension.web-learn": { "enabled": false },
646
+ > "toolset-state:pi-lean-dimension.search": { "enabled": true }
647
+ > }
648
+ > }
649
+ > ```
650
+ >
651
+ > - Keys are the toolsets' `persistKey` values (`toolset-state:<id>`).
652
+ > - Omit a `toolsetDefaults` key to use the toolset's packaged default (`web`
653
+ > and `search` default `true`; `web-learn` defaults `false`).
654
+ > - The `search` key only applies when `pi-lean-search` is installed.
655
+ >
656
+ > Once the offload ships and the legacy read is removed, delete the
657
+ > `browserToggle` block. Until then, a migration warning fires on session
658
+ > start when the legacy key is present and the web default hasn't yet been
659
+ > mirrored into `toolsetDefaults`; mirroring it suppresses the warning.
660
+
621
661
  ### `browser.maxStorageStateSize`
622
662
 
623
663
  Size threshold for profile state warnings (default: 10 MB):
package/browser-toggle.ts CHANGED
@@ -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";
@@ -12,6 +11,25 @@ import {
12
11
  import type { ToolsetSpec } from "pi-tool-masking";
13
12
  import { readMergedSettings } from "./core/shared/settings-reader.js";
14
13
 
14
+ // Focus-mode guard helper. The library's published `DefaultResolutionMode`
15
+ // type is `"exclusion" | "inclusion"` (the allowlist mode is unpublished /
16
+ // ships in pi-tool-masking 1.2.0), so the string cast is load-bearing: an
17
+ // allowlist-capable consumer sharing the `globalThis` module state writes
18
+ // `"allowlist"` into it, and this consumer reads that value back at runtime
19
+ // even though its own bundled type doesn't name the mode. On published
20
+ // versions no caller ever writes `"allowlist"`, so this is a no-op for
21
+ // ordinary users — it only activates when an allowlist-capable
22
+ // pi-tool-masking consumer is in play.
23
+ //
24
+ // Cleanup at the ^1.2.0 bump: once `DefaultResolutionMode` names
25
+ // `"allowlist"`, drop the `as string` cast here and in pi-lean-search's
26
+ // co-activation mirror — the type system can then check the comparison
27
+ // directly and the cast becomes a suppressor of a check it should perform.
28
+ function isFocusHolding(): boolean {
29
+ const mode = getDefaultResolutionMode() as string;
30
+ return mode === "inclusion" || mode === "allowlist";
31
+ }
32
+
15
33
  // ---- Toolset specs -----------------------------------------------
16
34
 
17
35
  const PORTAL_WEB_SPEC: ToolsetSpec = {
@@ -136,10 +154,72 @@ function renderBrowserGlyph(
136
154
  }
137
155
  }
138
156
 
157
+ // ---- Legacy settings migration warning ---------------------------
158
+ //
159
+ // The portal currently seeds the web toolset's fresh-session default from
160
+ // `browserToggle.defaultEnabled` in settings.json. An upcoming pi-tool-masking
161
+ // release takes over settings-based toolset defaults and reads a new
162
+ // `toolsetDefaults` block instead. Warn users who pinned the legacy key so
163
+ // they can migrate before the offload lands and the legacy read is removed.
164
+ //
165
+ // ponytail: warn-only — we still honor the legacy key for backward compat
166
+ // until pi-tool-masking owns the settings tier; then delete this helper and
167
+ // the `browserToggle` read below. Ceiling: a silent default shift for users
168
+ // who ignore the warning; upgrade path is the pi-tool-masking bump.
169
+ const TOOLSET_DEFAULTS_MIGRATION_MSG =
170
+ "⚠️ pi-lean-portal: settings-based toolset defaults are moving to the " +
171
+ "pi-tool-masking library. The `browserToggle.defaultEnabled` key in your " +
172
+ "settings.json will stop being read in an upcoming release. It still works " +
173
+ "today — KEEP it until the replacement ships, and add the new " +
174
+ "`toolsetDefaults` block alongside it so your config is ready (the new " +
175
+ "block is not read yet, but is harmless now and will take effect " +
176
+ "automatically once the offload lands):\n\n" +
177
+ "{\n" +
178
+ ' "browserToggle": { "defaultEnabled": true },\n' +
179
+ ' "toolsetDefaults": {\n' +
180
+ ' "toolset-state:pi-lean-dimension.web": { "enabled": true },\n' +
181
+ ' "toolset-state:pi-lean-dimension.web-learn": { "enabled": true },\n' +
182
+ ' "toolset-state:pi-lean-dimension.search": { "enabled": true }\n' +
183
+ " }\n" +
184
+ "}\n" +
185
+ "(omit a `toolsetDefaults` key to use the toolset's packaged default; the " +
186
+ "`search` key only applies when pi-lean-search is installed). Mirror your " +
187
+ "web default into `toolset-state:pi-lean-dimension.web` to silence this " +
188
+ "warning.";
189
+
190
+ function hasLegacyToolsetDefault(merged: Record<string, unknown>): boolean {
191
+ const seg = merged["browserToggle"];
192
+ if (!seg || typeof seg !== "object" || Array.isArray(seg)) return false;
193
+ return (
194
+ typeof (seg as Record<string, unknown>)["defaultEnabled"] === "boolean"
195
+ );
196
+ }
197
+
198
+ // The new `toolsetDefaults` block the pi-tool-masking offload will read.
199
+ // When the user has already migrated the web toolset's default into it,
200
+ // the warning is redundant even if the legacy `browserToggle.defaultEnabled`
201
+ // key is still sitting on disk — suppress so a migrated settings file stays
202
+ // quiet. Only the web persist key gates this: it's the one the legacy key
203
+ // controlled, so its presence means the user acted on the migration.
204
+ const WEB_TOOLSET_PERSIST_KEY = "toolset-state:pi-lean-dimension.web";
205
+ function hasMigratedToolsetDefault(merged: Record<string, unknown>): boolean {
206
+ const td = merged["toolsetDefaults"];
207
+ if (!td || typeof td !== "object" || Array.isArray(td)) return false;
208
+ const entry = (td as Record<string, unknown>)[WEB_TOOLSET_PERSIST_KEY];
209
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
210
+ return typeof (entry as Record<string, unknown>)["enabled"] === "boolean";
211
+ }
212
+
139
213
  // ---- Toggle initializer ------------------------------------------
140
214
 
141
215
  export default function initBrowserToggle(pi: ExtensionAPI) {
142
216
  const merged = readMergedSettings();
217
+ // Warn only when the legacy key is pinned AND the user hasn't already
218
+ // migrated the web default into `toolsetDefaults`. Once the migrated
219
+ // entry exists, pi-tool-masking will read it directly and the legacy
220
+ // key is dead weight — no need to nag.
221
+ const legacyDefaultPinned =
222
+ hasLegacyToolsetDefault(merged) && !hasMigratedToolsetDefault(merged);
143
223
  const browserToggleSegment = (merged as Record<string, unknown>)[
144
224
  "browserToggle"
145
225
  ] as Record<string, unknown> | undefined;
@@ -180,16 +260,19 @@ export default function initBrowserToggle(pi: ExtensionAPI) {
180
260
  const cmd = args.trim().toLowerCase();
181
261
 
182
262
  // Focus-mode guard (§13.2): refuse actuating subcommands while the
183
- // library holds the line in inclusion mode, so a sibling toggle
184
- // can't write a focus-indistinguishable {enabled} entry. Read-only
185
- // subcommands (status/profile/cookies/bare /web) stay unguarded,
186
- // matching tbox's treatment of its own read-only commands.
187
- if (
188
- ["on", "off", "learn"].includes(cmd) &&
189
- getDefaultResolutionMode() === "inclusion"
190
- ) {
263
+ // library holds the line — either inclusion mode or allowlist focus
264
+ // (an upstream pi-tool-masking consumer). Either way a sibling
265
+ // toggle must not write a focus-indistinguishable {enabled} entry.
266
+ // Read-only subcommands (status/profile/cookies/bare /web) stay
267
+ // unguarded, matching the focus controller's treatment of its own
268
+ // read-only commands.
269
+ if (["on", "off", "learn"].includes(cmd) && isFocusHolding()) {
270
+ const inInclusion =
271
+ (getDefaultResolutionMode() as string) === "inclusion";
191
272
  ctx.ui.notify(
192
- "Another plugin has active inclusion mode — this toolset can't be toggled while inclusion is holding the line. Deactivate it there first.",
273
+ inInclusion
274
+ ? "Another plugin has active inclusion mode — this toolset can't be toggled while inclusion is holding the line. Deactivate it there first."
275
+ : "Focus mode (allowlist) is active — this toolset can't be toggled while focus is holding the line. Exit focus there first.",
193
276
  "warning",
194
277
  );
195
278
  return;
@@ -265,6 +348,11 @@ export default function initBrowserToggle(pi: ExtensionAPI) {
265
348
  restoreProfile(pi, ctx);
266
349
  _lastCtx = ctx;
267
350
  syncCachedState();
351
+ // One-time-per-session migration warning when the legacy
352
+ // `browserToggle.defaultEnabled` pin is still on disk.
353
+ if (legacyDefaultPinned) {
354
+ ctx.ui.notify(TOOLSET_DEFAULTS_MIGRATION_MSG, "warning");
355
+ }
268
356
  });
269
357
 
270
358
  pi.on("session_tree", async (_event, ctx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lean-portal",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
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.0.0",
59
+ "pi-tool-masking": "^1.1.0",
60
60
  "playwright": "^1.60.0",
61
61
  "turndown": "^7.2.0"
62
62
  },