browsentic 0.4.13 → 0.4.15
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 +432 -92
- package/dist/daemon-main.js +3 -3
- package/extension/chrome-mv3/assets/globals-Bj_wgW8U.css +2 -0
- package/extension/chrome-mv3/background.js +2 -2
- package/extension/chrome-mv3/chunks/{globals-B4qbR8F8.js → globals-NNs2RHRZ.js} +1 -1
- package/extension/chrome-mv3/chunks/popup-eocjPmx2.js +1 -0
- package/extension/chrome-mv3/chunks/sidepanel-CgfZof6T.js +11 -0
- package/extension/chrome-mv3/content-scripts/content.js +101 -19
- 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 +1 -1
- package/extension/chrome-mv3/assets/globals-DEu7-bvL.css +0 -2
- package/extension/chrome-mv3/chunks/popup-CBHYDoU5.js +0 -1
- package/extension/chrome-mv3/chunks/sidepanel-CdI2mAPj.js +0 -11
package/dist/cli.js
CHANGED
|
@@ -2276,7 +2276,7 @@ var require_websocket = __commonJS({
|
|
|
2276
2276
|
var http = __require("http");
|
|
2277
2277
|
var net = __require("net");
|
|
2278
2278
|
var tls = __require("tls");
|
|
2279
|
-
var { randomBytes:
|
|
2279
|
+
var { randomBytes: randomBytes4, createHash: createHash3 } = __require("crypto");
|
|
2280
2280
|
var { Duplex, Readable } = __require("stream");
|
|
2281
2281
|
var { URL: URL2 } = __require("url");
|
|
2282
2282
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2814,7 +2814,7 @@ var require_websocket = __commonJS({
|
|
|
2814
2814
|
}
|
|
2815
2815
|
}
|
|
2816
2816
|
const defaultPort = isSecure ? 443 : 80;
|
|
2817
|
-
const key =
|
|
2817
|
+
const key = randomBytes4(16).toString("base64");
|
|
2818
2818
|
const request = isSecure ? https.request : http.request;
|
|
2819
2819
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
2820
2820
|
let perMessageDeflate;
|
|
@@ -6658,7 +6658,7 @@ var require_compile = __commonJS({
|
|
|
6658
6658
|
const schOrFunc = root.refs[ref];
|
|
6659
6659
|
if (schOrFunc)
|
|
6660
6660
|
return schOrFunc;
|
|
6661
|
-
let _sch =
|
|
6661
|
+
let _sch = resolve3.call(this, root, ref);
|
|
6662
6662
|
if (_sch === void 0) {
|
|
6663
6663
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
6664
6664
|
const { schemaId } = this.opts;
|
|
@@ -6685,7 +6685,7 @@ var require_compile = __commonJS({
|
|
|
6685
6685
|
function sameSchemaEnv(s1, s2) {
|
|
6686
6686
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
6687
6687
|
}
|
|
6688
|
-
function
|
|
6688
|
+
function resolve3(root, ref) {
|
|
6689
6689
|
let sch;
|
|
6690
6690
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
6691
6691
|
ref = sch;
|
|
@@ -7316,55 +7316,55 @@ var require_fast_uri = __commonJS({
|
|
|
7316
7316
|
}
|
|
7317
7317
|
return uri;
|
|
7318
7318
|
}
|
|
7319
|
-
function
|
|
7319
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
7320
7320
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
7321
7321
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
7322
7322
|
schemelessOptions.skipEscape = true;
|
|
7323
7323
|
return serialize(resolved, schemelessOptions);
|
|
7324
7324
|
}
|
|
7325
|
-
function resolveComponent(base,
|
|
7325
|
+
function resolveComponent(base, relative3, options, skipNormalization) {
|
|
7326
7326
|
const target = {};
|
|
7327
7327
|
if (!skipNormalization) {
|
|
7328
7328
|
base = parse3(serialize(base, options), options);
|
|
7329
|
-
|
|
7329
|
+
relative3 = parse3(serialize(relative3, options), options);
|
|
7330
7330
|
}
|
|
7331
7331
|
options = options || {};
|
|
7332
|
-
if (!options.tolerant &&
|
|
7333
|
-
target.scheme =
|
|
7334
|
-
target.userinfo =
|
|
7335
|
-
target.host =
|
|
7336
|
-
target.port =
|
|
7337
|
-
target.path = removeDotSegments(
|
|
7338
|
-
target.query =
|
|
7332
|
+
if (!options.tolerant && relative3.scheme) {
|
|
7333
|
+
target.scheme = relative3.scheme;
|
|
7334
|
+
target.userinfo = relative3.userinfo;
|
|
7335
|
+
target.host = relative3.host;
|
|
7336
|
+
target.port = relative3.port;
|
|
7337
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
7338
|
+
target.query = relative3.query;
|
|
7339
7339
|
} else {
|
|
7340
|
-
if (
|
|
7341
|
-
target.userinfo =
|
|
7342
|
-
target.host =
|
|
7343
|
-
target.port =
|
|
7344
|
-
target.path = removeDotSegments(
|
|
7345
|
-
target.query =
|
|
7340
|
+
if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
|
|
7341
|
+
target.userinfo = relative3.userinfo;
|
|
7342
|
+
target.host = relative3.host;
|
|
7343
|
+
target.port = relative3.port;
|
|
7344
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
7345
|
+
target.query = relative3.query;
|
|
7346
7346
|
} else {
|
|
7347
|
-
if (!
|
|
7347
|
+
if (!relative3.path) {
|
|
7348
7348
|
target.path = base.path;
|
|
7349
|
-
if (
|
|
7350
|
-
target.query =
|
|
7349
|
+
if (relative3.query !== void 0) {
|
|
7350
|
+
target.query = relative3.query;
|
|
7351
7351
|
} else {
|
|
7352
7352
|
target.query = base.query;
|
|
7353
7353
|
}
|
|
7354
7354
|
} else {
|
|
7355
|
-
if (
|
|
7356
|
-
target.path = removeDotSegments(
|
|
7355
|
+
if (relative3.path[0] === "/") {
|
|
7356
|
+
target.path = removeDotSegments(relative3.path);
|
|
7357
7357
|
} else {
|
|
7358
7358
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
7359
|
-
target.path = "/" +
|
|
7359
|
+
target.path = "/" + relative3.path;
|
|
7360
7360
|
} else if (!base.path) {
|
|
7361
|
-
target.path =
|
|
7361
|
+
target.path = relative3.path;
|
|
7362
7362
|
} else {
|
|
7363
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
7363
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
|
|
7364
7364
|
}
|
|
7365
7365
|
target.path = removeDotSegments(target.path);
|
|
7366
7366
|
}
|
|
7367
|
-
target.query =
|
|
7367
|
+
target.query = relative3.query;
|
|
7368
7368
|
}
|
|
7369
7369
|
target.userinfo = base.userinfo;
|
|
7370
7370
|
target.host = base.host;
|
|
@@ -7372,7 +7372,7 @@ var require_fast_uri = __commonJS({
|
|
|
7372
7372
|
}
|
|
7373
7373
|
target.scheme = base.scheme;
|
|
7374
7374
|
}
|
|
7375
|
-
target.fragment =
|
|
7375
|
+
target.fragment = relative3.fragment;
|
|
7376
7376
|
return target;
|
|
7377
7377
|
}
|
|
7378
7378
|
function equal(uriA, uriB, options) {
|
|
@@ -7580,7 +7580,7 @@ var require_fast_uri = __commonJS({
|
|
|
7580
7580
|
var fastUri = {
|
|
7581
7581
|
SCHEMES,
|
|
7582
7582
|
normalize,
|
|
7583
|
-
resolve,
|
|
7583
|
+
resolve: resolve3,
|
|
7584
7584
|
resolveComponent,
|
|
7585
7585
|
equal,
|
|
7586
7586
|
serialize,
|
|
@@ -10570,7 +10570,8 @@ var require_dist = __commonJS({
|
|
|
10570
10570
|
});
|
|
10571
10571
|
|
|
10572
10572
|
// cli.ts
|
|
10573
|
-
import { readFileSync as
|
|
10573
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
10574
|
+
import { createInterface } from "readline/promises";
|
|
10574
10575
|
|
|
10575
10576
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
10576
10577
|
import process3 from "process";
|
|
@@ -26686,12 +26687,12 @@ var StdioServerTransport = class {
|
|
|
26686
26687
|
this.onclose?.();
|
|
26687
26688
|
}
|
|
26688
26689
|
send(message) {
|
|
26689
|
-
return new Promise((
|
|
26690
|
+
return new Promise((resolve3) => {
|
|
26690
26691
|
const json2 = serializeMessage(message);
|
|
26691
26692
|
if (this._stdout.write(json2)) {
|
|
26692
|
-
|
|
26693
|
+
resolve3();
|
|
26693
26694
|
} else {
|
|
26694
|
-
this._stdout.once("drain",
|
|
26695
|
+
this._stdout.once("drain", resolve3);
|
|
26695
26696
|
}
|
|
26696
26697
|
});
|
|
26697
26698
|
}
|
|
@@ -27680,7 +27681,7 @@ function hoverSequence(el, at) {
|
|
|
27680
27681
|
|
|
27681
27682
|
// ../lib/actions/page/drag-element.ts
|
|
27682
27683
|
var FRAME_MS = 16;
|
|
27683
|
-
var settle = (ms) => new Promise((
|
|
27684
|
+
var settle = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
27684
27685
|
function mouseInit(at, buttons) {
|
|
27685
27686
|
return {
|
|
27686
27687
|
clientX: at.x,
|
|
@@ -28392,8 +28393,8 @@ function renderDiagram(regions) {
|
|
|
28392
28393
|
const walk2 = (nodes, indent) => {
|
|
28393
28394
|
nodes.forEach((region, i) => {
|
|
28394
28395
|
const last = i === nodes.length - 1;
|
|
28395
|
-
const { bounds, contains } = region;
|
|
28396
|
-
const counts = ["links", "buttons", "fields"].filter((kind) =>
|
|
28396
|
+
const { bounds, contains: contains2 } = region;
|
|
28397
|
+
const counts = ["links", "buttons", "fields"].filter((kind) => contains2[kind] > 0).map((kind) => ` \xB7 ${contains2[kind]} ${kind}`).join("");
|
|
28397
28398
|
lines.push(
|
|
28398
28399
|
`${indent}${last ? "\u2514" : "\u251C"} ${regionName(region)} \xB7 ${bounds.width}\xD7${bounds.height} @ (${bounds.x},${bounds.y})${counts}`
|
|
28399
28400
|
);
|
|
@@ -28698,7 +28699,7 @@ function pickWithLens({ hint, timeoutMs }) {
|
|
|
28698
28699
|
const box = root.querySelector(".box");
|
|
28699
28700
|
const chip = root.querySelector(".chip");
|
|
28700
28701
|
let hovered = null;
|
|
28701
|
-
return new Promise((
|
|
28702
|
+
return new Promise((resolve3) => {
|
|
28702
28703
|
const dismiss = () => settle2({ cancelled: true });
|
|
28703
28704
|
dismissCurrent = dismiss;
|
|
28704
28705
|
const timer = setTimeout(() => settle2({ timedOut: true }), timeoutMs);
|
|
@@ -28766,7 +28767,7 @@ function pickWithLens({ hint, timeoutMs }) {
|
|
|
28766
28767
|
host.remove();
|
|
28767
28768
|
cursor.remove();
|
|
28768
28769
|
if (dismissCurrent === dismiss) dismissCurrent = null;
|
|
28769
|
-
|
|
28770
|
+
resolve3(outcome);
|
|
28770
28771
|
}
|
|
28771
28772
|
});
|
|
28772
28773
|
}
|
|
@@ -29201,12 +29202,12 @@ function callToolkit(fn, args, timeoutMs) {
|
|
|
29201
29202
|
throw new ActionError("No toolkit is installed in this page.", TOOLKIT_MISSING);
|
|
29202
29203
|
}
|
|
29203
29204
|
const callId = crypto.randomUUID();
|
|
29204
|
-
return new Promise((
|
|
29205
|
+
return new Promise((resolve3, reject) => {
|
|
29205
29206
|
const onResult = (event) => {
|
|
29206
29207
|
const reply = parseReply(event.detail);
|
|
29207
29208
|
if (reply?.id !== callId) return;
|
|
29208
29209
|
stop2();
|
|
29209
|
-
if (reply.ok)
|
|
29210
|
+
if (reply.ok) resolve3(reply.value ?? null);
|
|
29210
29211
|
else reject(new ActionError(reply.error ?? "The function threw.", CODE_ERROR));
|
|
29211
29212
|
};
|
|
29212
29213
|
const timer = setTimeout(() => {
|
|
@@ -29330,11 +29331,11 @@ var scrollTo = defineAction({
|
|
|
29330
29331
|
}
|
|
29331
29332
|
});
|
|
29332
29333
|
function scrollSettled() {
|
|
29333
|
-
return new Promise((
|
|
29334
|
+
return new Promise((resolve3) => {
|
|
29334
29335
|
const done = () => {
|
|
29335
29336
|
window.removeEventListener("scrollend", done);
|
|
29336
29337
|
clearTimeout(timer);
|
|
29337
|
-
|
|
29338
|
+
resolve3();
|
|
29338
29339
|
};
|
|
29339
29340
|
const timer = setTimeout(done, 1e3);
|
|
29340
29341
|
window.addEventListener("scrollend", done);
|
|
@@ -29748,7 +29749,7 @@ var LINGER_AFTER = {
|
|
|
29748
29749
|
var MAX_DURATION_MS = 12e4;
|
|
29749
29750
|
var keyDelays = (text3, base) => [...text3].map((char) => base * (LINGER_AFTER[char] ?? 1));
|
|
29750
29751
|
var budgetFor = (delays, jitter) => Math.round(delays.reduce((total, ms) => total + ms, 0) * (1 + jitter));
|
|
29751
|
-
var pause = (ms) => new Promise((
|
|
29752
|
+
var pause = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
29752
29753
|
var typeText = defineAction({
|
|
29753
29754
|
name: "page.typeText",
|
|
29754
29755
|
description: "Stream text into a field one keystroke at a time, at a human pace \u2014 a real key event per character, pauses that vary, and longer breaths after punctuation. Use page.fillInput when you just need the value in the field; use this when the page should watch someone type.",
|
|
@@ -29898,12 +29899,12 @@ var waitForElement = defineAction({
|
|
|
29898
29899
|
if (satisfied(element)) {
|
|
29899
29900
|
return { state, elapsedMs: 0, element: element ? describeElement(element) : void 0 };
|
|
29900
29901
|
}
|
|
29901
|
-
await new Promise((
|
|
29902
|
+
await new Promise((resolve3, reject) => {
|
|
29902
29903
|
const check2 = () => {
|
|
29903
29904
|
element = find();
|
|
29904
29905
|
if (satisfied(element)) {
|
|
29905
29906
|
cleanup();
|
|
29906
|
-
|
|
29907
|
+
resolve3();
|
|
29907
29908
|
}
|
|
29908
29909
|
};
|
|
29909
29910
|
const observer = new MutationObserver(check2);
|
|
@@ -30078,7 +30079,7 @@ function assertToolNamesRoundTrip(actionNames) {
|
|
|
30078
30079
|
}
|
|
30079
30080
|
|
|
30080
30081
|
// cli.ts
|
|
30081
|
-
import { basename as
|
|
30082
|
+
import { basename as basename3, join as join18 } from "path";
|
|
30082
30083
|
|
|
30083
30084
|
// agent/agent-skills.ts
|
|
30084
30085
|
import { createHash } from "crypto";
|
|
@@ -31671,6 +31672,38 @@ async function probeExisting() {
|
|
|
31671
31672
|
}
|
|
31672
31673
|
return null;
|
|
31673
31674
|
}
|
|
31675
|
+
async function runningDaemons() {
|
|
31676
|
+
const found = /* @__PURE__ */ new Map();
|
|
31677
|
+
for (const port of DAEMON_PORTS) {
|
|
31678
|
+
const pid = await healthyPid(port);
|
|
31679
|
+
if (pid !== null && !found.has(pid)) found.set(pid, port);
|
|
31680
|
+
}
|
|
31681
|
+
return [...found].map(([pid, port]) => ({ pid, port }));
|
|
31682
|
+
}
|
|
31683
|
+
async function stopDaemons(graceMs = 5e3) {
|
|
31684
|
+
const daemons = await runningDaemons();
|
|
31685
|
+
for (const { pid } of daemons) kill(pid, "SIGTERM");
|
|
31686
|
+
const remaining = await waitForExit(daemons, graceMs);
|
|
31687
|
+
for (const { pid } of remaining) kill(pid, "SIGKILL");
|
|
31688
|
+
const stubborn = await waitForExit(remaining, 2e3);
|
|
31689
|
+
clearLockfile();
|
|
31690
|
+
return { stopped: daemons.filter((daemon) => !stubborn.includes(daemon)), stubborn };
|
|
31691
|
+
}
|
|
31692
|
+
function kill(pid, signal) {
|
|
31693
|
+
try {
|
|
31694
|
+
process.kill(pid, signal);
|
|
31695
|
+
} catch {
|
|
31696
|
+
}
|
|
31697
|
+
}
|
|
31698
|
+
async function waitForExit(daemons, timeoutMs) {
|
|
31699
|
+
const deadline = Date.now() + timeoutMs;
|
|
31700
|
+
let alive = daemons.filter((daemon) => isRunning(daemon.pid));
|
|
31701
|
+
while (alive.length && Date.now() < deadline) {
|
|
31702
|
+
await delay(POLL_INTERVAL_MS);
|
|
31703
|
+
alive = alive.filter((daemon) => isRunning(daemon.pid));
|
|
31704
|
+
}
|
|
31705
|
+
return alive;
|
|
31706
|
+
}
|
|
31674
31707
|
async function healthyPid(port) {
|
|
31675
31708
|
try {
|
|
31676
31709
|
const response = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
@@ -31684,7 +31717,7 @@ async function healthyPid(port) {
|
|
|
31684
31717
|
}
|
|
31685
31718
|
}
|
|
31686
31719
|
function delay(ms) {
|
|
31687
|
-
return new Promise((
|
|
31720
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
31688
31721
|
}
|
|
31689
31722
|
|
|
31690
31723
|
// install.ts
|
|
@@ -31797,6 +31830,71 @@ function install(dir, force = false) {
|
|
|
31797
31830
|
return { dir, version: version2, source: packaged.source, files: sources.length, changed, alreadyCurrent: false };
|
|
31798
31831
|
}
|
|
31799
31832
|
|
|
31833
|
+
// npx.ts
|
|
31834
|
+
import { existsSync as existsSync5, readFileSync as readFileSync9, readdirSync as readdirSync5, realpathSync } from "fs";
|
|
31835
|
+
import { homedir as homedir7 } from "os";
|
|
31836
|
+
import { dirname as dirname6, join as join15, resolve, sep as sep2 } from "path";
|
|
31837
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
31838
|
+
var packageRoot = resolve(dirname6(fileURLToPath5(import.meta.url)), "..");
|
|
31839
|
+
var inNpxCache = (path) => path.split(sep2).includes("_npx");
|
|
31840
|
+
function installKind() {
|
|
31841
|
+
if (inNpxCache(packageRoot)) return "npx";
|
|
31842
|
+
if (existsSync5(join15(packageRoot, "tsup.config.ts"))) return "repo";
|
|
31843
|
+
return "global";
|
|
31844
|
+
}
|
|
31845
|
+
function real(path) {
|
|
31846
|
+
try {
|
|
31847
|
+
return realpathSync(path);
|
|
31848
|
+
} catch {
|
|
31849
|
+
return path;
|
|
31850
|
+
}
|
|
31851
|
+
}
|
|
31852
|
+
function cacheRoots() {
|
|
31853
|
+
const roots = [
|
|
31854
|
+
process.env.npm_config_cache,
|
|
31855
|
+
process.platform === "win32" ? join15(process.env.LOCALAPPDATA ?? homedir7(), "npm-cache") : null,
|
|
31856
|
+
join15(homedir7(), ".npm")
|
|
31857
|
+
].filter((root) => !!root);
|
|
31858
|
+
return [...new Set(roots.map((root) => join15(root, "_npx")))];
|
|
31859
|
+
}
|
|
31860
|
+
function readJson(path) {
|
|
31861
|
+
try {
|
|
31862
|
+
return JSON.parse(readFileSync9(path, "utf8"));
|
|
31863
|
+
} catch {
|
|
31864
|
+
return null;
|
|
31865
|
+
}
|
|
31866
|
+
}
|
|
31867
|
+
function npxEntries() {
|
|
31868
|
+
const own = inNpxCache(packageRoot) ? real(resolve(packageRoot, "..", "..")) : null;
|
|
31869
|
+
const scanned = cacheRoots().flatMap((root) => {
|
|
31870
|
+
try {
|
|
31871
|
+
return readdirSync5(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => real(join15(root, entry.name)));
|
|
31872
|
+
} catch {
|
|
31873
|
+
return [];
|
|
31874
|
+
}
|
|
31875
|
+
});
|
|
31876
|
+
const entries = /* @__PURE__ */ new Map();
|
|
31877
|
+
for (const dir of [...scanned, ...own ? [own] : []]) {
|
|
31878
|
+
if (entries.has(dir)) continue;
|
|
31879
|
+
const manifest = readJson(join15(dir, "node_modules", "browsentic", "package.json"));
|
|
31880
|
+
if (!manifest) continue;
|
|
31881
|
+
const requested = readJson(join15(dir, "package.json"))?._npx;
|
|
31882
|
+
entries.set(dir, {
|
|
31883
|
+
dir,
|
|
31884
|
+
version: typeof manifest.version === "string" ? manifest.version : null,
|
|
31885
|
+
packages: Array.isArray(requested?.packages) ? requested.packages : [],
|
|
31886
|
+
running: dir === own
|
|
31887
|
+
});
|
|
31888
|
+
}
|
|
31889
|
+
return [...entries.values()];
|
|
31890
|
+
}
|
|
31891
|
+
function pinnedVersion() {
|
|
31892
|
+
const own = npxEntries().find((entry) => entry.running);
|
|
31893
|
+
const spec = own?.packages.find((name) => name === "browsentic" || name.startsWith("browsentic@"));
|
|
31894
|
+
const requested = spec?.slice("browsentic@".length);
|
|
31895
|
+
return requested && /^\d+\.\d+\.\d+/.test(requested) ? requested : null;
|
|
31896
|
+
}
|
|
31897
|
+
|
|
31800
31898
|
// remote-bridge.ts
|
|
31801
31899
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
31802
31900
|
|
|
@@ -31823,11 +31921,11 @@ var RemoteBridge = class _RemoteBridge {
|
|
|
31823
31921
|
pending = /* @__PURE__ */ new Map();
|
|
31824
31922
|
manifestListeners = /* @__PURE__ */ new Set();
|
|
31825
31923
|
static connect(port, token, runId) {
|
|
31826
|
-
return new Promise((
|
|
31924
|
+
return new Promise((resolve3, reject) => {
|
|
31827
31925
|
const socket = new import_websocket.default(`ws://127.0.0.1:${port}/control`, {
|
|
31828
31926
|
headers: { authorization: `Bearer ${token}` }
|
|
31829
31927
|
});
|
|
31830
|
-
socket.once("open", () =>
|
|
31928
|
+
socket.once("open", () => resolve3(new _RemoteBridge(socket, runId)));
|
|
31831
31929
|
socket.once("error", reject);
|
|
31832
31930
|
});
|
|
31833
31931
|
}
|
|
@@ -31874,14 +31972,14 @@ var RemoteBridge = class _RemoteBridge {
|
|
|
31874
31972
|
}
|
|
31875
31973
|
request(request, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
31876
31974
|
if (this.socket.readyState !== import_websocket.default.OPEN) return Promise.resolve(null);
|
|
31877
|
-
return new Promise((
|
|
31975
|
+
return new Promise((resolve3) => {
|
|
31878
31976
|
const timer = setTimeout(() => {
|
|
31879
31977
|
this.pending.delete(request.id);
|
|
31880
|
-
|
|
31978
|
+
resolve3(null);
|
|
31881
31979
|
}, timeoutMs);
|
|
31882
31980
|
this.pending.set(request.id, (message) => {
|
|
31883
31981
|
clearTimeout(timer);
|
|
31884
|
-
|
|
31982
|
+
resolve3(message);
|
|
31885
31983
|
});
|
|
31886
31984
|
this.socket.send(JSON.stringify(request));
|
|
31887
31985
|
});
|
|
@@ -31912,6 +32010,83 @@ function invokeTimeoutFor(action, input2) {
|
|
|
31912
32010
|
return REQUEST_TIMEOUT_MS;
|
|
31913
32011
|
}
|
|
31914
32012
|
|
|
32013
|
+
// self-update.ts
|
|
32014
|
+
import { spawnSync } from "child_process";
|
|
32015
|
+
import { rmSync as rmSync5 } from "fs";
|
|
32016
|
+
var REGISTRY = process.env.BROWSENTIC_REGISTRY ?? "https://registry.npmjs.org";
|
|
32017
|
+
async function publishedVersion(timeoutMs = 4e3) {
|
|
32018
|
+
try {
|
|
32019
|
+
const response = await fetch(`${REGISTRY}/browsentic/latest`, {
|
|
32020
|
+
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
32021
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
32022
|
+
});
|
|
32023
|
+
if (!response.ok) return null;
|
|
32024
|
+
const manifest = await response.json();
|
|
32025
|
+
return typeof manifest.version === "string" ? manifest.version : null;
|
|
32026
|
+
} catch {
|
|
32027
|
+
return null;
|
|
32028
|
+
}
|
|
32029
|
+
}
|
|
32030
|
+
function isNewer(candidate, current) {
|
|
32031
|
+
const release = (version2) => version2.split("-")[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
32032
|
+
const [a, b] = [release(candidate), release(current)];
|
|
32033
|
+
for (let i = 0; i < 3; i++) if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
|
|
32034
|
+
const [pre, currentPre] = [candidate.split("-")[1], current.split("-")[1]];
|
|
32035
|
+
if (pre === currentPre) return false;
|
|
32036
|
+
if (!pre) return true;
|
|
32037
|
+
if (!currentPre) return false;
|
|
32038
|
+
return pre > currentPre;
|
|
32039
|
+
}
|
|
32040
|
+
async function upgradeCli(current, forward) {
|
|
32041
|
+
const pinned = pinnedVersion();
|
|
32042
|
+
if (pinned) return null;
|
|
32043
|
+
const latest = await publishedVersion();
|
|
32044
|
+
if (!latest || !isNewer(latest, current)) return null;
|
|
32045
|
+
const kind = installKind();
|
|
32046
|
+
if (kind === "repo") {
|
|
32047
|
+
console.error(`
|
|
32048
|
+
! browsentic ${latest} is published; this is ${current}, from a source checkout.`);
|
|
32049
|
+
console.error(` Update it with "git pull && yarn setup".
|
|
32050
|
+
`);
|
|
32051
|
+
return null;
|
|
32052
|
+
}
|
|
32053
|
+
console.error(`
|
|
32054
|
+
\u21BB Updating the command itself, ${current} \u2192 ${latest}
|
|
32055
|
+
`);
|
|
32056
|
+
const rerun = [...forward, "--no-self-update"];
|
|
32057
|
+
if (kind === "npx") {
|
|
32058
|
+
for (const entry of npxEntries()) rmSync5(entry.dir, { recursive: true, force: true });
|
|
32059
|
+
const code = run("npx", ["-y", `browsentic@${latest}`, ...rerun]);
|
|
32060
|
+
if (code !== 0) {
|
|
32061
|
+
console.error(`
|
|
32062
|
+
That did not run, but nothing is broken: the cache is cleared, so a plain`);
|
|
32063
|
+
console.error(` \`npx browsentic ${forward[0] ?? "setup"}\` fetches ${latest} fresh next time.
|
|
32064
|
+
`);
|
|
32065
|
+
}
|
|
32066
|
+
return code;
|
|
32067
|
+
}
|
|
32068
|
+
const installed = run("npm", ["install", "-g", `browsentic@${latest}`]);
|
|
32069
|
+
if (installed !== 0) {
|
|
32070
|
+
console.error(`
|
|
32071
|
+
Could not replace the global install. Run this yourself, then try again:
|
|
32072
|
+
`);
|
|
32073
|
+
console.error(` npm install -g browsentic@${latest}
|
|
32074
|
+
`);
|
|
32075
|
+
return installed;
|
|
32076
|
+
}
|
|
32077
|
+
return run("browsentic", rerun);
|
|
32078
|
+
}
|
|
32079
|
+
function run(command2, args) {
|
|
32080
|
+
const result = spawnSync(command2, args, { stdio: "inherit", shell: process.platform === "win32" });
|
|
32081
|
+
if (result.error) {
|
|
32082
|
+
console.error(`
|
|
32083
|
+
Could not run \`${command2}\`: ${result.error.message}
|
|
32084
|
+
`);
|
|
32085
|
+
return 1;
|
|
32086
|
+
}
|
|
32087
|
+
return result.status ?? 1;
|
|
32088
|
+
}
|
|
32089
|
+
|
|
31915
32090
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
31916
32091
|
function isZ4Schema(s) {
|
|
31917
32092
|
const schema = s;
|
|
@@ -32504,7 +32679,7 @@ var Protocol = class {
|
|
|
32504
32679
|
return;
|
|
32505
32680
|
}
|
|
32506
32681
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
32507
|
-
await new Promise((
|
|
32682
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
32508
32683
|
options?.signal?.throwIfAborted();
|
|
32509
32684
|
}
|
|
32510
32685
|
} catch (error51) {
|
|
@@ -32521,7 +32696,7 @@ var Protocol = class {
|
|
|
32521
32696
|
*/
|
|
32522
32697
|
request(request, resultSchema, options) {
|
|
32523
32698
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
32524
|
-
return new Promise((
|
|
32699
|
+
return new Promise((resolve3, reject) => {
|
|
32525
32700
|
const earlyReject = (error51) => {
|
|
32526
32701
|
reject(error51);
|
|
32527
32702
|
};
|
|
@@ -32599,7 +32774,7 @@ var Protocol = class {
|
|
|
32599
32774
|
if (!parseResult.success) {
|
|
32600
32775
|
reject(parseResult.error);
|
|
32601
32776
|
} else {
|
|
32602
|
-
|
|
32777
|
+
resolve3(parseResult.data);
|
|
32603
32778
|
}
|
|
32604
32779
|
} catch (error51) {
|
|
32605
32780
|
reject(error51);
|
|
@@ -32860,12 +33035,12 @@ var Protocol = class {
|
|
|
32860
33035
|
}
|
|
32861
33036
|
} catch {
|
|
32862
33037
|
}
|
|
32863
|
-
return new Promise((
|
|
33038
|
+
return new Promise((resolve3, reject) => {
|
|
32864
33039
|
if (signal.aborted) {
|
|
32865
33040
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
32866
33041
|
return;
|
|
32867
33042
|
}
|
|
32868
|
-
const timeoutId = setTimeout(
|
|
33043
|
+
const timeoutId = setTimeout(resolve3, interval);
|
|
32869
33044
|
signal.addEventListener("abort", () => {
|
|
32870
33045
|
clearTimeout(timeoutId);
|
|
32871
33046
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -33918,10 +34093,98 @@ function text2(uri, mimeType, body) {
|
|
|
33918
34093
|
return { contents: [{ uri, mimeType, text: body }] };
|
|
33919
34094
|
}
|
|
33920
34095
|
|
|
34096
|
+
// uninstall.ts
|
|
34097
|
+
import { existsSync as existsSync6, readdirSync as readdirSync6, rmSync as rmSync6 } from "fs";
|
|
34098
|
+
import { isAbsolute as isAbsolute4, join as join17, relative as relative2 } from "path";
|
|
34099
|
+
|
|
34100
|
+
// screenshots.ts
|
|
34101
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
34102
|
+
import { chmodSync as chmodSync5, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
34103
|
+
import { homedir as homedir8 } from "os";
|
|
34104
|
+
import { basename as basename2, isAbsolute as isAbsolute3, join as join16, resolve as resolve2, sep as sep3 } from "path";
|
|
34105
|
+
function screenshotDir() {
|
|
34106
|
+
const configured = readAgentConfig().screenshotDir;
|
|
34107
|
+
if (typeof configured === "string" && configured.trim()) return expandHome3(configured.trim());
|
|
34108
|
+
return join16(homedir8(), "browsentic", "screenshot");
|
|
34109
|
+
}
|
|
34110
|
+
function expandHome3(p) {
|
|
34111
|
+
if (p === "~") return homedir8();
|
|
34112
|
+
if (p.startsWith("~/")) return join16(homedir8(), p.slice(2));
|
|
34113
|
+
return isAbsolute3(p) ? p : join16(homedir8(), p);
|
|
34114
|
+
}
|
|
34115
|
+
|
|
34116
|
+
// uninstall.ts
|
|
34117
|
+
function contains(root, path) {
|
|
34118
|
+
const inside = relative2(root, path);
|
|
34119
|
+
return !inside.startsWith("..") && !isAbsolute4(inside);
|
|
34120
|
+
}
|
|
34121
|
+
function planUninstall(options = {}) {
|
|
34122
|
+
const config2 = readAgentConfig();
|
|
34123
|
+
const extension2 = extensionDir(config2.extensionDir);
|
|
34124
|
+
const roots = [stateDir, userDir];
|
|
34125
|
+
const removals = [];
|
|
34126
|
+
if (!roots.some((root) => contains(root, extension2)) && existsSync6(extension2)) {
|
|
34127
|
+
removals.push({ label: "extension", path: extension2, holds: "the unpacked build Chrome loads" });
|
|
34128
|
+
}
|
|
34129
|
+
removals.push({
|
|
34130
|
+
label: "state",
|
|
34131
|
+
path: stateDir,
|
|
34132
|
+
holds: "pairing keys, config, approvals, logs",
|
|
34133
|
+
keep: options.keepSkills ? ["skills"] : void 0
|
|
34134
|
+
});
|
|
34135
|
+
removals.push({
|
|
34136
|
+
label: "files",
|
|
34137
|
+
path: userDir,
|
|
34138
|
+
holds: "the extension, skills, site maps, screenshots, captured downloads",
|
|
34139
|
+
keep: options.keepSkills ? ["skills"] : void 0
|
|
34140
|
+
});
|
|
34141
|
+
const elsewhere = [];
|
|
34142
|
+
const outside = (label2, path, holds) => {
|
|
34143
|
+
if (!roots.some((root) => contains(root, path)) && existsSync6(path)) elsewhere.push({ label: label2, path, holds });
|
|
34144
|
+
};
|
|
34145
|
+
outside("skills", uploadedSkillsDir(), "site maps and uploaded skills");
|
|
34146
|
+
outside("screenshots", screenshotDir(), "captures taken with save: true");
|
|
34147
|
+
outside("downloads", downloadDir(), "files captured from pages");
|
|
34148
|
+
return {
|
|
34149
|
+
removals: removals.filter((removal) => existsSync6(removal.path)),
|
|
34150
|
+
elsewhere,
|
|
34151
|
+
npx: npxEntries()
|
|
34152
|
+
};
|
|
34153
|
+
}
|
|
34154
|
+
function removeAll(removals) {
|
|
34155
|
+
return removals.map((removal) => {
|
|
34156
|
+
try {
|
|
34157
|
+
const kept = removal.keep?.length ? keepingSome(removal.path, removal.keep) : [];
|
|
34158
|
+
if (!kept.length) rmSync6(removal.path, { recursive: true, force: true });
|
|
34159
|
+
return { removal, removed: true, kept };
|
|
34160
|
+
} catch (error51) {
|
|
34161
|
+
return { removal, removed: false, kept: [], error: error51.message };
|
|
34162
|
+
}
|
|
34163
|
+
});
|
|
34164
|
+
}
|
|
34165
|
+
function keepingSome(dir, keep) {
|
|
34166
|
+
const kept = [];
|
|
34167
|
+
for (const entry of readdirSync6(dir)) {
|
|
34168
|
+
if (keep.includes(entry)) kept.push(entry);
|
|
34169
|
+
else rmSync6(join17(dir, entry), { recursive: true, force: true });
|
|
34170
|
+
}
|
|
34171
|
+
return kept;
|
|
34172
|
+
}
|
|
34173
|
+
function purgeNpxCache(entries) {
|
|
34174
|
+
return entries.map((entry) => {
|
|
34175
|
+
try {
|
|
34176
|
+
rmSync6(entry.dir, { recursive: true, force: true });
|
|
34177
|
+
return { entry, removed: true };
|
|
34178
|
+
} catch (error51) {
|
|
34179
|
+
return { entry, removed: false, error: error51.message };
|
|
34180
|
+
}
|
|
34181
|
+
});
|
|
34182
|
+
}
|
|
34183
|
+
|
|
33921
34184
|
// package.json
|
|
33922
34185
|
var package_default = {
|
|
33923
34186
|
name: "browsentic",
|
|
33924
|
-
version: "0.4.
|
|
34187
|
+
version: "0.4.15",
|
|
33925
34188
|
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.",
|
|
33926
34189
|
type: "module",
|
|
33927
34190
|
license: "MIT",
|
|
@@ -33978,7 +34241,8 @@ var package_default = {
|
|
|
33978
34241
|
var USAGE = `browsentic ${package_default.version} \u2014 hand your real browser to the agent you already run
|
|
33979
34242
|
|
|
33980
34243
|
browsentic setup install the extension, start the daemon, print a pairing code
|
|
33981
|
-
browsentic update
|
|
34244
|
+
browsentic update pull the newest build \u2014 the command itself, then the extension
|
|
34245
|
+
browsentic uninstall stop the daemon and remove everything Browsentic wrote
|
|
33982
34246
|
browsentic pair issue a one-time code to type into the extension
|
|
33983
34247
|
browsentic status daemon, extension and agent state
|
|
33984
34248
|
browsentic sessions list paired browsers
|
|
@@ -34006,7 +34270,7 @@ For MCP clients
|
|
|
34006
34270
|
browsentic mcp serve MCP over stdio \u2014 what a client runs, not what you type
|
|
34007
34271
|
claude mcp add browsentic -- browsentic mcp
|
|
34008
34272
|
`;
|
|
34009
|
-
var invokedAs =
|
|
34273
|
+
var invokedAs = basename3(process.argv[1] ?? "").replace(/\.(?:js|cjs|mjs|exe|cmd|ps1)$/i, "");
|
|
34010
34274
|
var servesBare = invokedAs === "browsentic-mcp" || !!process.env.BROWSENTIC_AGENT_RUN;
|
|
34011
34275
|
var [command] = process.argv.slice(2);
|
|
34012
34276
|
switch (command) {
|
|
@@ -34023,6 +34287,9 @@ switch (command) {
|
|
|
34023
34287
|
case "update":
|
|
34024
34288
|
await setup(["--no-pair", "--restart", ...process.argv.slice(3)]);
|
|
34025
34289
|
break;
|
|
34290
|
+
case "uninstall":
|
|
34291
|
+
await uninstall(process.argv.slice(3));
|
|
34292
|
+
break;
|
|
34026
34293
|
case "pair":
|
|
34027
34294
|
await pair();
|
|
34028
34295
|
break;
|
|
@@ -34042,7 +34309,7 @@ switch (command) {
|
|
|
34042
34309
|
await showStatus();
|
|
34043
34310
|
break;
|
|
34044
34311
|
case "stop":
|
|
34045
|
-
stop();
|
|
34312
|
+
await stop();
|
|
34046
34313
|
break;
|
|
34047
34314
|
case "restart":
|
|
34048
34315
|
await restart();
|
|
@@ -34118,7 +34385,7 @@ function printSkills() {
|
|
|
34118
34385
|
].filter(Boolean);
|
|
34119
34386
|
console.log(`${skill.name} (${tags.join(" \xB7 ")})`);
|
|
34120
34387
|
if (skill.description) console.log(` ${skill.description}`);
|
|
34121
|
-
if (skill.provenance === "generated") console.log(` ${
|
|
34388
|
+
if (skill.provenance === "generated") console.log(` ${join18(uploadedSkillsDir(), skill.name)}/`);
|
|
34122
34389
|
}
|
|
34123
34390
|
console.log(`
|
|
34124
34391
|
Read in order: ${skillDirNames().join(" \u2192 ")} (a later one shadows an earlier one by name)`);
|
|
@@ -34164,34 +34431,27 @@ async function showStatus() {
|
|
|
34164
34431
|
);
|
|
34165
34432
|
if (!status2.pairedBrowsers) console.log('\nRun "browsentic setup" to install the extension, or "browsentic pair" if it is already loaded.');
|
|
34166
34433
|
}
|
|
34167
|
-
function stop() {
|
|
34168
|
-
const
|
|
34169
|
-
|
|
34170
|
-
|
|
34171
|
-
|
|
34172
|
-
console.log(`Stopped daemon (pid ${lock.pid}).`);
|
|
34173
|
-
} catch {
|
|
34174
|
-
console.log(`Daemon (pid ${lock.pid}) was not running; clearing the lockfile.`);
|
|
34175
|
-
clearLockfile();
|
|
34434
|
+
async function stop() {
|
|
34435
|
+
const { stopped, stubborn } = await stopDaemons();
|
|
34436
|
+
for (const daemon of stopped) console.log(`Stopped daemon (pid ${daemon.pid}) on 127.0.0.1:${daemon.port}.`);
|
|
34437
|
+
for (const daemon of stubborn) {
|
|
34438
|
+
console.error(`Daemon (pid ${daemon.pid}) on 127.0.0.1:${daemon.port} would not exit \u2014 kill it by hand.`);
|
|
34176
34439
|
}
|
|
34440
|
+
if (!stopped.length && !stubborn.length) console.log("No daemon is answering; nothing to stop.");
|
|
34441
|
+
if (stubborn.length) process.exitCode = 1;
|
|
34177
34442
|
}
|
|
34178
34443
|
async function restart() {
|
|
34179
|
-
const
|
|
34180
|
-
|
|
34181
|
-
|
|
34182
|
-
|
|
34183
|
-
if (Date.now() > deadline) {
|
|
34184
|
-
console.error(`Daemon (pid ${lock.pid}) is still exiting \u2014 try again in a moment.`);
|
|
34185
|
-
process.exit(1);
|
|
34186
|
-
}
|
|
34187
|
-
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
34444
|
+
const { stubborn } = await stopDaemons();
|
|
34445
|
+
if (stubborn.length) {
|
|
34446
|
+
console.error(`Daemon (pid ${stubborn[0].pid}) is still exiting \u2014 try again in a moment.`);
|
|
34447
|
+
process.exit(1);
|
|
34188
34448
|
}
|
|
34189
34449
|
const fresh = await ensureDaemon();
|
|
34190
34450
|
console.log(`Daemon running on 127.0.0.1:${fresh.port} (pid ${fresh.pid}, v${fresh.daemonVersion}).`);
|
|
34191
34451
|
}
|
|
34192
34452
|
function showLogs() {
|
|
34193
34453
|
try {
|
|
34194
|
-
process.stdout.write(
|
|
34454
|
+
process.stdout.write(readFileSync10(logPath, "utf8"));
|
|
34195
34455
|
} catch {
|
|
34196
34456
|
console.log(`No log at ${logPath} yet.`);
|
|
34197
34457
|
}
|
|
@@ -34222,6 +34482,10 @@ async function setup(argv) {
|
|
|
34222
34482
|
const at = argv.indexOf(`--${name}`);
|
|
34223
34483
|
return at === -1 ? void 0 : argv[at + 1];
|
|
34224
34484
|
};
|
|
34485
|
+
if (!flag("no-self-update")) {
|
|
34486
|
+
const code2 = await upgradeCli(package_default.version, process.argv.slice(2));
|
|
34487
|
+
if (code2 !== null) process.exit(code2);
|
|
34488
|
+
}
|
|
34225
34489
|
const browser = valueOf("browser") ?? "chrome";
|
|
34226
34490
|
if (browser === "firefox") {
|
|
34227
34491
|
console.log(`
|
|
@@ -34260,15 +34524,11 @@ async function setup(argv) {
|
|
|
34260
34524
|
}
|
|
34261
34525
|
if (flag("restart")) await restart();
|
|
34262
34526
|
const lock = await ensureDaemon();
|
|
34263
|
-
|
|
34264
|
-
|
|
34265
|
-
|
|
34266
|
-
|
|
34267
|
-
|
|
34268
|
-
alreadyPaired = sessions.some((session) => session.origin.startsWith("chrome-extension://"));
|
|
34269
|
-
if (!alreadyPaired) code = (await bridge.pair()).code;
|
|
34270
|
-
await bridge.close();
|
|
34271
|
-
}
|
|
34527
|
+
const bridge = await RemoteBridge.connect(lock.port, lock.token);
|
|
34528
|
+
const sessions = await bridge.sessions();
|
|
34529
|
+
const alreadyPaired = sessions.some((session) => session.origin.startsWith("chrome-extension://"));
|
|
34530
|
+
const code = alreadyPaired || flag("no-pair") ? void 0 : (await bridge.pair()).code;
|
|
34531
|
+
await bridge.close();
|
|
34272
34532
|
if (json2) {
|
|
34273
34533
|
console.log(
|
|
34274
34534
|
JSON.stringify(
|
|
@@ -34308,11 +34568,91 @@ async function setup(argv) {
|
|
|
34308
34568
|
console.log(` ${groupCode(code)}
|
|
34309
34569
|
`);
|
|
34310
34570
|
console.log(` Single use, expires in 10 minutes. Need another? "browsentic pair"
|
|
34571
|
+
`);
|
|
34572
|
+
} else {
|
|
34573
|
+
console.log(` 2. Run "browsentic pair" and paste the code into the Browsentic popup.
|
|
34311
34574
|
`);
|
|
34312
34575
|
}
|
|
34313
34576
|
console.log(` Then open the side panel and say what you want.
|
|
34314
34577
|
`);
|
|
34315
34578
|
}
|
|
34579
|
+
async function uninstall(argv) {
|
|
34580
|
+
const flag = (name) => argv.includes(`--${name}`);
|
|
34581
|
+
const plan = planUninstall({ keepSkills: flag("keep-skills") });
|
|
34582
|
+
const daemons = await runningDaemons();
|
|
34583
|
+
const kind = installKind();
|
|
34584
|
+
console.log(`
|
|
34585
|
+
Browsentic ${package_default.version} \u2014 uninstall
|
|
34586
|
+
`);
|
|
34587
|
+
if (!daemons.length && !plan.removals.length && !plan.npx.length) {
|
|
34588
|
+
console.log(" Nothing to remove; this machine is already clean.\n");
|
|
34589
|
+
return;
|
|
34590
|
+
}
|
|
34591
|
+
console.log(" This removes:\n");
|
|
34592
|
+
for (const daemon of daemons) console.log(` daemon 127.0.0.1:${daemon.port}, pid ${daemon.pid}`);
|
|
34593
|
+
for (const removal of plan.removals) {
|
|
34594
|
+
console.log(` ${removal.label.padEnd(11)} ${removal.path}`);
|
|
34595
|
+
console.log(` ${removal.holds}${removal.keep ? " \u2014 keeping skills/" : ""}`);
|
|
34596
|
+
}
|
|
34597
|
+
for (const entry of plan.npx) {
|
|
34598
|
+
const running = entry.running ? ", the copy running right now" : "";
|
|
34599
|
+
console.log(` npx cache ${entry.dir}`);
|
|
34600
|
+
console.log(` browsentic ${entry.version ?? "unknown"}${running}`);
|
|
34601
|
+
}
|
|
34602
|
+
if (plan.elsewhere.length) {
|
|
34603
|
+
console.log("\n Left alone \u2014 configuration put these outside the two roots:\n");
|
|
34604
|
+
for (const dir of plan.elsewhere) console.log(` ${dir.label.padEnd(11)} ${dir.path} (${dir.holds})`);
|
|
34605
|
+
}
|
|
34606
|
+
console.log("\n You will have to remove these yourself:\n");
|
|
34607
|
+
console.log(" the Browsentic card at chrome://extensions. Do that first \u2014 remove the");
|
|
34608
|
+
console.log(" directory while the card is loaded and the browser is left holding a");
|
|
34609
|
+
console.log(" broken one. It is also what clears recordings and held secrets, which");
|
|
34610
|
+
console.log(" live in extension storage rather than on disk.");
|
|
34611
|
+
if (kind === "global") console.log("\n the command itself: npm rm -g browsentic");
|
|
34612
|
+
if (kind === "repo") console.log("\n the global link: yarn daemon:unlink");
|
|
34613
|
+
console.log("\n the entry in your MCP client, e.g. claude mcp remove browsentic");
|
|
34614
|
+
if (flag("dry-run")) {
|
|
34615
|
+
console.log("\n --dry-run: nothing was removed.\n");
|
|
34616
|
+
return;
|
|
34617
|
+
}
|
|
34618
|
+
if (!flag("yes") && !argv.includes("-y")) {
|
|
34619
|
+
if (!process.stdin.isTTY) {
|
|
34620
|
+
console.error("\n Nothing was removed \u2014 this is not a terminal, so there is nobody to ask.");
|
|
34621
|
+
console.error(" Re-run it with --yes.\n");
|
|
34622
|
+
process.exit(1);
|
|
34623
|
+
}
|
|
34624
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
34625
|
+
const answer = await rl.question("\n Remove all of it? [y/N] ");
|
|
34626
|
+
rl.close();
|
|
34627
|
+
if (!/^y(es)?$/i.test(answer.trim())) return console.log("\n Nothing was removed.\n");
|
|
34628
|
+
}
|
|
34629
|
+
console.log();
|
|
34630
|
+
const lock = await probeExisting();
|
|
34631
|
+
if (lock) {
|
|
34632
|
+
try {
|
|
34633
|
+
const bridge = await RemoteBridge.connect(lock.port, lock.token);
|
|
34634
|
+
const revoked = await bridge.revoke();
|
|
34635
|
+
await bridge.close();
|
|
34636
|
+
if (revoked) console.log(` \u2713 Unpaired ${revoked} browser${revoked === 1 ? "" : "s"}`);
|
|
34637
|
+
} catch {
|
|
34638
|
+
console.log(" \xB7 Unpair skipped, the daemon did not answer");
|
|
34639
|
+
}
|
|
34640
|
+
}
|
|
34641
|
+
const { stopped, stubborn } = await stopDaemons();
|
|
34642
|
+
if (stopped.length) console.log(` \u2713 Daemon stopped (pid ${stopped.map((daemon) => daemon.pid).join(", ")})`);
|
|
34643
|
+
for (const daemon of stubborn) console.log(` \u2717 Daemon pid ${daemon.pid} would not exit \u2014 kill it by hand`);
|
|
34644
|
+
for (const outcome of removeAll(plan.removals)) {
|
|
34645
|
+
if (!outcome.removed) console.log(` \u2717 ${outcome.removal.path} \u2014 ${outcome.error}`);
|
|
34646
|
+
else if (outcome.kept.length) console.log(` \u2713 Emptied ${outcome.removal.path} \u2014 kept ${outcome.kept.join(", ")}/`);
|
|
34647
|
+
else console.log(` \u2713 Removed ${outcome.removal.path}`);
|
|
34648
|
+
}
|
|
34649
|
+
for (const purge of purgeNpxCache(plan.npx)) {
|
|
34650
|
+
if (purge.removed) console.log(` \u2713 Cleared ${purge.entry.dir}`);
|
|
34651
|
+
else console.log(` \u2717 ${purge.entry.dir} \u2014 ${purge.error}`);
|
|
34652
|
+
}
|
|
34653
|
+
console.log("\n Done. Remove the card at chrome://extensions if you have not.\n");
|
|
34654
|
+
if (stubborn.length) process.exitCode = 1;
|
|
34655
|
+
}
|
|
34316
34656
|
async function showSessions() {
|
|
34317
34657
|
const bridge = await connect();
|
|
34318
34658
|
const sessions = await bridge.sessions();
|