pi-chrome 0.15.18 → 0.15.20

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable user-facing changes to `pi-chrome`.
4
4
 
5
+ ## 0.15.20 — 2026-05-15
6
+
7
+ - **Interruptible `chrome_*` tools.** All `chrome_*` tools now honor the agent harness `AbortSignal`, so pressing Esc aborts in-flight bridge calls (including the long-polling `chrome_wait_for`) immediately instead of waiting out the full `timeoutMs`.
8
+
9
+ ## 0.15.19 — 2026-05-14
10
+
11
+ - **Simpler package description.** README hero and npm/pi.dev description now use the same concise authorization-focused sentence.
12
+
5
13
  ## 0.15.18 — 2026-05-14
6
14
 
7
15
  - **Cleaner package description.** npm/pi.dev description now focuses on the existing Chrome profile and explicit authorization model, avoiding implementation details.
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # pi-chrome
2
2
 
3
- > **Let a [Pi](https://pi.dev) agent use your existing signed-in Chrome profile.**
4
- > Explicitly authorize each Pi session. No throwaway browser, no re-login.
3
+ > **Let [Pi](https://pi.dev) use your existing signed-in Chrome profile after explicit authorization.**
5
4
 
6
5
  **MIT · 0 runtime deps · loopback-only bridge (`127.0.0.1:17318`) · inspect [`extensions/chrome-profile-bridge/browser-extension/`](./extensions/chrome-profile-bridge/browser-extension) before loading.** Verify connectivity in one command: `/chrome doctor`.
7
6
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Pi Chrome Connector",
4
- "version": "0.15.18",
4
+ "version": "0.15.20",
5
5
  "description": "Lets Pi control tabs in Chrome via a local connector at 127.0.0.1.",
6
6
  "permissions": [
7
7
  "tabs",
@@ -237,32 +237,58 @@ class ChromeProfileBridge {
237
237
  this.mode = undefined;
238
238
  }
239
239
 
240
- send(action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<unknown> {
241
- if (this.mode === "client") return this.sendViaOwner(action, params, timeoutMs);
242
- return this.sendLocal(action, params, timeoutMs);
240
+ send(action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS, signal?: AbortSignal): Promise<unknown> {
241
+ if (this.mode === "client") return this.sendViaOwner(action, params, timeoutMs, signal);
242
+ return this.sendLocal(action, params, timeoutMs, signal);
243
243
  }
244
244
 
245
- private sendLocal(action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<unknown> {
245
+ private sendLocal(action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS, signal?: AbortSignal): Promise<unknown> {
246
246
  const id = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
247
247
  const command = { id, action, params };
248
248
  return new Promise((resolveCommand, rejectCommand) => {
249
+ if (signal?.aborted) {
250
+ rejectCommand(new Error("Chrome command aborted"));
251
+ return;
252
+ }
253
+ const cleanupAbort = () => {
254
+ if (signal) signal.removeEventListener("abort", onAbort);
255
+ };
256
+ const onAbort = () => {
257
+ clearTimeout(timer);
258
+ this.pending.delete(id);
259
+ this.queue = this.queue.filter((queued) => queued.id !== id);
260
+ cleanupAbort();
261
+ rejectCommand(new Error("Chrome command aborted"));
262
+ };
249
263
  const timer = setTimeout(() => {
250
264
  this.pending.delete(id);
251
265
  this.queue = this.queue.filter((queued) => queued.id !== id);
266
+ cleanupAbort();
252
267
  rejectCommand(
253
268
  new Error(
254
269
  `Timed out waiting for Chrome extension after ${timeoutMs}ms. Run /chrome onboard, then load the bundled browser-extension folder in your normal Chrome profile.`,
255
270
  ),
256
271
  );
257
272
  }, timeoutMs);
258
- this.pending.set(id, { command, resolve: resolveCommand, reject: rejectCommand, timer });
273
+ this.pending.set(id, {
274
+ command,
275
+ resolve: (value) => { cleanupAbort(); resolveCommand(value); },
276
+ reject: (err) => { cleanupAbort(); rejectCommand(err); },
277
+ timer,
278
+ });
279
+ if (signal) signal.addEventListener("abort", onAbort, { once: true });
259
280
  this.enqueue(command);
260
281
  });
261
282
  }
262
283
 
263
- private async sendViaOwner(action: string, params: Record<string, unknown>, timeoutMs: number): Promise<unknown> {
284
+ private async sendViaOwner(action: string, params: Record<string, unknown>, timeoutMs: number, signal?: AbortSignal): Promise<unknown> {
264
285
  const controller = new AbortController();
265
286
  const timer = setTimeout(() => controller.abort(), timeoutMs + 2_000);
287
+ const forwardAbort = () => controller.abort();
288
+ if (signal) {
289
+ if (signal.aborted) controller.abort();
290
+ else signal.addEventListener("abort", forwardAbort, { once: true });
291
+ }
266
292
  try {
267
293
  const response = await fetch(`${this.url}/command`, {
268
294
  method: "POST",
@@ -280,11 +306,13 @@ class ChromeProfileBridge {
280
306
  return payload.result;
281
307
  } catch (error) {
282
308
  if ((error as Error).name === "AbortError") {
309
+ if (signal?.aborted) throw new Error("Chrome command aborted");
283
310
  throw new Error(`Timed out waiting for shared Chrome bridge owner after ${timeoutMs}ms`);
284
311
  }
285
312
  throw error;
286
313
  } finally {
287
314
  clearTimeout(timer);
315
+ if (signal) signal.removeEventListener("abort", forwardAbort);
288
316
  }
289
317
  }
290
318
 
@@ -419,8 +447,9 @@ function StringEnum<T extends readonly [string, ...string[]]>(values: T) {
419
447
  }
420
448
 
421
449
  export default function (pi: ExtensionAPI): void {
450
+ const instanceToken = Symbol("pi-chrome-instance");
422
451
  const globalState = globalThis as typeof globalThis & {
423
- [PI_CHROME_GLOBAL_KEY]?: { version: string; root: string };
452
+ [PI_CHROME_GLOBAL_KEY]?: { version: string; root: string; token: symbol };
424
453
  };
425
454
  const alreadyLoaded = globalState[PI_CHROME_GLOBAL_KEY];
426
455
  if (alreadyLoaded) {
@@ -429,7 +458,7 @@ export default function (pi: ExtensionAPI): void {
429
458
  );
430
459
  return;
431
460
  }
432
- globalState[PI_CHROME_GLOBAL_KEY] = { version: PI_CHROME_VERSION, root: extensionRoot() };
461
+ globalState[PI_CHROME_GLOBAL_KEY] = { version: PI_CHROME_VERSION, root: extensionRoot(), token: instanceToken };
433
462
 
434
463
  const bridge = new ChromeProfileBridge(DEFAULT_HOST, DEFAULT_PORT);
435
464
  let backgroundDefault = false;
@@ -457,9 +486,9 @@ export default function (pi: ExtensionAPI): void {
457
486
  }
458
487
  };
459
488
 
460
- const authorizedBridgeSend = (action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<unknown> => {
489
+ const authorizedBridgeSend = (action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS, signal?: AbortSignal): Promise<unknown> => {
461
490
  requireChromeControlAuthorized();
462
- return bridge.send(action, params, timeoutMs);
491
+ return bridge.send(action, params, timeoutMs, signal);
463
492
  };
464
493
 
465
494
  // Translate the public `background` parameter (default false = visible/foreground) into the
@@ -490,6 +519,9 @@ export default function (pi: ExtensionAPI): void {
490
519
 
491
520
  pi.on("session_shutdown", () => {
492
521
  bridge.stop();
522
+ if (globalState[PI_CHROME_GLOBAL_KEY]?.token === instanceToken) {
523
+ delete globalState[PI_CHROME_GLOBAL_KEY];
524
+ }
493
525
  });
494
526
 
495
527
  pi.on("before_agent_start", (event) => {
@@ -829,9 +861,9 @@ Usage rules:
829
861
  useDefaultProfile: Type.Optional(Type.Boolean({ description: "Ignored; existing-profile access comes from the companion Chrome extension." })),
830
862
  headless: Type.Optional(Type.Boolean({ description: "Ignored." })),
831
863
  }),
832
- async execute(_id, params, _signal, _onUpdate, ctx): Promise<ToolTextResult> {
864
+ async execute(_id, params, signal, _onUpdate, ctx): Promise<ToolTextResult> {
833
865
  if (params.url && bridge.connected) {
834
- const result = await authorizedBridgeSend("tab.new", { url: params.url }, DEFAULT_TIMEOUT_MS);
866
+ const result = await authorizedBridgeSend("tab.new", { url: params.url }, DEFAULT_TIMEOUT_MS, signal);
835
867
  return { content: [{ type: "text", text: `Chrome bridge connected; opened ${params.url}` }], details: { status: bridge.status(), result } };
836
868
  }
837
869
  return {
@@ -865,8 +897,8 @@ Usage rules:
865
897
  host: Type.Optional(Type.String()),
866
898
  port: Type.Optional(Type.Number()),
867
899
  }),
868
- async execute(_id, params): Promise<ToolTextResult> {
869
- const result = await authorizedBridgeSend(`tab.${params.action}`, params, DEFAULT_TIMEOUT_MS);
900
+ async execute(_id, params, signal): Promise<ToolTextResult> {
901
+ const result = await authorizedBridgeSend(`tab.${params.action}`, params, DEFAULT_TIMEOUT_MS, signal);
870
902
  if (params.action === "list") {
871
903
  const tabs = result as Array<{ id: number; title: string; url: string; active: boolean; windowId: number }>;
872
904
  const text = tabs.map((tab) => `${tab.id}\t${tab.active ? "*" : " "}\t${tab.title || "(untitled)"}\t${tab.url}`).join("\n") || "No tabs.";
@@ -896,11 +928,12 @@ Usage rules:
896
928
  host: Type.Optional(Type.String()),
897
929
  port: Type.Optional(Type.Number()),
898
930
  }),
899
- async execute(_id, params): Promise<ToolTextResult> {
931
+ async execute(_id, params, signal): Promise<ToolTextResult> {
900
932
  const snapshot = await authorizedBridgeSend(
901
933
  "page.snapshot",
902
934
  withBackground({ ...params, maxElements: params.maxElements ?? MAX_ELEMENTS }),
903
935
  DEFAULT_TIMEOUT_MS,
936
+ signal,
904
937
  );
905
938
  return { content: [{ type: "text", text: truncateText(safeJson(snapshot)) }], details: { snapshot } };
906
939
  },
@@ -926,8 +959,8 @@ Usage rules:
926
959
  host: Type.Optional(Type.String()),
927
960
  port: Type.Optional(Type.Number()),
928
961
  }),
929
- async execute(_id, params): Promise<ToolTextResult> {
930
- const result = await authorizedBridgeSend("page.navigate", withBackground(params), (params.timeoutMs ?? 15_000) + 2_000);
962
+ async execute(_id, params, signal): Promise<ToolTextResult> {
963
+ const result = await authorizedBridgeSend("page.navigate", withBackground(params), (params.timeoutMs ?? 15_000) + 2_000, signal);
931
964
  return { content: [{ type: "text", text: `Navigated to ${params.url}${params.initScript ? " (with initScript)" : ""}` }], details: { result: result as Json } };
932
965
  },
933
966
  });
@@ -950,8 +983,8 @@ Usage rules:
950
983
  host: Type.Optional(Type.String()),
951
984
  port: Type.Optional(Type.Number()),
952
985
  }),
953
- async execute(_id, params): Promise<ToolTextResult> {
954
- const value = await authorizedBridgeSend("page.evaluate", withBackground(params), DEFAULT_TIMEOUT_MS);
986
+ async execute(_id, params, signal): Promise<ToolTextResult> {
987
+ const value = await authorizedBridgeSend("page.evaluate", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
955
988
  const text = value === undefined
956
989
  ? "undefined"
957
990
  : typeof value === "string"
@@ -983,8 +1016,8 @@ Usage rules:
983
1016
  host: Type.Optional(Type.String()),
984
1017
  port: Type.Optional(Type.Number()),
985
1018
  }),
986
- async execute(_id, params): Promise<ToolTextResult> {
987
- const raw = await authorizedBridgeSend("page.click", withBackground(params), DEFAULT_TIMEOUT_MS);
1019
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1020
+ const raw = await authorizedBridgeSend("page.click", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
988
1021
  const result = (params.includeSnapshot ? (raw as { result: unknown }).result : raw) as Json;
989
1022
  const summary = summarizeActionResult(result);
990
1023
  const target = params.uid ?? params.selector ?? `${params.x},${params.y}`;
@@ -1015,8 +1048,8 @@ Usage rules:
1015
1048
  host: Type.Optional(Type.String()),
1016
1049
  port: Type.Optional(Type.Number()),
1017
1050
  }),
1018
- async execute(_id, params): Promise<ToolTextResult> {
1019
- const raw = await authorizedBridgeSend("page.type", withBackground(params), DEFAULT_TIMEOUT_MS);
1051
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1052
+ const raw = await authorizedBridgeSend("page.type", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1020
1053
  const result = (params.includeSnapshot ? (raw as { result: unknown }).result : raw) as Json;
1021
1054
  const summary = summarizeActionResult(result);
1022
1055
  const into = params.uid || params.selector ? ` into ${params.uid ?? params.selector}` : "";
@@ -1047,8 +1080,8 @@ Usage rules:
1047
1080
  host: Type.Optional(Type.String()),
1048
1081
  port: Type.Optional(Type.Number()),
1049
1082
  }),
1050
- async execute(_id, params): Promise<ToolTextResult> {
1051
- const raw = await authorizedBridgeSend("page.fill", withBackground(params), DEFAULT_TIMEOUT_MS);
1083
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1084
+ const raw = await authorizedBridgeSend("page.fill", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1052
1085
  const result = (params.includeSnapshot ? (raw as { result: unknown }).result : raw) as Json;
1053
1086
  const summary = summarizeActionResult(result);
1054
1087
  const into = params.uid || params.selector ? ` into ${params.uid ?? params.selector}` : "";
@@ -1082,8 +1115,8 @@ Usage rules:
1082
1115
  host: Type.Optional(Type.String()),
1083
1116
  port: Type.Optional(Type.Number()),
1084
1117
  }),
1085
- async execute(_id, params): Promise<ToolTextResult> {
1086
- const raw = await authorizedBridgeSend("page.key", withBackground(params), DEFAULT_TIMEOUT_MS);
1118
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1119
+ const raw = await authorizedBridgeSend("page.key", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1087
1120
  const result = (params.includeSnapshot ? (raw as { result: unknown }).result : raw) as Json;
1088
1121
  const summary = summarizeActionResult(result);
1089
1122
  const base = `Pressed ${params.key}.`;
@@ -1107,8 +1140,8 @@ Usage rules:
1107
1140
  host: Type.Optional(Type.String()),
1108
1141
  port: Type.Optional(Type.Number()),
1109
1142
  }),
1110
- async execute(_id, params): Promise<ToolTextResult> {
1111
- const result = await authorizedBridgeSend("page.waitFor", params, (params.timeoutMs ?? 10_000) + 2_000);
1143
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1144
+ const result = await authorizedBridgeSend("page.waitFor", params, (params.timeoutMs ?? 10_000) + 2_000, signal);
1112
1145
  return { content: [{ type: "text", text: `Observed ${params.kind}: ${params.value}` }], details: { result: result as Json } };
1113
1146
  },
1114
1147
  });
@@ -1128,8 +1161,8 @@ Usage rules:
1128
1161
  host: Type.Optional(Type.String()),
1129
1162
  port: Type.Optional(Type.Number()),
1130
1163
  }),
1131
- async execute(_id, params): Promise<ToolTextResult> {
1132
- const result = await authorizedBridgeSend("page.console.list", withBackground(params), DEFAULT_TIMEOUT_MS);
1164
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1165
+ const result = await authorizedBridgeSend("page.console.list", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1133
1166
  return { content: [{ type: "text", text: truncateText(safeJson(result)) }], details: { result: result as Json } };
1134
1167
  },
1135
1168
  });
@@ -1150,8 +1183,8 @@ Usage rules:
1150
1183
  host: Type.Optional(Type.String()),
1151
1184
  port: Type.Optional(Type.Number()),
1152
1185
  }),
1153
- async execute(_id, params): Promise<ToolTextResult> {
1154
- const result = await authorizedBridgeSend("page.network.list", withBackground(params), DEFAULT_TIMEOUT_MS);
1186
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1187
+ const result = await authorizedBridgeSend("page.network.list", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1155
1188
  return { content: [{ type: "text", text: truncateText(safeJson(result)) }], details: { result: result as Json } };
1156
1189
  },
1157
1190
  });
@@ -1170,8 +1203,8 @@ Usage rules:
1170
1203
  host: Type.Optional(Type.String()),
1171
1204
  port: Type.Optional(Type.Number()),
1172
1205
  }),
1173
- async execute(_id, params): Promise<ToolTextResult> {
1174
- const result = await authorizedBridgeSend("page.network.get", withBackground(params), DEFAULT_TIMEOUT_MS);
1206
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1207
+ const result = await authorizedBridgeSend("page.network.get", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1175
1208
  return { content: [{ type: "text", text: truncateText(safeJson(result)) }], details: { result: result as Json } };
1176
1209
  },
1177
1210
  });
@@ -1196,12 +1229,12 @@ Usage rules:
1196
1229
  host: Type.Optional(Type.String()),
1197
1230
  port: Type.Optional(Type.Number()),
1198
1231
  }),
1199
- async execute(_id, params, _signal, _onUpdate, ctx: ExtensionContext): Promise<ToolTextResult> {
1232
+ async execute(_id, params, signal, _onUpdate, ctx: ExtensionContext): Promise<ToolTextResult> {
1200
1233
  const format = params.format ?? "png";
1201
1234
  const cwd = workspaceCwd(ctx);
1202
1235
  const defaultPath = join(cwd, ".pi", "chrome-screenshots", `${new Date().toISOString().replace(/[:.]/g, "-")}.${format}`);
1203
1236
  const outputPath = params.path ? resolve(cwd, params.path) : defaultPath;
1204
- const result = (await authorizedBridgeSend("page.screenshot", withBackground(params), params.fullPage ? 120_000 : DEFAULT_TIMEOUT_MS)) as {
1237
+ const result = (await authorizedBridgeSend("page.screenshot", withBackground(params), params.fullPage ? 120_000 : DEFAULT_TIMEOUT_MS, signal)) as {
1205
1238
  dataUrl?: string;
1206
1239
  tab?: unknown;
1207
1240
  fullPage?: boolean;
@@ -1250,8 +1283,8 @@ Usage rules:
1250
1283
  titleIncludes: Type.Optional(Type.String()),
1251
1284
  background: Type.Optional(Type.Boolean()),
1252
1285
  }),
1253
- async execute(_id, params): Promise<ToolTextResult> {
1254
- const result = await authorizedBridgeSend("page.hover", withBackground(params), DEFAULT_TIMEOUT_MS);
1286
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1287
+ const result = await authorizedBridgeSend("page.hover", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1255
1288
  return { content: [{ type: "text", text: `Hovered ${params.uid ?? params.selector ?? `${params.x},${params.y}`}` }], details: { result: result as Json } };
1256
1289
  },
1257
1290
  });
@@ -1276,8 +1309,8 @@ Usage rules:
1276
1309
  titleIncludes: Type.Optional(Type.String()),
1277
1310
  background: Type.Optional(Type.Boolean()),
1278
1311
  }),
1279
- async execute(_id, params): Promise<ToolTextResult> {
1280
- const result = await authorizedBridgeSend("page.drag", withBackground(params), DEFAULT_TIMEOUT_MS);
1312
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1313
+ const result = await authorizedBridgeSend("page.drag", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1281
1314
  return { content: [{ type: "text", text: `Dragged from ${params.fromUid ?? params.fromSelector} to ${params.toUid ?? params.toSelector}` }], details: { result: result as Json } };
1282
1315
  },
1283
1316
  });
@@ -1298,8 +1331,8 @@ Usage rules:
1298
1331
  titleIncludes: Type.Optional(Type.String()),
1299
1332
  background: Type.Optional(Type.Boolean()),
1300
1333
  }),
1301
- async execute(_id, params): Promise<ToolTextResult> {
1302
- const result = await authorizedBridgeSend("page.tap", withBackground(params), DEFAULT_TIMEOUT_MS);
1334
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1335
+ const result = await authorizedBridgeSend("page.tap", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1303
1336
  const target = params.uid ?? params.selector ?? `${params.x},${params.y}`;
1304
1337
  return { content: [{ type: "text", text: `Tapped ${target} (touch)` }], details: { result: result as Json } };
1305
1338
  },
@@ -1321,8 +1354,8 @@ Usage rules:
1321
1354
  titleIncludes: Type.Optional(Type.String()),
1322
1355
  background: Type.Optional(Type.Boolean()),
1323
1356
  }),
1324
- async execute(_id, params): Promise<ToolTextResult> {
1325
- const result = await authorizedBridgeSend("page.scroll", withBackground(params), DEFAULT_TIMEOUT_MS);
1357
+ async execute(_id, params, signal): Promise<ToolTextResult> {
1358
+ const result = await authorizedBridgeSend("page.scroll", withBackground(params), DEFAULT_TIMEOUT_MS, signal);
1326
1359
  return { content: [{ type: "text", text: `Scrolled dy=${params.deltaY ?? 0} dx=${params.deltaX ?? 0}` }], details: { result: result as Json } };
1327
1360
  },
1328
1361
  });
@@ -1341,10 +1374,10 @@ Usage rules:
1341
1374
  titleIncludes: Type.Optional(Type.String()),
1342
1375
  background: Type.Optional(Type.Boolean()),
1343
1376
  }),
1344
- async execute(_id, params, _signal, _onUpdate, ctx): Promise<ToolTextResult> {
1377
+ async execute(_id, params, signal, _onUpdate, ctx): Promise<ToolTextResult> {
1345
1378
  const cwd = workspaceCwd(ctx);
1346
1379
  const paths = params.paths.map((p) => resolve(cwd, p));
1347
- const result = await authorizedBridgeSend("page.upload", withBackground({ ...params, paths }), DEFAULT_TIMEOUT_MS);
1380
+ const result = await authorizedBridgeSend("page.upload", withBackground({ ...params, paths }), DEFAULT_TIMEOUT_MS, signal);
1348
1381
  return { content: [{ type: "text", text: `Uploaded ${paths.length} file(s) to ${params.uid ?? params.selector}` }], details: { result: result as Json } };
1349
1382
  },
1350
1383
  });
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "pi-chrome",
3
- "version": "0.15.18",
3
+ "version": "0.15.20",
4
4
  "scripts": {
5
5
  "version": "node scripts/sync-manifest-version.js",
6
6
  "prepublishOnly": "node scripts/sync-manifest-version.js"
7
7
  },
8
- "description": "Let Pi use your existing signed-in Chrome profile after explicit authorization. No throwaway browser, no re-login.",
8
+ "description": "Let Pi use your existing signed-in Chrome profile after explicit authorization.",
9
9
  "keywords": [
10
10
  "pi",
11
11
  "pi-package",