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
|
|
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
|
|
|
@@ -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, {
|
|
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,
|
|
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,
|
|
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,
|
|
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.
|
|
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.
|
|
8
|
+
"description": "Let Pi use your existing signed-in Chrome profile after explicit authorization.",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"pi",
|
|
11
11
|
"pi-package",
|