browsentic 0.4.15 → 0.6.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 +200 -66
- package/dist/daemon-main.js +72 -5
- package/extension/chrome-mv3/assets/globals-gUnqG7C4.css +2 -0
- package/extension/chrome-mv3/background.js +23 -23
- package/extension/chrome-mv3/chunks/{globals-NNs2RHRZ.js → globals-RKxmETMG.js} +12 -12
- package/extension/chrome-mv3/chunks/{popup-eocjPmx2.js → popup-DBnq_NvX.js} +1 -1
- package/extension/chrome-mv3/chunks/{sidepanel-CgfZof6T.js → sidepanel-CrG8wCdP.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 +3 -3
- package/extension/chrome-mv3/sidepanel.html +3 -3
- package/package.json +7 -3
- package/skills/browser-control.md +9 -1
- package/extension/chrome-mv3/assets/globals-Bj_wgW8U.css +0 -2
package/dist/cli.js
CHANGED
|
@@ -2131,7 +2131,7 @@ var require_extension = __commonJS({
|
|
|
2131
2131
|
let inQuotes = false;
|
|
2132
2132
|
let extensionName;
|
|
2133
2133
|
let paramName;
|
|
2134
|
-
let
|
|
2134
|
+
let start2 = -1;
|
|
2135
2135
|
let code = -1;
|
|
2136
2136
|
let end = -1;
|
|
2137
2137
|
let i = 0;
|
|
@@ -2139,45 +2139,45 @@ var require_extension = __commonJS({
|
|
|
2139
2139
|
code = header.charCodeAt(i);
|
|
2140
2140
|
if (extensionName === void 0) {
|
|
2141
2141
|
if (end === -1 && tokenChars[code] === 1) {
|
|
2142
|
-
if (
|
|
2142
|
+
if (start2 === -1) start2 = i;
|
|
2143
2143
|
} else if (i !== 0 && (code === 32 || code === 9)) {
|
|
2144
|
-
if (end === -1 &&
|
|
2144
|
+
if (end === -1 && start2 !== -1) end = i;
|
|
2145
2145
|
} else if (code === 59 || code === 44) {
|
|
2146
|
-
if (
|
|
2146
|
+
if (start2 === -1) {
|
|
2147
2147
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2148
2148
|
}
|
|
2149
2149
|
if (end === -1) end = i;
|
|
2150
|
-
const name = header.slice(
|
|
2150
|
+
const name = header.slice(start2, end);
|
|
2151
2151
|
if (code === 44) {
|
|
2152
2152
|
push(offers, name, params);
|
|
2153
2153
|
params = /* @__PURE__ */ Object.create(null);
|
|
2154
2154
|
} else {
|
|
2155
2155
|
extensionName = name;
|
|
2156
2156
|
}
|
|
2157
|
-
|
|
2157
|
+
start2 = end = -1;
|
|
2158
2158
|
} else {
|
|
2159
2159
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2160
2160
|
}
|
|
2161
2161
|
} else if (paramName === void 0) {
|
|
2162
2162
|
if (end === -1 && tokenChars[code] === 1) {
|
|
2163
|
-
if (
|
|
2163
|
+
if (start2 === -1) start2 = i;
|
|
2164
2164
|
} else if (code === 32 || code === 9) {
|
|
2165
|
-
if (end === -1 &&
|
|
2165
|
+
if (end === -1 && start2 !== -1) end = i;
|
|
2166
2166
|
} else if (code === 59 || code === 44) {
|
|
2167
|
-
if (
|
|
2167
|
+
if (start2 === -1) {
|
|
2168
2168
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2169
2169
|
}
|
|
2170
2170
|
if (end === -1) end = i;
|
|
2171
|
-
push(params, header.slice(
|
|
2171
|
+
push(params, header.slice(start2, end), true);
|
|
2172
2172
|
if (code === 44) {
|
|
2173
2173
|
push(offers, extensionName, params);
|
|
2174
2174
|
params = /* @__PURE__ */ Object.create(null);
|
|
2175
2175
|
extensionName = void 0;
|
|
2176
2176
|
}
|
|
2177
|
-
|
|
2178
|
-
} else if (code === 61 &&
|
|
2179
|
-
paramName = header.slice(
|
|
2180
|
-
|
|
2177
|
+
start2 = end = -1;
|
|
2178
|
+
} else if (code === 61 && start2 !== -1 && end === -1) {
|
|
2179
|
+
paramName = header.slice(start2, i);
|
|
2180
|
+
start2 = end = -1;
|
|
2181
2181
|
} else {
|
|
2182
2182
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2183
2183
|
}
|
|
@@ -2186,13 +2186,13 @@ var require_extension = __commonJS({
|
|
|
2186
2186
|
if (tokenChars[code] !== 1) {
|
|
2187
2187
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2188
2188
|
}
|
|
2189
|
-
if (
|
|
2189
|
+
if (start2 === -1) start2 = i;
|
|
2190
2190
|
else if (!mustUnescape) mustUnescape = true;
|
|
2191
2191
|
isEscaping = false;
|
|
2192
2192
|
} else if (inQuotes) {
|
|
2193
2193
|
if (tokenChars[code] === 1) {
|
|
2194
|
-
if (
|
|
2195
|
-
} else if (code === 34 &&
|
|
2194
|
+
if (start2 === -1) start2 = i;
|
|
2195
|
+
} else if (code === 34 && start2 !== -1) {
|
|
2196
2196
|
inQuotes = false;
|
|
2197
2197
|
end = i;
|
|
2198
2198
|
} else if (code === 92) {
|
|
@@ -2203,15 +2203,15 @@ var require_extension = __commonJS({
|
|
|
2203
2203
|
} else if (code === 34 && header.charCodeAt(i - 1) === 61) {
|
|
2204
2204
|
inQuotes = true;
|
|
2205
2205
|
} else if (end === -1 && tokenChars[code] === 1) {
|
|
2206
|
-
if (
|
|
2207
|
-
} else if (
|
|
2206
|
+
if (start2 === -1) start2 = i;
|
|
2207
|
+
} else if (start2 !== -1 && (code === 32 || code === 9)) {
|
|
2208
2208
|
if (end === -1) end = i;
|
|
2209
2209
|
} else if (code === 59 || code === 44) {
|
|
2210
|
-
if (
|
|
2210
|
+
if (start2 === -1) {
|
|
2211
2211
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2212
2212
|
}
|
|
2213
2213
|
if (end === -1) end = i;
|
|
2214
|
-
let value = header.slice(
|
|
2214
|
+
let value = header.slice(start2, end);
|
|
2215
2215
|
if (mustUnescape) {
|
|
2216
2216
|
value = value.replace(/\\/g, "");
|
|
2217
2217
|
mustUnescape = false;
|
|
@@ -2223,17 +2223,17 @@ var require_extension = __commonJS({
|
|
|
2223
2223
|
extensionName = void 0;
|
|
2224
2224
|
}
|
|
2225
2225
|
paramName = void 0;
|
|
2226
|
-
|
|
2226
|
+
start2 = end = -1;
|
|
2227
2227
|
} else {
|
|
2228
2228
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2229
2229
|
}
|
|
2230
2230
|
}
|
|
2231
2231
|
}
|
|
2232
|
-
if (
|
|
2232
|
+
if (start2 === -1 || inQuotes || code === 32 || code === 9) {
|
|
2233
2233
|
throw new SyntaxError("Unexpected end of input");
|
|
2234
2234
|
}
|
|
2235
2235
|
if (end === -1) end = i;
|
|
2236
|
-
const token = header.slice(
|
|
2236
|
+
const token = header.slice(start2, end);
|
|
2237
2237
|
if (extensionName === void 0) {
|
|
2238
2238
|
push(offers, token, params);
|
|
2239
2239
|
} else {
|
|
@@ -3268,34 +3268,34 @@ var require_subprotocol = __commonJS({
|
|
|
3268
3268
|
var { tokenChars } = require_validation();
|
|
3269
3269
|
function parse3(header) {
|
|
3270
3270
|
const protocols = /* @__PURE__ */ new Set();
|
|
3271
|
-
let
|
|
3271
|
+
let start2 = -1;
|
|
3272
3272
|
let end = -1;
|
|
3273
3273
|
let i = 0;
|
|
3274
3274
|
for (i; i < header.length; i++) {
|
|
3275
3275
|
const code = header.charCodeAt(i);
|
|
3276
3276
|
if (end === -1 && tokenChars[code] === 1) {
|
|
3277
|
-
if (
|
|
3277
|
+
if (start2 === -1) start2 = i;
|
|
3278
3278
|
} else if (i !== 0 && (code === 32 || code === 9)) {
|
|
3279
|
-
if (end === -1 &&
|
|
3279
|
+
if (end === -1 && start2 !== -1) end = i;
|
|
3280
3280
|
} else if (code === 44) {
|
|
3281
|
-
if (
|
|
3281
|
+
if (start2 === -1) {
|
|
3282
3282
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
3283
3283
|
}
|
|
3284
3284
|
if (end === -1) end = i;
|
|
3285
|
-
const protocol2 = header.slice(
|
|
3285
|
+
const protocol2 = header.slice(start2, end);
|
|
3286
3286
|
if (protocols.has(protocol2)) {
|
|
3287
3287
|
throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`);
|
|
3288
3288
|
}
|
|
3289
3289
|
protocols.add(protocol2);
|
|
3290
|
-
|
|
3290
|
+
start2 = end = -1;
|
|
3291
3291
|
} else {
|
|
3292
3292
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
3293
3293
|
}
|
|
3294
3294
|
}
|
|
3295
|
-
if (
|
|
3295
|
+
if (start2 === -1 || end !== -1) {
|
|
3296
3296
|
throw new SyntaxError("Unexpected end of input");
|
|
3297
3297
|
}
|
|
3298
|
-
const protocol = header.slice(
|
|
3298
|
+
const protocol = header.slice(start2, i);
|
|
3299
3299
|
if (protocols.has(protocol)) {
|
|
3300
3300
|
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
|
|
3301
3301
|
}
|
|
@@ -11285,9 +11285,9 @@ function nullish(input2) {
|
|
|
11285
11285
|
return input2 === null || input2 === void 0;
|
|
11286
11286
|
}
|
|
11287
11287
|
function cleanRegex(source) {
|
|
11288
|
-
const
|
|
11288
|
+
const start2 = source.startsWith("^") ? 1 : 0;
|
|
11289
11289
|
const end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
11290
|
-
return source.slice(
|
|
11290
|
+
return source.slice(start2, end);
|
|
11291
11291
|
}
|
|
11292
11292
|
function floatSafeRemainder(val, step) {
|
|
11293
11293
|
const ratio = val / step;
|
|
@@ -14773,9 +14773,9 @@ var $ZodTemplateLiteral = /* @__PURE__ */ $constructor("$ZodTemplateLiteral", (i
|
|
|
14773
14773
|
const source = part._zod.pattern instanceof RegExp ? part._zod.pattern.source : part._zod.pattern;
|
|
14774
14774
|
if (!source)
|
|
14775
14775
|
throw new Error(`Invalid template literal part: ${part._zod.traits}`);
|
|
14776
|
-
const
|
|
14776
|
+
const start2 = source.startsWith("^") ? 1 : 0;
|
|
14777
14777
|
const end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
14778
|
-
regexParts.push(source.slice(
|
|
14778
|
+
regexParts.push(source.slice(start2, end));
|
|
14779
14779
|
} else if (part === null || primitiveTypes.has(typeof part)) {
|
|
14780
14780
|
regexParts.push(escapeRegex(`${part}`));
|
|
14781
14781
|
} else {
|
|
@@ -27722,14 +27722,14 @@ async function travel(from, to, steps, buttons, onStep) {
|
|
|
27722
27722
|
else firePointer(elementAt(at), "pointermove", "mousemove", at, buttons);
|
|
27723
27723
|
}
|
|
27724
27724
|
}
|
|
27725
|
-
async function approachFrom(
|
|
27726
|
-
await travel(
|
|
27725
|
+
async function approachFrom(start2, grip, over) {
|
|
27726
|
+
await travel(start2, grip, APPROACH_STEPS, 0);
|
|
27727
27727
|
hoverSequence(over ?? document.body, grip);
|
|
27728
27728
|
}
|
|
27729
27729
|
async function pointerDrag(source, plan) {
|
|
27730
|
-
const { approach:
|
|
27730
|
+
const { approach: start2, grip, drop, steps, holdMs, settleMs } = plan;
|
|
27731
27731
|
const held = source ?? elementAt(grip);
|
|
27732
|
-
await approachFrom(
|
|
27732
|
+
await approachFrom(start2, grip, held);
|
|
27733
27733
|
firePointer(held, "pointerdown", "mousedown", grip, 1);
|
|
27734
27734
|
await settle(holdMs);
|
|
27735
27735
|
await travel(grip, drop, steps, 1);
|
|
@@ -27739,9 +27739,9 @@ async function pointerDrag(source, plan) {
|
|
|
27739
27739
|
return { landedOn: landing ? cssPath(landing) : void 0 };
|
|
27740
27740
|
}
|
|
27741
27741
|
async function nativeDrag(source, plan) {
|
|
27742
|
-
const { approach:
|
|
27742
|
+
const { approach: start2, grip, drop, steps, holdMs, settleMs } = plan;
|
|
27743
27743
|
const dataTransfer = new DataTransfer();
|
|
27744
|
-
await approachFrom(
|
|
27744
|
+
await approachFrom(start2, grip, source);
|
|
27745
27745
|
firePointer(source, "pointerdown", "mousedown", grip, 1);
|
|
27746
27746
|
await settle(holdMs);
|
|
27747
27747
|
const started = fireDrag(source, "dragstart", grip, dataTransfer);
|
|
@@ -27836,14 +27836,14 @@ function digestOf(text3) {
|
|
|
27836
27836
|
}
|
|
27837
27837
|
return (hash3 >>> 0).toString(16).padStart(8, "0");
|
|
27838
27838
|
}
|
|
27839
|
-
function groupEnd(text3,
|
|
27840
|
-
if (text3.length -
|
|
27841
|
-
const window2 = text3.slice(
|
|
27839
|
+
function groupEnd(text3, start2, budget) {
|
|
27840
|
+
if (text3.length - start2 <= budget) return text3.length;
|
|
27841
|
+
const window2 = text3.slice(start2, start2 + budget);
|
|
27842
27842
|
for (const { pattern, floor } of BOUNDARIES) {
|
|
27843
27843
|
const cut = lastBoundary(window2, pattern, Math.floor(budget * floor));
|
|
27844
|
-
if (cut > 0) return
|
|
27844
|
+
if (cut > 0) return start2 + cut;
|
|
27845
27845
|
}
|
|
27846
|
-
return
|
|
27846
|
+
return start2 + budget;
|
|
27847
27847
|
}
|
|
27848
27848
|
function writeCursor(offset, delivered) {
|
|
27849
27849
|
return `${offset}.${digestOf(delivered)}`;
|
|
@@ -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;
|
|
@@ -28906,12 +28967,12 @@ var pressKey = defineAction({
|
|
|
28906
28967
|
el.dispatchEvent(new KeyboardEvent("keypress", init));
|
|
28907
28968
|
}
|
|
28908
28969
|
if (printable && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)) {
|
|
28909
|
-
const
|
|
28970
|
+
const start2 = el.selectionStart ?? el.value.length;
|
|
28910
28971
|
const end = el.selectionEnd ?? el.value.length;
|
|
28911
|
-
const next = el.value.slice(0,
|
|
28972
|
+
const next = el.value.slice(0, start2) + key + el.value.slice(end);
|
|
28912
28973
|
const proto = el instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype;
|
|
28913
28974
|
Object.getOwnPropertyDescriptor(proto, "value")?.set?.call(el, next);
|
|
28914
|
-
const caret =
|
|
28975
|
+
const caret = start2 + key.length;
|
|
28915
28976
|
try {
|
|
28916
28977
|
el.setSelectionRange(caret, caret);
|
|
28917
28978
|
} catch {
|
|
@@ -29789,7 +29850,7 @@ var typeText = defineAction({
|
|
|
29789
29850
|
}
|
|
29790
29851
|
if (clear) clearContent(el);
|
|
29791
29852
|
focusForTyping(el);
|
|
29792
|
-
const
|
|
29853
|
+
const start2 = performance.now();
|
|
29793
29854
|
const characters = [...text3];
|
|
29794
29855
|
for (const [index, char] of characters.entries()) {
|
|
29795
29856
|
const wait = index ? Math.round(delays[index - 1] * (1 + (Math.random() * 2 - 1) * jitter)) : 0;
|
|
@@ -29811,7 +29872,7 @@ var typeText = defineAction({
|
|
|
29811
29872
|
element: describeElement(el),
|
|
29812
29873
|
typed: characters.length,
|
|
29813
29874
|
charDelayMs: base,
|
|
29814
|
-
elapsedMs: Math.round(performance.now() -
|
|
29875
|
+
elapsedMs: Math.round(performance.now() - start2),
|
|
29815
29876
|
appended: !clear,
|
|
29816
29877
|
submitted
|
|
29817
29878
|
};
|
|
@@ -29845,10 +29906,10 @@ function focusForTyping(el) {
|
|
|
29845
29906
|
}
|
|
29846
29907
|
function insertCharacter(el, char) {
|
|
29847
29908
|
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
|
|
29848
|
-
const
|
|
29909
|
+
const start2 = el.selectionStart ?? el.value.length;
|
|
29849
29910
|
const end = el.selectionEnd ?? el.value.length;
|
|
29850
|
-
setNativeValue(el, el.value.slice(0,
|
|
29851
|
-
const caret =
|
|
29911
|
+
setNativeValue(el, el.value.slice(0, start2) + char + el.value.slice(end));
|
|
29912
|
+
const caret = start2 + char.length;
|
|
29852
29913
|
try {
|
|
29853
29914
|
el.setSelectionRange(caret, caret);
|
|
29854
29915
|
} catch {
|
|
@@ -29894,7 +29955,7 @@ var waitForElement = defineAction({
|
|
|
29894
29955
|
hidden: !el || !isVisible(el),
|
|
29895
29956
|
detached: !el
|
|
29896
29957
|
})[state];
|
|
29897
|
-
const
|
|
29958
|
+
const start2 = performance.now();
|
|
29898
29959
|
let element = find();
|
|
29899
29960
|
if (satisfied(element)) {
|
|
29900
29961
|
return { state, elapsedMs: 0, element: element ? describeElement(element) : void 0 };
|
|
@@ -29927,7 +29988,7 @@ var waitForElement = defineAction({
|
|
|
29927
29988
|
});
|
|
29928
29989
|
return {
|
|
29929
29990
|
state,
|
|
29930
|
-
elapsedMs: Math.round(performance.now() -
|
|
29991
|
+
elapsedMs: Math.round(performance.now() - start2),
|
|
29931
29992
|
element: element ? describeElement(element) : void 0
|
|
29932
29993
|
};
|
|
29933
29994
|
}
|
|
@@ -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,
|
|
@@ -30229,6 +30291,21 @@ function settingsFor(stored, kind) {
|
|
|
30229
30291
|
};
|
|
30230
30292
|
}
|
|
30231
30293
|
var text = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
30294
|
+
function writeAgentModel(kind, model) {
|
|
30295
|
+
const stored = readStored();
|
|
30296
|
+
const agents = { ...stored.agents ?? {} };
|
|
30297
|
+
const scoped = { ...agents[kind] ?? {} };
|
|
30298
|
+
const value = text(model);
|
|
30299
|
+
if (value) scoped.model = value;
|
|
30300
|
+
else delete scoped.model;
|
|
30301
|
+
if (Object.keys(scoped).length) agents[kind] = scoped;
|
|
30302
|
+
else delete agents[kind];
|
|
30303
|
+
const next = { ...stored };
|
|
30304
|
+
if (Object.keys(agents).length) next.agents = agents;
|
|
30305
|
+
else delete next.agents;
|
|
30306
|
+
if (kind === "claude") delete next.model;
|
|
30307
|
+
write(next);
|
|
30308
|
+
}
|
|
30232
30309
|
function write(config2) {
|
|
30233
30310
|
mkdirSync3(stateDir, { recursive: true, mode: 448 });
|
|
30234
30311
|
writeFileSync2(configPath, `${JSON.stringify(config2, null, 2)}
|
|
@@ -31836,9 +31913,11 @@ import { homedir as homedir7 } from "os";
|
|
|
31836
31913
|
import { dirname as dirname6, join as join15, resolve, sep as sep2 } from "path";
|
|
31837
31914
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
31838
31915
|
var packageRoot = resolve(dirname6(fileURLToPath5(import.meta.url)), "..");
|
|
31916
|
+
var APP_MARKER = ".browsentic-app.json";
|
|
31839
31917
|
var inNpxCache = (path) => path.split(sep2).includes("_npx");
|
|
31840
31918
|
function installKind() {
|
|
31841
31919
|
if (inNpxCache(packageRoot)) return "npx";
|
|
31920
|
+
if (existsSync5(join15(packageRoot, APP_MARKER))) return "app";
|
|
31842
31921
|
if (existsSync5(join15(packageRoot, "tsup.config.ts"))) return "repo";
|
|
31843
31922
|
return "global";
|
|
31844
31923
|
}
|
|
@@ -32047,6 +32126,13 @@ async function upgradeCli(current, forward) {
|
|
|
32047
32126
|
console.error(`
|
|
32048
32127
|
! browsentic ${latest} is published; this is ${current}, from a source checkout.`);
|
|
32049
32128
|
console.error(` Update it with "git pull && yarn setup".
|
|
32129
|
+
`);
|
|
32130
|
+
return null;
|
|
32131
|
+
}
|
|
32132
|
+
if (kind === "app") {
|
|
32133
|
+
console.error(`
|
|
32134
|
+
! browsentic ${latest} is published; this is ${current}, installed by Browsentic.app.`);
|
|
32135
|
+
console.error(` Update it from the app, which replaces the command and the extension together.
|
|
32050
32136
|
`);
|
|
32051
32137
|
return null;
|
|
32052
32138
|
}
|
|
@@ -34184,8 +34270,8 @@ function purgeNpxCache(entries) {
|
|
|
34184
34270
|
// package.json
|
|
34185
34271
|
var package_default = {
|
|
34186
34272
|
name: "browsentic",
|
|
34187
|
-
version: "0.
|
|
34188
|
-
description: "
|
|
34273
|
+
version: "0.6.0",
|
|
34274
|
+
description: "A browser extension with an AI side panel that hands your real, logged-in browser to the AI agent you already run. Installs the extension, runs the local daemon, and optionally speaks MCP.",
|
|
34189
34275
|
type: "module",
|
|
34190
34276
|
license: "MIT",
|
|
34191
34277
|
packageManager: "yarn@4.17.1",
|
|
@@ -34197,8 +34283,12 @@ var package_default = {
|
|
|
34197
34283
|
},
|
|
34198
34284
|
bugs: "https://github.com/imshaikot/browsentic/issues",
|
|
34199
34285
|
keywords: [
|
|
34200
|
-
"browser-
|
|
34286
|
+
"browser-extension",
|
|
34201
34287
|
"chrome-extension",
|
|
34288
|
+
"ai-browser-extension",
|
|
34289
|
+
"side-panel",
|
|
34290
|
+
"browser-agent",
|
|
34291
|
+
"browser-automation",
|
|
34202
34292
|
"ai-agent",
|
|
34203
34293
|
"agentic-browsing",
|
|
34204
34294
|
"mcp",
|
|
@@ -34251,6 +34341,7 @@ var USAGE = `browsentic ${package_default.version} \u2014 hand your real browser
|
|
|
34251
34341
|
browsentic agent show which agent runs the side panel, and which are installed
|
|
34252
34342
|
browsentic agent <name> switch to claude, codex or antigravity
|
|
34253
34343
|
browsentic agent fix <name> let Browsentic fix what that agent still needs
|
|
34344
|
+
browsentic agent model <name> [model] pin that agent's model, or omit it for the CLI's default
|
|
34254
34345
|
|
|
34255
34346
|
browsentic skills list the skills the agent can route to, and where they came from
|
|
34256
34347
|
browsentic approvals list the \u201Calways on this site\u201D approvals you have granted
|
|
@@ -34259,9 +34350,12 @@ var USAGE = `browsentic ${package_default.version} \u2014 hand your real browser
|
|
|
34259
34350
|
browsentic downloads clear delete all of them
|
|
34260
34351
|
browsentic tools print the bundled tool manifest (no browser needed)
|
|
34261
34352
|
browsentic logs print the daemon log
|
|
34353
|
+
browsentic start bring the background daemon up, if it is not already
|
|
34262
34354
|
browsentic stop stop the background daemon
|
|
34263
34355
|
browsentic restart stop the daemon and bring up a fresh one
|
|
34264
34356
|
browsentic token print the control token (for MCP clients, not the browser)
|
|
34357
|
+
|
|
34358
|
+
agent, skills, approvals and downloads take --json, which is what the macOS app reads.
|
|
34265
34359
|
browsentic --version print the version
|
|
34266
34360
|
|
|
34267
34361
|
Getting started: browsentic setup
|
|
@@ -34273,6 +34367,8 @@ For MCP clients
|
|
|
34273
34367
|
var invokedAs = basename3(process.argv[1] ?? "").replace(/\.(?:js|cjs|mjs|exe|cmd|ps1)$/i, "");
|
|
34274
34368
|
var servesBare = invokedAs === "browsentic-mcp" || !!process.env.BROWSENTIC_AGENT_RUN;
|
|
34275
34369
|
var [command] = process.argv.slice(2);
|
|
34370
|
+
var wantsJson = process.argv.includes("--json");
|
|
34371
|
+
var positional = process.argv.slice(3).filter((arg) => !arg.startsWith("--"));
|
|
34276
34372
|
switch (command) {
|
|
34277
34373
|
case void 0:
|
|
34278
34374
|
if (servesBare) await serve();
|
|
@@ -34300,7 +34396,7 @@ switch (command) {
|
|
|
34300
34396
|
await revoke(process.argv[3]);
|
|
34301
34397
|
break;
|
|
34302
34398
|
case "agent":
|
|
34303
|
-
await chooseAgent(
|
|
34399
|
+
await chooseAgent(positional[0], positional[1], positional[2]);
|
|
34304
34400
|
break;
|
|
34305
34401
|
case "tools":
|
|
34306
34402
|
printTools();
|
|
@@ -34308,6 +34404,9 @@ switch (command) {
|
|
|
34308
34404
|
case "status":
|
|
34309
34405
|
await showStatus();
|
|
34310
34406
|
break;
|
|
34407
|
+
case "start":
|
|
34408
|
+
await start();
|
|
34409
|
+
break;
|
|
34311
34410
|
case "stop":
|
|
34312
34411
|
await stop();
|
|
34313
34412
|
break;
|
|
@@ -34318,10 +34417,10 @@ switch (command) {
|
|
|
34318
34417
|
printSkills();
|
|
34319
34418
|
break;
|
|
34320
34419
|
case "approvals":
|
|
34321
|
-
manageApprovals(
|
|
34420
|
+
manageApprovals(positional[0], positional[1]);
|
|
34322
34421
|
break;
|
|
34323
34422
|
case "downloads":
|
|
34324
|
-
manageDownloads(
|
|
34423
|
+
manageDownloads(positional[0]);
|
|
34325
34424
|
break;
|
|
34326
34425
|
case "logs":
|
|
34327
34426
|
showLogs();
|
|
@@ -34370,6 +34469,16 @@ function printTools() {
|
|
|
34370
34469
|
}
|
|
34371
34470
|
function printSkills() {
|
|
34372
34471
|
const skills = loadSkills();
|
|
34472
|
+
if (wantsJson) {
|
|
34473
|
+
const config3 = readAgentConfig();
|
|
34474
|
+
const listed = skills.map(({ body: _body, ...skill }) => ({
|
|
34475
|
+
...skill,
|
|
34476
|
+
path: skill.provenance === "generated" ? join18(uploadedSkillsDir(), skill.name) : void 0
|
|
34477
|
+
}));
|
|
34478
|
+
const own2 = agentSkills(config3).map(({ name, description }) => ({ name, description }));
|
|
34479
|
+
console.log(JSON.stringify({ skills: listed, dirs: skillDirNames(), agent: config3.agent, agentSkills: own2 }, null, 2));
|
|
34480
|
+
return;
|
|
34481
|
+
}
|
|
34373
34482
|
if (!skills.length) {
|
|
34374
34483
|
console.log(`No skills found. Looked in:
|
|
34375
34484
|
${skillDirNames().join("\n ")}`);
|
|
@@ -34440,6 +34549,10 @@ async function stop() {
|
|
|
34440
34549
|
if (!stopped.length && !stubborn.length) console.log("No daemon is answering; nothing to stop.");
|
|
34441
34550
|
if (stubborn.length) process.exitCode = 1;
|
|
34442
34551
|
}
|
|
34552
|
+
async function start() {
|
|
34553
|
+
const lock = await ensureDaemon();
|
|
34554
|
+
console.log(`Daemon running on 127.0.0.1:${lock.port} (pid ${lock.pid}, v${lock.daemonVersion}).`);
|
|
34555
|
+
}
|
|
34443
34556
|
async function restart() {
|
|
34444
34557
|
const { stubborn } = await stopDaemons();
|
|
34445
34558
|
if (stubborn.length) {
|
|
@@ -34610,6 +34723,7 @@ async function uninstall(argv) {
|
|
|
34610
34723
|
console.log(" live in extension storage rather than on disk.");
|
|
34611
34724
|
if (kind === "global") console.log("\n the command itself: npm rm -g browsentic");
|
|
34612
34725
|
if (kind === "repo") console.log("\n the global link: yarn daemon:unlink");
|
|
34726
|
+
if (kind === "app") console.log("\n the app itself: drag Browsentic.app from Applications to the Trash");
|
|
34613
34727
|
console.log("\n the entry in your MCP client, e.g. claude mcp remove browsentic");
|
|
34614
34728
|
if (flag("dry-run")) {
|
|
34615
34729
|
console.log("\n --dry-run: nothing was removed.\n");
|
|
@@ -34665,7 +34779,15 @@ async function showSessions() {
|
|
|
34665
34779
|
console.log(` extension v${session.extensionVersion}, paired ${session.pairedAt}, last seen ${session.lastSeenAt}`);
|
|
34666
34780
|
}
|
|
34667
34781
|
}
|
|
34668
|
-
async function chooseAgent(first, second) {
|
|
34782
|
+
async function chooseAgent(first, second, third) {
|
|
34783
|
+
if (first === "model") {
|
|
34784
|
+
if (!isAgentKind(second)) {
|
|
34785
|
+
console.error(`Name the agent whose model to set. Pick one of: ${AGENT_KINDS.join(", ")}`);
|
|
34786
|
+
process.exit(1);
|
|
34787
|
+
}
|
|
34788
|
+
writeAgentModel(second, third ?? null);
|
|
34789
|
+
first = second = void 0;
|
|
34790
|
+
}
|
|
34669
34791
|
const grant = first === "fix" || first === "setup";
|
|
34670
34792
|
const named = grant ? second : first;
|
|
34671
34793
|
if (named !== void 0 && !isAgentKind(named)) {
|
|
@@ -34676,6 +34798,10 @@ async function chooseAgent(first, second) {
|
|
|
34676
34798
|
const bridge = await connect();
|
|
34677
34799
|
const state = await bridge.agent(kind && (grant ? { grant: kind } : { set: kind }));
|
|
34678
34800
|
await bridge.close();
|
|
34801
|
+
if (wantsJson) {
|
|
34802
|
+
console.log(JSON.stringify({ ...state, catalog: AGENT_LIST }, null, 2));
|
|
34803
|
+
return;
|
|
34804
|
+
}
|
|
34679
34805
|
for (const runner of state.runners) {
|
|
34680
34806
|
const agent = AGENTS[runner.kind];
|
|
34681
34807
|
const mark = runner.kind === state.active ? "\u25CF" : "\u25CB";
|
|
@@ -34713,6 +34839,10 @@ function manageDownloads(sub) {
|
|
|
34713
34839
|
return;
|
|
34714
34840
|
}
|
|
34715
34841
|
const downloads = storedDownloads();
|
|
34842
|
+
if (wantsJson) {
|
|
34843
|
+
console.log(JSON.stringify({ dir: downloadDir(), downloads }, null, 2));
|
|
34844
|
+
return;
|
|
34845
|
+
}
|
|
34716
34846
|
if (!downloads.length) {
|
|
34717
34847
|
console.log(`Nothing captured. Files land in ${downloadDir()} when an agent uses page.captureDownload.`);
|
|
34718
34848
|
return;
|
|
@@ -34738,6 +34868,10 @@ function manageApprovals(sub, host) {
|
|
|
34738
34868
|
return;
|
|
34739
34869
|
}
|
|
34740
34870
|
const grants = listGrants();
|
|
34871
|
+
if (wantsJson) {
|
|
34872
|
+
console.log(JSON.stringify({ grants }, null, 2));
|
|
34873
|
+
return;
|
|
34874
|
+
}
|
|
34741
34875
|
if (!grants.length) {
|
|
34742
34876
|
console.log("No standing approvals. Every gated action still asks.");
|
|
34743
34877
|
return;
|