browsentic 0.4.15 → 0.5.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/dist/cli.js +65 -3
- package/dist/daemon-main.js +66 -3
- package/extension/chrome-mv3/background.js +23 -23
- package/extension/chrome-mv3/chunks/{globals-NNs2RHRZ.js → globals-BlPE2up2.js} +12 -12
- package/extension/chrome-mv3/chunks/{popup-eocjPmx2.js → popup-Bv3LKSQA.js} +1 -1
- package/extension/chrome-mv3/chunks/{sidepanel-CgfZof6T.js → sidepanel-BfxbkWaC.js} +1 -1
- package/extension/chrome-mv3/content-scripts/content.js +23 -23
- package/extension/chrome-mv3/manifest.json +1 -1
- package/extension/chrome-mv3/popup.html +2 -2
- package/extension/chrome-mv3/sidepanel.html +2 -2
- package/package.json +1 -1
- package/skills/browser-control.md +9 -1
package/dist/cli.js
CHANGED
|
@@ -28284,6 +28284,54 @@ var focusInput = defineAction({
|
|
|
28284
28284
|
}
|
|
28285
28285
|
});
|
|
28286
28286
|
|
|
28287
|
+
// ../lib/actions/page/switch-frame.ts
|
|
28288
|
+
var switchFrame = defineAction({
|
|
28289
|
+
name: "page.switchFrame",
|
|
28290
|
+
description: 'Step into an <iframe> so that every later page action \u2014 reading, clicking, typing, waiting, site tools, injected code \u2014 runs inside it as if it were the page, or step back out. page.getPageInfo lists the frames the current document embeds under "frames"; pass one as "frame" to enter it, and call again from inside to go deeper. Call it with no arguments to return to the top document, or with to: "parent" to step out one level. The focus is per tab, clears when the tab navigates, and page.getPageInfo reports it under "frame" whenever it is not the top. A frame that forbids scripts (a sandbox without allow-scripts) or a browser-internal frame cannot be entered; page.screenshot and page.trustedClick by coordinates still reach those. page.screenshot and page.navigate always act on the whole tab.',
|
|
28291
|
+
input: external_exports.object({
|
|
28292
|
+
frame: targetSchema.optional().describe(
|
|
28293
|
+
'The <iframe> or <frame> element to enter, matched inside the frame currently in focus \u2014 use a selector from the "frames" list of page.getPageInfo. Omit it to leave instead.'
|
|
28294
|
+
),
|
|
28295
|
+
to: external_exports.enum(["top", "parent"]).default("top").describe('Where to go when no "frame" is given: "top" returns to the main document, "parent" steps out one level.')
|
|
28296
|
+
}),
|
|
28297
|
+
execute({ frame }) {
|
|
28298
|
+
if (!frame) {
|
|
28299
|
+
throw new ActionError("Leaving a frame is resolved by the Browsentic extension, not in the page", "UNSUPPORTED");
|
|
28300
|
+
}
|
|
28301
|
+
const el = resolveTarget(frame);
|
|
28302
|
+
if (!isFrameElement(el)) {
|
|
28303
|
+
throw new ActionError(
|
|
28304
|
+
`${cssPath(el)} is a <${el.tagName.toLowerCase()}>, not an <iframe> \u2014 pick one of the frames page.getPageInfo lists`,
|
|
28305
|
+
"INVALID_TARGET"
|
|
28306
|
+
);
|
|
28307
|
+
}
|
|
28308
|
+
return {
|
|
28309
|
+
frameId: frameIdOf(el),
|
|
28310
|
+
src: el.src || void 0,
|
|
28311
|
+
name: el.name || void 0,
|
|
28312
|
+
sandbox: sandboxOf(el),
|
|
28313
|
+
...describeElement(el)
|
|
28314
|
+
};
|
|
28315
|
+
}
|
|
28316
|
+
});
|
|
28317
|
+
function isFrameElement(el) {
|
|
28318
|
+
return el instanceof HTMLIFrameElement || el instanceof HTMLFrameElement;
|
|
28319
|
+
}
|
|
28320
|
+
function sandboxOf(el) {
|
|
28321
|
+
return el instanceof HTMLIFrameElement && el.hasAttribute("sandbox") ? el.sandbox.value || "all restrictions" : void 0;
|
|
28322
|
+
}
|
|
28323
|
+
function frameIdOf(target) {
|
|
28324
|
+
const scope = globalThis;
|
|
28325
|
+
const id = (scope.browser?.runtime?.getFrameId ?? scope.chrome?.runtime?.getFrameId)?.(target);
|
|
28326
|
+
if (typeof id !== "number" || id < 0) {
|
|
28327
|
+
throw new ActionError(
|
|
28328
|
+
"This browser cannot identify frames from the page \u2014 entering a frame needs Chrome 116 or Firefox 96 or newer",
|
|
28329
|
+
"UNSUPPORTED"
|
|
28330
|
+
);
|
|
28331
|
+
}
|
|
28332
|
+
return id;
|
|
28333
|
+
}
|
|
28334
|
+
|
|
28287
28335
|
// ../lib/actions/page/get-page-info.ts
|
|
28288
28336
|
var IMPLICIT_ROLES = {
|
|
28289
28337
|
header: "banner",
|
|
@@ -28308,7 +28356,7 @@ var LANDMARK_ROLES = /* @__PURE__ */ new Set([
|
|
|
28308
28356
|
]);
|
|
28309
28357
|
var getPageInfo = defineAction({
|
|
28310
28358
|
name: "page.getPageInfo",
|
|
28311
|
-
description:
|
|
28359
|
+
description: 'Snapshot the current page: document metadata, viewport and scroll state, a semantic layout tree with a text diagram, the heading outline, and an inventory of interactive elements \u2014 each carrying its ARIA role, its live state (disabled, checked, expanded, filled, aria-current) and the landmark region it sits in. When the site registers WebMCP tools, the result also carries a siteTools list \u2014 prefer page.callSiteTool over clicking wherever a listed tool covers the step. Visible iframes come back under "frames"; nothing inside one is in this snapshot until page.switchFrame enters it, and "frame" then says which one is in focus.',
|
|
28312
28360
|
input: external_exports.object({
|
|
28313
28361
|
maxPerKind: external_exports.number().int().positive().default(30).describe("Cap on links, buttons, fields, and forms listed per kind")
|
|
28314
28362
|
}),
|
|
@@ -28337,10 +28385,23 @@ var getPageInfo = defineAction({
|
|
|
28337
28385
|
level: Number(heading.tagName[1]),
|
|
28338
28386
|
text: accessibleText(heading).slice(0, 120)
|
|
28339
28387
|
})),
|
|
28340
|
-
interactive: inventory(found, owners, maxPerKind)
|
|
28388
|
+
interactive: inventory(found, owners, maxPerKind),
|
|
28389
|
+
frames: embeddedFrames()
|
|
28341
28390
|
};
|
|
28342
28391
|
}
|
|
28343
28392
|
});
|
|
28393
|
+
var MAX_FRAMES = 20;
|
|
28394
|
+
function embeddedFrames() {
|
|
28395
|
+
const frames = [...document.querySelectorAll("iframe,frame")].filter(isFrameElement).filter(isExposed).slice(0, MAX_FRAMES).map((frame) => ({
|
|
28396
|
+
selector: cssPath(frame),
|
|
28397
|
+
src: frame.src || void 0,
|
|
28398
|
+
name: frame.name || void 0,
|
|
28399
|
+
title: frame.title || void 0,
|
|
28400
|
+
sandbox: sandboxOf(frame),
|
|
28401
|
+
bounds: documentBounds(frame)
|
|
28402
|
+
}));
|
|
28403
|
+
return frames.length ? frames : void 0;
|
|
28404
|
+
}
|
|
28344
28405
|
function regionRole(el) {
|
|
28345
28406
|
const explicit = el.getAttribute("role");
|
|
28346
28407
|
if (explicit) return LANDMARK_ROLES.has(explicit) ? explicit : void 0;
|
|
@@ -29979,6 +30040,7 @@ var actions = new Map(
|
|
|
29979
30040
|
navigate,
|
|
29980
30041
|
openTab,
|
|
29981
30042
|
switchTab,
|
|
30043
|
+
switchFrame,
|
|
29982
30044
|
closeTab,
|
|
29983
30045
|
screenshot,
|
|
29984
30046
|
listFiles,
|
|
@@ -34184,7 +34246,7 @@ function purgeNpxCache(entries) {
|
|
|
34184
34246
|
// package.json
|
|
34185
34247
|
var package_default = {
|
|
34186
34248
|
name: "browsentic",
|
|
34187
|
-
version: "0.
|
|
34249
|
+
version: "0.5.0",
|
|
34188
34250
|
description: "Hand your real, logged-in browser to the AI agent you already run. Installs the browser extension, runs the local daemon, and speaks MCP.",
|
|
34189
34251
|
type: "module",
|
|
34190
34252
|
license: "MIT",
|
package/dist/daemon-main.js
CHANGED
|
@@ -19876,6 +19876,54 @@ var focusInput = defineAction({
|
|
|
19876
19876
|
}
|
|
19877
19877
|
});
|
|
19878
19878
|
|
|
19879
|
+
// ../lib/actions/page/switch-frame.ts
|
|
19880
|
+
var switchFrame = defineAction({
|
|
19881
|
+
name: "page.switchFrame",
|
|
19882
|
+
description: 'Step into an <iframe> so that every later page action \u2014 reading, clicking, typing, waiting, site tools, injected code \u2014 runs inside it as if it were the page, or step back out. page.getPageInfo lists the frames the current document embeds under "frames"; pass one as "frame" to enter it, and call again from inside to go deeper. Call it with no arguments to return to the top document, or with to: "parent" to step out one level. The focus is per tab, clears when the tab navigates, and page.getPageInfo reports it under "frame" whenever it is not the top. A frame that forbids scripts (a sandbox without allow-scripts) or a browser-internal frame cannot be entered; page.screenshot and page.trustedClick by coordinates still reach those. page.screenshot and page.navigate always act on the whole tab.',
|
|
19883
|
+
input: external_exports.object({
|
|
19884
|
+
frame: targetSchema.optional().describe(
|
|
19885
|
+
'The <iframe> or <frame> element to enter, matched inside the frame currently in focus \u2014 use a selector from the "frames" list of page.getPageInfo. Omit it to leave instead.'
|
|
19886
|
+
),
|
|
19887
|
+
to: external_exports.enum(["top", "parent"]).default("top").describe('Where to go when no "frame" is given: "top" returns to the main document, "parent" steps out one level.')
|
|
19888
|
+
}),
|
|
19889
|
+
execute({ frame }) {
|
|
19890
|
+
if (!frame) {
|
|
19891
|
+
throw new ActionError("Leaving a frame is resolved by the Browsentic extension, not in the page", "UNSUPPORTED");
|
|
19892
|
+
}
|
|
19893
|
+
const el = resolveTarget(frame);
|
|
19894
|
+
if (!isFrameElement(el)) {
|
|
19895
|
+
throw new ActionError(
|
|
19896
|
+
`${cssPath(el)} is a <${el.tagName.toLowerCase()}>, not an <iframe> \u2014 pick one of the frames page.getPageInfo lists`,
|
|
19897
|
+
"INVALID_TARGET"
|
|
19898
|
+
);
|
|
19899
|
+
}
|
|
19900
|
+
return {
|
|
19901
|
+
frameId: frameIdOf(el),
|
|
19902
|
+
src: el.src || void 0,
|
|
19903
|
+
name: el.name || void 0,
|
|
19904
|
+
sandbox: sandboxOf(el),
|
|
19905
|
+
...describeElement(el)
|
|
19906
|
+
};
|
|
19907
|
+
}
|
|
19908
|
+
});
|
|
19909
|
+
function isFrameElement(el) {
|
|
19910
|
+
return el instanceof HTMLIFrameElement || el instanceof HTMLFrameElement;
|
|
19911
|
+
}
|
|
19912
|
+
function sandboxOf(el) {
|
|
19913
|
+
return el instanceof HTMLIFrameElement && el.hasAttribute("sandbox") ? el.sandbox.value || "all restrictions" : void 0;
|
|
19914
|
+
}
|
|
19915
|
+
function frameIdOf(target) {
|
|
19916
|
+
const scope = globalThis;
|
|
19917
|
+
const id = (scope.browser?.runtime?.getFrameId ?? scope.chrome?.runtime?.getFrameId)?.(target);
|
|
19918
|
+
if (typeof id !== "number" || id < 0) {
|
|
19919
|
+
throw new ActionError(
|
|
19920
|
+
"This browser cannot identify frames from the page \u2014 entering a frame needs Chrome 116 or Firefox 96 or newer",
|
|
19921
|
+
"UNSUPPORTED"
|
|
19922
|
+
);
|
|
19923
|
+
}
|
|
19924
|
+
return id;
|
|
19925
|
+
}
|
|
19926
|
+
|
|
19879
19927
|
// ../lib/actions/page/get-page-info.ts
|
|
19880
19928
|
var IMPLICIT_ROLES = {
|
|
19881
19929
|
header: "banner",
|
|
@@ -19900,7 +19948,7 @@ var LANDMARK_ROLES = /* @__PURE__ */ new Set([
|
|
|
19900
19948
|
]);
|
|
19901
19949
|
var getPageInfo = defineAction({
|
|
19902
19950
|
name: "page.getPageInfo",
|
|
19903
|
-
description:
|
|
19951
|
+
description: 'Snapshot the current page: document metadata, viewport and scroll state, a semantic layout tree with a text diagram, the heading outline, and an inventory of interactive elements \u2014 each carrying its ARIA role, its live state (disabled, checked, expanded, filled, aria-current) and the landmark region it sits in. When the site registers WebMCP tools, the result also carries a siteTools list \u2014 prefer page.callSiteTool over clicking wherever a listed tool covers the step. Visible iframes come back under "frames"; nothing inside one is in this snapshot until page.switchFrame enters it, and "frame" then says which one is in focus.',
|
|
19904
19952
|
input: external_exports.object({
|
|
19905
19953
|
maxPerKind: external_exports.number().int().positive().default(30).describe("Cap on links, buttons, fields, and forms listed per kind")
|
|
19906
19954
|
}),
|
|
@@ -19929,10 +19977,23 @@ var getPageInfo = defineAction({
|
|
|
19929
19977
|
level: Number(heading.tagName[1]),
|
|
19930
19978
|
text: accessibleText(heading).slice(0, 120)
|
|
19931
19979
|
})),
|
|
19932
|
-
interactive: inventory(found, owners, maxPerKind)
|
|
19980
|
+
interactive: inventory(found, owners, maxPerKind),
|
|
19981
|
+
frames: embeddedFrames()
|
|
19933
19982
|
};
|
|
19934
19983
|
}
|
|
19935
19984
|
});
|
|
19985
|
+
var MAX_FRAMES = 20;
|
|
19986
|
+
function embeddedFrames() {
|
|
19987
|
+
const frames = [...document.querySelectorAll("iframe,frame")].filter(isFrameElement).filter(isExposed).slice(0, MAX_FRAMES).map((frame) => ({
|
|
19988
|
+
selector: cssPath(frame),
|
|
19989
|
+
src: frame.src || void 0,
|
|
19990
|
+
name: frame.name || void 0,
|
|
19991
|
+
title: frame.title || void 0,
|
|
19992
|
+
sandbox: sandboxOf(frame),
|
|
19993
|
+
bounds: documentBounds(frame)
|
|
19994
|
+
}));
|
|
19995
|
+
return frames.length ? frames : void 0;
|
|
19996
|
+
}
|
|
19936
19997
|
function regionRole(el) {
|
|
19937
19998
|
const explicit = el.getAttribute("role");
|
|
19938
19999
|
if (explicit) return LANDMARK_ROLES.has(explicit) ? explicit : void 0;
|
|
@@ -21577,6 +21638,7 @@ var actions = new Map(
|
|
|
21577
21638
|
navigate,
|
|
21578
21639
|
openTab,
|
|
21579
21640
|
switchTab,
|
|
21641
|
+
switchFrame,
|
|
21580
21642
|
closeTab,
|
|
21581
21643
|
screenshot,
|
|
21582
21644
|
listFiles,
|
|
@@ -24554,6 +24616,7 @@ var READ_ONLY_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
24554
24616
|
"page.findSearch",
|
|
24555
24617
|
"page.findCaptcha",
|
|
24556
24618
|
"page.listSiteTools",
|
|
24619
|
+
"page.switchFrame",
|
|
24557
24620
|
"page.monitorStatus",
|
|
24558
24621
|
"page.timerStatus",
|
|
24559
24622
|
"page.readTheme",
|
|
@@ -27181,7 +27244,7 @@ X-Browsentic-Reason: ${reason}\r
|
|
|
27181
27244
|
// package.json
|
|
27182
27245
|
var package_default = {
|
|
27183
27246
|
name: "browsentic",
|
|
27184
|
-
version: "0.
|
|
27247
|
+
version: "0.5.0",
|
|
27185
27248
|
description: "Hand your real, logged-in browser to the AI agent you already run. Installs the browser extension, runs the local daemon, and speaks MCP.",
|
|
27186
27249
|
type: "module",
|
|
27187
27250
|
license: "MIT",
|