@narumitw/pi-chrome-devtools 0.20.0 → 0.31.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
@@ -189,7 +189,8 @@ filename is deprecated and will be removed in a future major release.
189
189
  ```txt
190
190
  extensions/pi-chrome-devtools/
191
191
  ├── src/
192
- │ ├── chrome-devtools.ts # Pi entrypoint and command orchestration
192
+ │ ├── index.ts # Pi package entrypoint
193
+ │ ├── chrome-devtools.ts # Extension registration and command orchestration
193
194
  │ └── *.ts # Package-local browser, CDP, tool, and storage modules
194
195
  ├── README.md
195
196
  ├── LICENSE
@@ -197,12 +198,12 @@ extensions/pi-chrome-devtools/
197
198
  └── package.json
198
199
  ```
199
200
 
200
- Only `chrome-devtools.ts` is a Pi entrypoint; the other source modules are internal. The package exposes its Pi extension through `package.json`:
201
+ `index.ts` is the Pi entrypoint and forwards to `chrome-devtools.ts`; the other source modules are internal. The package exposes its Pi extension through `package.json`:
201
202
 
202
203
  ```json
203
204
  {
204
205
  "pi": {
205
- "extensions": ["./src/chrome-devtools.ts"]
206
+ "extensions": ["./src/index.ts"]
206
207
  }
207
208
  }
208
209
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narumitw/pi-chrome-devtools",
3
- "version": "0.20.0",
3
+ "version": "0.31.0",
4
4
  "description": "Pi extension that exposes Chrome DevTools Protocol tools.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "pi": {
22
22
  "extensions": [
23
- "./src/chrome-devtools.ts"
23
+ "./src/index.ts"
24
24
  ]
25
25
  },
26
26
  "scripts": {
@@ -29,11 +29,11 @@
29
29
  "typecheck": "tsc --noEmit"
30
30
  },
31
31
  "dependencies": {
32
- "typebox": "^1.3.3"
32
+ "typebox": "^1.3.8"
33
33
  },
34
34
  "devDependencies": {
35
- "@biomejs/biome": "2.5.3",
36
- "@earendil-works/pi-coding-agent": "0.80.10",
35
+ "@biomejs/biome": "2.5.5",
36
+ "@earendil-works/pi-coding-agent": "0.82.1",
37
37
  "typescript": "7.0.2"
38
38
  },
39
39
  "repository": {
@@ -1,21 +1,20 @@
1
- import { spawn, type ChildProcess } from "node:child_process";
1
+ import { type ChildProcess, spawn } from "node:child_process";
2
2
  import { constants } from "node:fs";
3
3
  import { access, mkdtemp, readFile, rm } from "node:fs/promises";
4
4
  import { tmpdir } from "node:os";
5
- import { basename, delimiter, isAbsolute, join, resolve } from "node:path";
5
+ import { delimiter, isAbsolute, join, resolve } from "node:path";
6
6
  import {
7
7
  BROWSER_SHUTDOWN_WAIT_MS,
8
+ type BrowserCandidate,
9
+ type BrowserCandidateDefinition,
8
10
  DEFAULT_ENDPOINT_RETRY_MS,
9
11
  DEFAULT_ENDPOINT_WAIT_MS,
10
- DEFAULT_HOST,
11
12
  DEFAULT_HTTP_TIMEOUT_MS,
12
13
  DEVTOOLS_ACTIVE_PORT_FILE,
13
- MANAGED_BROWSER_PROFILE_PREFIX,
14
- state,
15
- type BrowserCandidate,
16
- type BrowserCandidateDefinition,
17
14
  type DevToolsPage,
15
+ MANAGED_BROWSER_PROFILE_PREFIX,
18
16
  type ManagedBrowser,
17
+ state,
19
18
  } from "./runtime.js";
20
19
 
21
20
  function formatError(error: unknown) {
@@ -128,7 +127,12 @@ async function launchBrowserCandidate(candidate: BrowserCandidate, waitMs: numbe
128
127
  ];
129
128
  throwIfBrowserLaunchCancelled();
130
129
  const child = spawn(candidate.resolvedExecutable, args, { shell: false, stdio: "ignore" });
131
- const launchedBrowser: ManagedBrowser = { process: child, userDataDir, exited: false, ready: false };
130
+ const launchedBrowser: ManagedBrowser = {
131
+ process: child,
132
+ userDataDir,
133
+ exited: false,
134
+ ready: false,
135
+ };
132
136
  managedBrowser = launchedBrowser;
133
137
  state.managedBrowser = launchedBrowser;
134
138
 
@@ -259,7 +263,8 @@ export async function shutdownManagedBrowser(
259
263
  });
260
264
  }
261
265
  await rm(managedBrowser.userDataDir, { recursive: true, force: true }).catch(() => undefined);
262
- if (!state.portConfigured && managedBrowser.port === state.port) state.port = state.configuredPort;
266
+ if (!state.portConfigured && managedBrowser.port === state.port)
267
+ state.port = state.configuredPort;
263
268
  }
264
269
 
265
270
  function killManagedBrowserProcess(managedBrowser: ManagedBrowser, signal?: NodeJS.Signals) {
@@ -400,9 +405,13 @@ export function launchModeLabel() {
400
405
  if (!isLocalDevToolsHost(state.host)) return "manual remote endpoint";
401
406
  if (!state.autoLaunchEnabled) return "manual; auto-launch disabled";
402
407
  if (state.managedBrowser && !state.managedBrowser.exited) {
403
- return state.portConfigured ? "auto-launched on explicit port" : "auto-launched on dynamic port";
408
+ return state.portConfigured
409
+ ? "auto-launched on explicit port"
410
+ : "auto-launched on dynamic port";
404
411
  }
405
- return state.portConfigured ? "attach first; auto-launch explicit port" : "attach first; auto-launch dynamic port";
412
+ return state.portConfigured
413
+ ? "attach first; auto-launch explicit port"
414
+ : "attach first; auto-launch dynamic port";
406
415
  }
407
416
 
408
417
  export function launchAttemptLines() {
@@ -435,7 +444,9 @@ export function launchHint() {
435
444
  }
436
445
 
437
446
  export function browserCandidateHint() {
438
- return `Browser candidates: ${browserCandidateDefinitions().map((candidate) => candidate.label).join(", ")}`;
447
+ return `Browser candidates: ${browserCandidateDefinitions()
448
+ .map((candidate) => candidate.label)
449
+ .join(", ")}`;
439
450
  }
440
451
 
441
452
  export function chromeLaunchCommand() {
@@ -475,7 +486,9 @@ function browserCandidateDefinitions(): BrowserCandidateDefinition[] {
475
486
 
476
487
  function explicitBrowserCandidateDefinition(): BrowserCandidateDefinition[] {
477
488
  if (!state.browserExecutable) return [];
478
- return [{ label: "PI_CHROME_DEVTOOLS_BROWSER", executable: state.browserExecutable, source: "env" }];
489
+ return [
490
+ { label: "PI_CHROME_DEVTOOLS_BROWSER", executable: state.browserExecutable, source: "env" },
491
+ ];
479
492
  }
480
493
 
481
494
  function platformBrowserCandidateDefinitions(): BrowserCandidateDefinition[] {
package/src/cdp-client.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
- ensureDevToolsEndpoint,
3
2
  devToolsEndpoint,
3
+ ensureDevToolsEndpoint,
4
4
  fetchDevToolsJson,
5
5
  formatPageListItem,
6
6
  launchHint,
@@ -9,8 +9,8 @@ import {
9
9
  import {
10
10
  DEFAULT_ENDPOINT_WAIT_MS,
11
11
  DEFAULT_TIMEOUT_MS,
12
- state,
13
12
  type DevToolsPage,
13
+ state,
14
14
  } from "./runtime.js";
15
15
 
16
16
  interface CdpResponse<T = unknown> {
@@ -1,14 +1,13 @@
1
1
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import { shutdownManagedBrowser } from "./browser-manager.js";
3
- import { loadSettings } from "./settings.js";
4
3
  import { state } from "./runtime.js";
4
+ import { loadSettings } from "./settings.js";
5
5
  import {
6
6
  allChromeDevtoolsTools,
7
7
  applyChromeDevtoolsTools,
8
8
  buildCommandGuide,
9
9
  buildQuickstartMessage,
10
10
  buildToolStatusMessage,
11
- setSelectedChromeDevtoolsTools,
12
11
  showToolSelector,
13
12
  updateChromeDevtoolsTools,
14
13
  } from "./tool-selector.js";
@@ -104,16 +103,22 @@ async function handleChromeDevtoolsCommand(pi: ExtensionAPI, args: string, ctx:
104
103
  return;
105
104
  }
106
105
 
107
- ctx.ui.notify(`Unknown /chrome-devtools command: ${args.trim()}
106
+ ctx.ui.notify(
107
+ `Unknown /chrome-devtools command: ${args.trim()}
108
108
 
109
- ${buildCommandGuide()}`, "warning");
109
+ ${buildCommandGuide()}`,
110
+ "warning",
111
+ );
110
112
  }
111
113
 
112
114
  async function showMenu(pi: ExtensionAPI, ctx: CommandContext) {
113
115
  if (!ctx.hasUI) {
114
- ctx.ui.notify(`${buildCommandGuide()}
116
+ ctx.ui.notify(
117
+ `${buildCommandGuide()}
115
118
 
116
- ${await buildToolStatusMessage(pi)}`, "info");
119
+ ${await buildToolStatusMessage(pi)}`,
120
+ "info",
121
+ );
117
122
  return;
118
123
  }
119
124
 
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from "./chrome-devtools.js";
package/src/render.ts CHANGED
@@ -1,7 +1,4 @@
1
- import type {
2
- AgentToolResult,
3
- ToolRenderResultOptions,
4
- } from "@earendil-works/pi-coding-agent";
1
+ import type { AgentToolResult, ToolRenderResultOptions } from "@earendil-works/pi-coding-agent";
5
2
 
6
3
  const STATUS_KEY = "chrome-devtools";
7
4
  interface StatusContext {
@@ -90,9 +87,7 @@ class PiTextComponent implements RenderComponent {
90
87
  .split(/\r?\n/)
91
88
  .map((line) => {
92
89
  const truncatedLine = truncateLine(line, Math.max(1, width));
93
- return this.theme && this.color
94
- ? this.theme.fg(this.color, truncatedLine)
95
- : truncatedLine;
90
+ return this.theme && this.color ? this.theme.fg(this.color, truncatedLine) : truncatedLine;
96
91
  });
97
92
  }
98
93
  }
@@ -101,7 +96,11 @@ function truncateLine(line: string, maxWidth: number) {
101
96
  return Array.from(line).slice(0, maxWidth).join("");
102
97
  }
103
98
 
104
- export async function withStatus<T>(ctx: StatusContext, status: string, callback: () => Promise<T>) {
99
+ export async function withStatus<T>(
100
+ ctx: StatusContext,
101
+ status: string,
102
+ callback: () => Promise<T>,
103
+ ) {
105
104
  ctx.ui.setStatus(STATUS_KEY, status);
106
105
  try {
107
106
  return await callback();
package/src/screenshot.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { link, lstat, mkdir, mkdtemp, realpath, rename, rm, writeFile } from "node:fs/promises";
2
+ import { lstat, mkdir, realpath, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { withFileMutationQueue } from "@earendil-works/pi-coding-agent";
@@ -47,7 +47,10 @@ export async function saveScreenshot(
47
47
  };
48
48
  }
49
49
 
50
- export function resolveScreenshotPath(savePath: string | undefined, cwd: string): ResolvedScreenshotPath {
50
+ export function resolveScreenshotPath(
51
+ savePath: string | undefined,
52
+ cwd: string,
53
+ ): ResolvedScreenshotPath {
51
54
  const cwdRoot = resolve(cwd);
52
55
  const tempRoot = resolve(tmpdir());
53
56
 
@@ -228,7 +231,9 @@ export function isPathInsideRoot(path: string, root: string) {
228
231
  const normalizedPath = normalizePathForComparison(resolve(path));
229
232
  const normalizedRoot = normalizePathForComparison(resolve(root));
230
233
  if (normalizedPath === normalizedRoot) return true;
231
- const rootWithSeparator = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;
234
+ const rootWithSeparator = normalizedRoot.endsWith(sep)
235
+ ? normalizedRoot
236
+ : `${normalizedRoot}${sep}`;
232
237
  return normalizedPath.startsWith(rootWithSeparator);
233
238
  }
234
239
 
package/src/settings.ts CHANGED
@@ -3,10 +3,7 @@ import { constants } from "node:fs";
3
3
  import { access, link, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
- import {
7
- CHROME_DEVTOOLS_TOOL_NAMES,
8
- type ChromeDevToolsToolName,
9
- } from "./tool-names.js";
6
+ import { CHROME_DEVTOOLS_TOOL_NAMES, type ChromeDevToolsToolName } from "./tool-names.js";
10
7
 
11
8
  const NEW_SETTINGS_FILE_NAME = "pi-chrome-devtools.json";
12
9
  const LEGACY_SETTINGS_FILE_NAME = "pi-chrome-devtools-settings.json";
@@ -99,10 +96,7 @@ async function migrateLegacySettings(
99
96
  ): Promise<SettingsMigrationResult> {
100
97
  const newPath = settingsFilePath();
101
98
  try {
102
- await installSettingsFileExclusively(
103
- newPath,
104
- `${JSON.stringify(settings, null, 2)}\n`,
105
- );
99
+ await installSettingsFileExclusively(newPath, `${JSON.stringify(settings, null, 2)}\n`);
106
100
  } catch (error) {
107
101
  return {
108
102
  kind: "failed",
@@ -134,7 +128,9 @@ async function fileExists(filePath: string) {
134
128
  }
135
129
  }
136
130
 
137
- export function normalizeChromeDevtoolsSettings(value: unknown): ChromeDevToolsSettings | undefined {
131
+ export function normalizeChromeDevtoolsSettings(
132
+ value: unknown,
133
+ ): ChromeDevToolsSettings | undefined {
138
134
  if (!value || typeof value !== "object") return undefined;
139
135
  const settings = value as { tools?: unknown; updatedAt?: unknown };
140
136
  if (typeof settings.updatedAt !== "number") return undefined;
@@ -190,7 +186,3 @@ function isNodeError(error: unknown): error is NodeJS.ErrnoException {
190
186
  function formatError(error: unknown) {
191
187
  return error instanceof Error ? error.message : String(error);
192
188
  }
193
-
194
- function unique<T>(values: T[]) {
195
- return Array.from(new Set(values));
196
- }
@@ -1,7 +1,6 @@
1
1
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import {
3
3
  browserCandidateHint,
4
- chromeLaunchCommand,
5
4
  devToolsEndpoint,
6
5
  endpointConfigHint,
7
6
  endpointSourceLabel,
@@ -9,12 +8,9 @@ import {
9
8
  launchHint,
10
9
  launchModeLabel,
11
10
  } from "./browser-manager.js";
12
- import { loadSettings, saveSettings, settingsFilePath } from "./settings.js";
13
11
  import { state } from "./runtime.js";
14
- import {
15
- CHROME_DEVTOOLS_TOOL_NAMES,
16
- type ChromeDevToolsToolName,
17
- } from "./tool-names.js";
12
+ import { loadSettings, saveSettings, settingsFilePath } from "./settings.js";
13
+ import { CHROME_DEVTOOLS_TOOL_NAMES, type ChromeDevToolsToolName } from "./tool-names.js";
18
14
 
19
15
  type CommandContext = ExtensionCommandContext;
20
16
  const TOOL_SELECTOR_DONE = "Done";
@@ -187,9 +183,12 @@ export async function updateChromeDevtoolsTools(
187
183
  action: string,
188
184
  ) {
189
185
  await setSelectedChromeDevtoolsTools(pi, ctx, selectedTools);
190
- ctx.ui.notify(`Chrome DevTools tools ${action}.
186
+ ctx.ui.notify(
187
+ `Chrome DevTools tools ${action}.
191
188
 
192
- ${await buildToolStatusMessage(pi)}`, "info");
189
+ ${await buildToolStatusMessage(pi)}`,
190
+ "info",
191
+ );
193
192
  }
194
193
 
195
194
  export async function setSelectedChromeDevtoolsTools(