pi-lean-dimension 0.3.0 → 0.3.2

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.
@@ -691,12 +691,10 @@ When creating navigation guides with `web-learn`:
691
691
 
692
692
  ### Security
693
693
 
694
- - URLs are validated against private IP ranges (10.x, 172.16-31.x,
695
- 192.168.x, 127.x, 169.254.169.254) — localhost and internal networks
696
- are blocked by default
697
- - Dangerous URL schemes are blocked: `file:`, `ftp:`, `data:`,
698
- `javascript:`, `vbscript:`
699
- - Secrets in URLs are detected heuristically
694
+ - URLs are parsed with `new URL()` as input validation — malformed
695
+ URLs are rejected, but no SSRF boundary is enforced (a coding agent
696
+ already has filesystem and shell access, so blocking localhost or
697
+ private IPs would be theater)
700
698
  - Profile state is stored with restricted file permissions (0700 dirs,
701
699
  0600 files)
702
700
 
@@ -259,26 +259,26 @@ describe("getToggleState / getLearnState", () => {
259
259
  // appendEntry persist keys
260
260
  // ==================================================================
261
261
  describe("persistence key split", () => {
262
- it("appends toolset-state:portal.web on enable", async () => {
262
+ it("appends toolset-state:pi-lean-dimension.web on enable", async () => {
263
263
  const { pi } = mockPi([]);
264
264
  browserToggle(pi);
265
265
 
266
266
  await captureWebHandler(pi)("on", mockCtx());
267
267
 
268
268
  const webCalls = (pi.appendEntry as any).mock.calls.filter(
269
- (c: any) => c[0] === "toolset-state:portal.web",
269
+ (c: any) => c[0] === "toolset-state:pi-lean-dimension.web",
270
270
  );
271
271
  expect(webCalls.length).toBeGreaterThanOrEqual(1);
272
272
  });
273
273
 
274
- it("appends toolset-state:portal.learn on learn", async () => {
274
+ it("appends toolset-state:pi-lean-dimension.web-learn on learn", async () => {
275
275
  const { pi } = mockPi([]);
276
276
  browserToggle(pi);
277
277
 
278
278
  await captureWebHandler(pi)("learn", mockCtx());
279
279
 
280
280
  const learnCalls = (pi.appendEntry as any).mock.calls.filter(
281
- (c: any) => c[0] === "toolset-state:portal.learn",
281
+ (c: any) => c[0] === "toolset-state:pi-lean-dimension.web-learn",
282
282
  );
283
283
  expect(learnCalls.length).toBeGreaterThanOrEqual(1);
284
284
  });
@@ -377,7 +377,7 @@ describe("/web focus-mode guard", () => {
377
377
  // Glyph sync on external-plugin changed events
378
378
  // ==================================================================
379
379
  describe("external-plugin glyph sync", () => {
380
- it("re-renders browser glyph off when external plugin fires portal.web disabled", async () => {
380
+ it("re-renders browser glyph off when external plugin fires pi-lean-dimension.web disabled", async () => {
381
381
  const { pi, handlers, events } = mockPi();
382
382
  browserToggle(pi);
383
383
 
@@ -391,7 +391,7 @@ describe("external-plugin glyph sync", () => {
391
391
  // Clear the initial render call so we only see the external-plugin re-render.
392
392
  vi.clearAllMocks();
393
393
 
394
- // Simulate an external plugin disabling portal.web — it has
394
+ // Simulate an external plugin disabling pi-lean-dimension.web — it has
395
395
  // already removed browser tools from the active set.
396
396
  const nonBrowser = ALL_TOOLS.map((t) => t.name).filter(
397
397
  (n) => !BROWSER_TOOL_NAMES.has(n),
@@ -399,7 +399,7 @@ describe("external-plugin glyph sync", () => {
399
399
  (pi.getActiveTools as any).mockReturnValue(nonBrowser);
400
400
 
401
401
  events.emit(TOOLSET_EVENTS.changed, {
402
- id: "portal.web",
402
+ id: "pi-lean-dimension.web",
403
403
  enabled: false,
404
404
  });
405
405
 
@@ -15,7 +15,7 @@ import { readMergedSettings } from "./core/shared/settings-reader.js";
15
15
  // ---- Toolset specs -----------------------------------------------
16
16
 
17
17
  const PORTAL_WEB_SPEC: ToolsetSpec = {
18
- id: "portal.web",
18
+ id: "pi-lean-dimension.web",
19
19
  names: new Set([
20
20
  "web-fetch",
21
21
  "browser-navigate",
@@ -29,15 +29,15 @@ const PORTAL_WEB_SPEC: ToolsetSpec = {
29
29
  "browser-inspect",
30
30
  "web-guide",
31
31
  ]),
32
- persistKey: "toolset-state:portal.web",
32
+ persistKey: "toolset-state:pi-lean-dimension.web",
33
33
  };
34
34
 
35
35
  const PORTAL_LEARN_SPEC: ToolsetSpec = {
36
- id: "portal.learn",
36
+ id: "pi-lean-dimension.web-learn",
37
37
  names: new Set(["web-learn"]),
38
- persistKey: "toolset-state:portal.learn",
38
+ persistKey: "toolset-state:pi-lean-dimension.web-learn",
39
39
  defaultEnabled: false,
40
- requires: ["portal.web"],
40
+ requires: ["pi-lean-dimension.web"],
41
41
  };
42
42
 
43
43
  // ---- Status bar cached state (derived from library events) ------
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lean-portal",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
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,6 +56,7 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "node-html-parser": "^6.1.0",
59
+ "pi-tool-masking": "^1.0.0",
59
60
  "playwright": "^1.60.0",
60
61
  "turndown": "^7.2.0"
61
62
  },
@@ -63,7 +64,6 @@
63
64
  "@earendil-works/pi-ai": "*",
64
65
  "@earendil-works/pi-coding-agent": "*",
65
66
  "@earendil-works/pi-tui": "*",
66
- "pi-tool-masking": "^1.0.0",
67
67
  "typebox": "*"
68
68
  }
69
69
  }
@@ -447,15 +447,15 @@ beforeEach(() => {
447
447
  });
448
448
 
449
449
  // ==================================================================
450
- // Toolset wiring: portal.web ↔ search.web co-activation mirror
450
+ // Toolset wiring: pi-lean-dimension.web ↔ pi-lean-dimension.search co-activation mirror
451
451
  // ==================================================================
452
- describe("portal.web co-activation mirror", () => {
453
- it("disables search.web when portal.web changed fires with enabled: false", async () => {
452
+ describe("pi-lean-dimension.web co-activation mirror", () => {
453
+ it("disables pi-lean-dimension.search when pi-lean-dimension.web changed fires with enabled: false", async () => {
454
454
  const { pi, events } = mockSearchPi();
455
455
  searchExtension(pi);
456
456
 
457
457
  events.emit(TOOLSET_EVENTS.changed, {
458
- id: "portal.web",
458
+ id: "pi-lean-dimension.web",
459
459
  enabled: false,
460
460
  });
461
461
 
@@ -464,12 +464,12 @@ describe("portal.web co-activation mirror", () => {
464
464
  );
465
465
  });
466
466
 
467
- it("enables search.web when portal.web changed fires with enabled: true", async () => {
467
+ it("enables pi-lean-dimension.search when pi-lean-dimension.web changed fires with enabled: true", async () => {
468
468
  const { pi, events } = mockSearchPi([]);
469
469
  searchExtension(pi);
470
470
 
471
471
  events.emit(TOOLSET_EVENTS.changed, {
472
- id: "portal.web",
472
+ id: "pi-lean-dimension.web",
473
473
  enabled: true,
474
474
  });
475
475
 
@@ -4,7 +4,7 @@
4
4
  * Registers the `web-search` tool and a `/searxng-status` diagnostic command.
5
5
  * Manages the `search` status bar slot with health-colored glyphs.
6
6
  *
7
- * Owns the `search.web` toolset (co-activated off `portal.web`):
7
+ * Owns the `pi-lean-dimension.search` toolset (co-activated off `pi-lean-dimension.web`):
8
8
  * ● searxng (accent/blue) — healthy and reachable
9
9
  * ● searxng (warning/yellow) — server up but pipeline degraded
10
10
  * ● searxng (error/red) — unreachable
@@ -24,9 +24,9 @@ import { webSearchTool } from "./web-search-tool.js";
24
24
  // ─── Toolset spec ────────────────────────────────────────────────
25
25
 
26
26
  const SEARCH_WEB_SPEC: ToolsetSpec = {
27
- id: "search.web",
27
+ id: "pi-lean-dimension.search",
28
28
  names: new Set(["web-search"]),
29
- persistKey: "toolset-state:search.web",
29
+ persistKey: "toolset-state:pi-lean-dimension.search",
30
30
  defaultEnabled: true,
31
31
  };
32
32
 
@@ -35,7 +35,7 @@ const SEARCH_WEB_SPEC: ToolsetSpec = {
35
35
  /** Cached SearXNG URL (read once at startup, stable mid-session). */
36
36
  let _searxngUrl: string | undefined;
37
37
 
38
- /** Last known search.web enabled state (updated by library events). */
38
+ /** Last known pi-lean-dimension.search enabled state (updated by library events). */
39
39
  let _lastSearchEnabled = true;
40
40
 
41
41
  /** Last known health state: true=healthy, false=unreachable, null=unconfigured. */
@@ -128,10 +128,10 @@ function displayUrl(url: string): string {
128
128
  /**
129
129
  * Render the `search` status slot based on toolset state + health.
130
130
  *
131
- * search.web off → ○ searxng
132
- * search.web on + healthy → ● searxng (accent/blue)
133
- * search.web on + degraded → ● searxng (warning/yellow)
134
- * search.web on + unreachable → ● searxng (error/red)
131
+ * pi-lean-dimension.search off → ○ searxng
132
+ * pi-lean-dimension.search on + healthy → ● searxng (accent/blue)
133
+ * pi-lean-dimension.search on + degraded → ● searxng (warning/yellow)
134
+ * pi-lean-dimension.search on + unreachable → ● searxng (error/red)
135
135
  * unconfigured → (clear slot)
136
136
  */
137
137
  function renderSearchGlyph(ctx: {
@@ -154,13 +154,13 @@ function renderSearchGlyph(ctx: {
154
154
  return;
155
155
  }
156
156
 
157
- // search.web disabled — show off state
157
+ // pi-lean-dimension.search disabled — show off state
158
158
  if (!_lastSearchEnabled) {
159
159
  safeSetStatus("○ searxng");
160
160
  return;
161
161
  }
162
162
 
163
- // search.web enabled — show health-colored glyph
163
+ // pi-lean-dimension.search enabled — show health-colored glyph
164
164
  if (!_lastHealth) {
165
165
  safeSetStatus(ctx.ui.theme.fg("error", "●") + " searxng");
166
166
  return;
@@ -193,15 +193,15 @@ export default function (pi: ExtensionAPI) {
193
193
  // ── Register the web-search tool ─────────────────────────
194
194
  pi.registerTool(webSearchTool);
195
195
 
196
- // ── Define the search.web toolset ────────────────────────
196
+ // ── Define the pi-lean-dimension.search toolset ───────────
197
197
  // Registers restore handler on session_start / session_tree.
198
198
  const searchToolset = defineToolset(pi, SEARCH_WEB_SPEC);
199
199
 
200
- // ── Co-activation: mirror portal.web changed events ──────
200
+ // ── Co-activation: mirror pi-lean-dimension.web changed events ─
201
201
  // Listen on changed ONLY, not restored (§10.1).
202
202
  pi.events.on(TOOLSET_EVENTS.changed, (data: unknown) => {
203
203
  const event = data as ToolsetChangedEvent;
204
- if (event.id === "portal.web") {
204
+ if (event.id === "pi-lean-dimension.web") {
205
205
  if (event.enabled) {
206
206
  searchToolset.enable(pi);
207
207
  } else {
@@ -213,7 +213,7 @@ export default function (pi: ExtensionAPI) {
213
213
  // ── Keep cached state in sync with library events ────────
214
214
  const syncSearchState = (data: unknown) => {
215
215
  const event = data as ToolsetChangedEvent;
216
- if (event.id === "search.web") {
216
+ if (event.id === "pi-lean-dimension.search") {
217
217
  _lastSearchEnabled = event.enabled;
218
218
  if (_lastCtx) renderSearchGlyph(_lastCtx);
219
219
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lean-search",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
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",
@@ -37,12 +37,14 @@
37
37
  "prepack": "cp ../../LICENSE ./LICENSE",
38
38
  "test": "vitest run"
39
39
  },
40
+ "dependencies": {
41
+ "pi-tool-masking": "^1.0.0"
42
+ },
40
43
  "peerDependencies": {
41
44
  "@earendil-works/pi-ai": "*",
42
45
  "@earendil-works/pi-coding-agent": "*",
43
46
  "@earendil-works/pi-tui": "*",
44
47
  "pi-lean-portal": "*",
45
- "pi-tool-masking": "^1.0.0",
46
48
  "typebox": "*"
47
49
  },
48
50
  "peerDependenciesMeta": {