opensteer 0.6.4 → 0.6.6
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/{chunk-G6V2DJRN.js → chunk-H27BERRF.js} +83 -5
- package/dist/cli/profile.cjs +83 -5
- package/dist/cli/profile.js +1 -1
- package/dist/cli/server.cjs +83 -5
- package/dist/cli/server.js +1 -1
- package/dist/index.cjs +83 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/electron/SKILL.md +6 -4
- package/skills/electron/references/opensteer-electron-recipes.md +5 -3
- package/skills/electron/references/opensteer-electron-workflow.md +2 -2
- package/skills/opensteer/SKILL.md +17 -3
- package/skills/opensteer/references/cli-reference.md +4 -1
|
@@ -7529,6 +7529,8 @@ import WebSocket2, { WebSocketServer } from "ws";
|
|
|
7529
7529
|
var CDP_DISCOVERY_TIMEOUT_MS = 3e3;
|
|
7530
7530
|
var LOCAL_PROXY_HOST = "127.0.0.1";
|
|
7531
7531
|
var INTERNAL_COMMAND_ID_START = 1e9;
|
|
7532
|
+
var CREATE_BLANK_TARGET_COMMAND_ID = 1;
|
|
7533
|
+
var CREATE_BLANK_TARGET_TIMEOUT_MS = 5e3;
|
|
7532
7534
|
async function discoverTargets(cdpUrl) {
|
|
7533
7535
|
const baseUrl = resolveHttpDiscoveryBase(cdpUrl);
|
|
7534
7536
|
const [targetsPayload, versionPayload] = await Promise.all([
|
|
@@ -7540,6 +7542,81 @@ async function discoverTargets(cdpUrl) {
|
|
|
7540
7542
|
targets: readPageTargets(targetsPayload)
|
|
7541
7543
|
};
|
|
7542
7544
|
}
|
|
7545
|
+
function createBlankTarget(browserWsUrl) {
|
|
7546
|
+
return new Promise((resolve, reject) => {
|
|
7547
|
+
const ws = new WebSocket2(browserWsUrl);
|
|
7548
|
+
let settled = false;
|
|
7549
|
+
function settle(handler) {
|
|
7550
|
+
if (settled) {
|
|
7551
|
+
return;
|
|
7552
|
+
}
|
|
7553
|
+
settled = true;
|
|
7554
|
+
clearTimeout(timeout);
|
|
7555
|
+
ws.close();
|
|
7556
|
+
handler();
|
|
7557
|
+
}
|
|
7558
|
+
const timeout = setTimeout(() => {
|
|
7559
|
+
settle(
|
|
7560
|
+
() => reject(new Error("Timed out creating a blank tab via CDP."))
|
|
7561
|
+
);
|
|
7562
|
+
}, CREATE_BLANK_TARGET_TIMEOUT_MS);
|
|
7563
|
+
ws.once("open", () => {
|
|
7564
|
+
ws.send(
|
|
7565
|
+
JSON.stringify({
|
|
7566
|
+
id: CREATE_BLANK_TARGET_COMMAND_ID,
|
|
7567
|
+
method: "Target.createTarget",
|
|
7568
|
+
params: { url: "about:blank" }
|
|
7569
|
+
})
|
|
7570
|
+
);
|
|
7571
|
+
});
|
|
7572
|
+
ws.on("message", (data, isBinary) => {
|
|
7573
|
+
if (isBinary) {
|
|
7574
|
+
return;
|
|
7575
|
+
}
|
|
7576
|
+
const message = parseMessage(data);
|
|
7577
|
+
if (!message || asNumber(message.id) !== CREATE_BLANK_TARGET_COMMAND_ID) {
|
|
7578
|
+
return;
|
|
7579
|
+
}
|
|
7580
|
+
const cdpError = asObject(message.error);
|
|
7581
|
+
if (cdpError) {
|
|
7582
|
+
settle(
|
|
7583
|
+
() => reject(
|
|
7584
|
+
new Error(
|
|
7585
|
+
`Target.createTarget failed: ${asString(cdpError.message) ?? JSON.stringify(cdpError)}`
|
|
7586
|
+
)
|
|
7587
|
+
)
|
|
7588
|
+
);
|
|
7589
|
+
return;
|
|
7590
|
+
}
|
|
7591
|
+
const targetId = asString(asObject(message.result)?.targetId);
|
|
7592
|
+
if (targetId) {
|
|
7593
|
+
settle(() => resolve(targetId));
|
|
7594
|
+
return;
|
|
7595
|
+
}
|
|
7596
|
+
settle(
|
|
7597
|
+
() => reject(
|
|
7598
|
+
new Error(
|
|
7599
|
+
"Target.createTarget succeeded but no targetId was returned."
|
|
7600
|
+
)
|
|
7601
|
+
)
|
|
7602
|
+
);
|
|
7603
|
+
});
|
|
7604
|
+
ws.once("error", (err) => {
|
|
7605
|
+
settle(
|
|
7606
|
+
() => reject(new Error(`Failed to create blank tab: ${errorMessage(err)}`))
|
|
7607
|
+
);
|
|
7608
|
+
});
|
|
7609
|
+
ws.once("close", () => {
|
|
7610
|
+
settle(
|
|
7611
|
+
() => reject(
|
|
7612
|
+
new Error(
|
|
7613
|
+
"CDP browser websocket closed before blank tab creation completed."
|
|
7614
|
+
)
|
|
7615
|
+
)
|
|
7616
|
+
);
|
|
7617
|
+
});
|
|
7618
|
+
});
|
|
7619
|
+
}
|
|
7543
7620
|
var CDPProxy = class {
|
|
7544
7621
|
constructor(browserWsUrl, targetId) {
|
|
7545
7622
|
this.browserWsUrl = browserWsUrl;
|
|
@@ -7947,12 +8024,13 @@ var BrowserPool = class {
|
|
|
7947
8024
|
let cdpProxy = null;
|
|
7948
8025
|
try {
|
|
7949
8026
|
const { browserWsUrl, targets } = await discoverTargets(cdpUrl);
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
8027
|
+
let targetId;
|
|
8028
|
+
if (targets.length > 0) {
|
|
8029
|
+
targetId = targets[0].id;
|
|
8030
|
+
} else {
|
|
8031
|
+
targetId = await createBlankTarget(browserWsUrl);
|
|
7954
8032
|
}
|
|
7955
|
-
cdpProxy = new CDPProxy(browserWsUrl,
|
|
8033
|
+
cdpProxy = new CDPProxy(browserWsUrl, targetId);
|
|
7956
8034
|
const proxyWsUrl = await cdpProxy.start();
|
|
7957
8035
|
browser = await chromium.connectOverCDP(proxyWsUrl, {
|
|
7958
8036
|
timeout: timeout ?? 3e4
|
package/dist/cli/profile.cjs
CHANGED
|
@@ -1336,6 +1336,8 @@ var import_ws = __toESM(require("ws"), 1);
|
|
|
1336
1336
|
var CDP_DISCOVERY_TIMEOUT_MS = 3e3;
|
|
1337
1337
|
var LOCAL_PROXY_HOST = "127.0.0.1";
|
|
1338
1338
|
var INTERNAL_COMMAND_ID_START = 1e9;
|
|
1339
|
+
var CREATE_BLANK_TARGET_COMMAND_ID = 1;
|
|
1340
|
+
var CREATE_BLANK_TARGET_TIMEOUT_MS = 5e3;
|
|
1339
1341
|
async function discoverTargets(cdpUrl) {
|
|
1340
1342
|
const baseUrl = resolveHttpDiscoveryBase(cdpUrl);
|
|
1341
1343
|
const [targetsPayload, versionPayload] = await Promise.all([
|
|
@@ -1347,6 +1349,81 @@ async function discoverTargets(cdpUrl) {
|
|
|
1347
1349
|
targets: readPageTargets(targetsPayload)
|
|
1348
1350
|
};
|
|
1349
1351
|
}
|
|
1352
|
+
function createBlankTarget(browserWsUrl) {
|
|
1353
|
+
return new Promise((resolve, reject) => {
|
|
1354
|
+
const ws = new import_ws.default(browserWsUrl);
|
|
1355
|
+
let settled = false;
|
|
1356
|
+
function settle(handler) {
|
|
1357
|
+
if (settled) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
settled = true;
|
|
1361
|
+
clearTimeout(timeout);
|
|
1362
|
+
ws.close();
|
|
1363
|
+
handler();
|
|
1364
|
+
}
|
|
1365
|
+
const timeout = setTimeout(() => {
|
|
1366
|
+
settle(
|
|
1367
|
+
() => reject(new Error("Timed out creating a blank tab via CDP."))
|
|
1368
|
+
);
|
|
1369
|
+
}, CREATE_BLANK_TARGET_TIMEOUT_MS);
|
|
1370
|
+
ws.once("open", () => {
|
|
1371
|
+
ws.send(
|
|
1372
|
+
JSON.stringify({
|
|
1373
|
+
id: CREATE_BLANK_TARGET_COMMAND_ID,
|
|
1374
|
+
method: "Target.createTarget",
|
|
1375
|
+
params: { url: "about:blank" }
|
|
1376
|
+
})
|
|
1377
|
+
);
|
|
1378
|
+
});
|
|
1379
|
+
ws.on("message", (data, isBinary) => {
|
|
1380
|
+
if (isBinary) {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
const message = parseMessage(data);
|
|
1384
|
+
if (!message || asNumber(message.id) !== CREATE_BLANK_TARGET_COMMAND_ID) {
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
const cdpError = asObject(message.error);
|
|
1388
|
+
if (cdpError) {
|
|
1389
|
+
settle(
|
|
1390
|
+
() => reject(
|
|
1391
|
+
new Error(
|
|
1392
|
+
`Target.createTarget failed: ${asString(cdpError.message) ?? JSON.stringify(cdpError)}`
|
|
1393
|
+
)
|
|
1394
|
+
)
|
|
1395
|
+
);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
const targetId = asString(asObject(message.result)?.targetId);
|
|
1399
|
+
if (targetId) {
|
|
1400
|
+
settle(() => resolve(targetId));
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
settle(
|
|
1404
|
+
() => reject(
|
|
1405
|
+
new Error(
|
|
1406
|
+
"Target.createTarget succeeded but no targetId was returned."
|
|
1407
|
+
)
|
|
1408
|
+
)
|
|
1409
|
+
);
|
|
1410
|
+
});
|
|
1411
|
+
ws.once("error", (err) => {
|
|
1412
|
+
settle(
|
|
1413
|
+
() => reject(new Error(`Failed to create blank tab: ${errorMessage(err)}`))
|
|
1414
|
+
);
|
|
1415
|
+
});
|
|
1416
|
+
ws.once("close", () => {
|
|
1417
|
+
settle(
|
|
1418
|
+
() => reject(
|
|
1419
|
+
new Error(
|
|
1420
|
+
"CDP browser websocket closed before blank tab creation completed."
|
|
1421
|
+
)
|
|
1422
|
+
)
|
|
1423
|
+
);
|
|
1424
|
+
});
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1350
1427
|
var CDPProxy = class {
|
|
1351
1428
|
constructor(browserWsUrl, targetId) {
|
|
1352
1429
|
this.browserWsUrl = browserWsUrl;
|
|
@@ -1830,12 +1907,13 @@ var BrowserPool = class {
|
|
|
1830
1907
|
let cdpProxy = null;
|
|
1831
1908
|
try {
|
|
1832
1909
|
const { browserWsUrl, targets } = await discoverTargets(cdpUrl);
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1910
|
+
let targetId;
|
|
1911
|
+
if (targets.length > 0) {
|
|
1912
|
+
targetId = targets[0].id;
|
|
1913
|
+
} else {
|
|
1914
|
+
targetId = await createBlankTarget(browserWsUrl);
|
|
1837
1915
|
}
|
|
1838
|
-
cdpProxy = new CDPProxy(browserWsUrl,
|
|
1916
|
+
cdpProxy = new CDPProxy(browserWsUrl, targetId);
|
|
1839
1917
|
const proxyWsUrl = await cdpProxy.start();
|
|
1840
1918
|
browser = await import_playwright.chromium.connectOverCDP(proxyWsUrl, {
|
|
1841
1919
|
timeout: timeout ?? 3e4
|
package/dist/cli/profile.js
CHANGED
package/dist/cli/server.cjs
CHANGED
|
@@ -437,6 +437,8 @@ var import_ws = __toESM(require("ws"), 1);
|
|
|
437
437
|
var CDP_DISCOVERY_TIMEOUT_MS = 3e3;
|
|
438
438
|
var LOCAL_PROXY_HOST = "127.0.0.1";
|
|
439
439
|
var INTERNAL_COMMAND_ID_START = 1e9;
|
|
440
|
+
var CREATE_BLANK_TARGET_COMMAND_ID = 1;
|
|
441
|
+
var CREATE_BLANK_TARGET_TIMEOUT_MS = 5e3;
|
|
440
442
|
async function discoverTargets(cdpUrl) {
|
|
441
443
|
const baseUrl = resolveHttpDiscoveryBase(cdpUrl);
|
|
442
444
|
const [targetsPayload, versionPayload] = await Promise.all([
|
|
@@ -448,6 +450,81 @@ async function discoverTargets(cdpUrl) {
|
|
|
448
450
|
targets: readPageTargets(targetsPayload)
|
|
449
451
|
};
|
|
450
452
|
}
|
|
453
|
+
function createBlankTarget(browserWsUrl) {
|
|
454
|
+
return new Promise((resolve, reject) => {
|
|
455
|
+
const ws = new import_ws.default(browserWsUrl);
|
|
456
|
+
let settled = false;
|
|
457
|
+
function settle(handler) {
|
|
458
|
+
if (settled) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
settled = true;
|
|
462
|
+
clearTimeout(timeout);
|
|
463
|
+
ws.close();
|
|
464
|
+
handler();
|
|
465
|
+
}
|
|
466
|
+
const timeout = setTimeout(() => {
|
|
467
|
+
settle(
|
|
468
|
+
() => reject(new Error("Timed out creating a blank tab via CDP."))
|
|
469
|
+
);
|
|
470
|
+
}, CREATE_BLANK_TARGET_TIMEOUT_MS);
|
|
471
|
+
ws.once("open", () => {
|
|
472
|
+
ws.send(
|
|
473
|
+
JSON.stringify({
|
|
474
|
+
id: CREATE_BLANK_TARGET_COMMAND_ID,
|
|
475
|
+
method: "Target.createTarget",
|
|
476
|
+
params: { url: "about:blank" }
|
|
477
|
+
})
|
|
478
|
+
);
|
|
479
|
+
});
|
|
480
|
+
ws.on("message", (data, isBinary) => {
|
|
481
|
+
if (isBinary) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const message = parseMessage(data);
|
|
485
|
+
if (!message || asNumber(message.id) !== CREATE_BLANK_TARGET_COMMAND_ID) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const cdpError = asObject(message.error);
|
|
489
|
+
if (cdpError) {
|
|
490
|
+
settle(
|
|
491
|
+
() => reject(
|
|
492
|
+
new Error(
|
|
493
|
+
`Target.createTarget failed: ${asString(cdpError.message) ?? JSON.stringify(cdpError)}`
|
|
494
|
+
)
|
|
495
|
+
)
|
|
496
|
+
);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const targetId = asString(asObject(message.result)?.targetId);
|
|
500
|
+
if (targetId) {
|
|
501
|
+
settle(() => resolve(targetId));
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
settle(
|
|
505
|
+
() => reject(
|
|
506
|
+
new Error(
|
|
507
|
+
"Target.createTarget succeeded but no targetId was returned."
|
|
508
|
+
)
|
|
509
|
+
)
|
|
510
|
+
);
|
|
511
|
+
});
|
|
512
|
+
ws.once("error", (err) => {
|
|
513
|
+
settle(
|
|
514
|
+
() => reject(new Error(`Failed to create blank tab: ${errorMessage(err)}`))
|
|
515
|
+
);
|
|
516
|
+
});
|
|
517
|
+
ws.once("close", () => {
|
|
518
|
+
settle(
|
|
519
|
+
() => reject(
|
|
520
|
+
new Error(
|
|
521
|
+
"CDP browser websocket closed before blank tab creation completed."
|
|
522
|
+
)
|
|
523
|
+
)
|
|
524
|
+
);
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
}
|
|
451
528
|
var CDPProxy = class {
|
|
452
529
|
constructor(browserWsUrl, targetId) {
|
|
453
530
|
this.browserWsUrl = browserWsUrl;
|
|
@@ -931,12 +1008,13 @@ var BrowserPool = class {
|
|
|
931
1008
|
let cdpProxy = null;
|
|
932
1009
|
try {
|
|
933
1010
|
const { browserWsUrl, targets } = await discoverTargets(cdpUrl);
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1011
|
+
let targetId;
|
|
1012
|
+
if (targets.length > 0) {
|
|
1013
|
+
targetId = targets[0].id;
|
|
1014
|
+
} else {
|
|
1015
|
+
targetId = await createBlankTarget(browserWsUrl);
|
|
938
1016
|
}
|
|
939
|
-
cdpProxy = new CDPProxy(browserWsUrl,
|
|
1017
|
+
cdpProxy = new CDPProxy(browserWsUrl, targetId);
|
|
940
1018
|
const proxyWsUrl = await cdpProxy.start();
|
|
941
1019
|
browser = await import_playwright.chromium.connectOverCDP(proxyWsUrl, {
|
|
942
1020
|
timeout: timeout ?? 3e4
|
package/dist/cli/server.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -528,6 +528,8 @@ var import_ws = __toESM(require("ws"), 1);
|
|
|
528
528
|
var CDP_DISCOVERY_TIMEOUT_MS = 3e3;
|
|
529
529
|
var LOCAL_PROXY_HOST = "127.0.0.1";
|
|
530
530
|
var INTERNAL_COMMAND_ID_START = 1e9;
|
|
531
|
+
var CREATE_BLANK_TARGET_COMMAND_ID = 1;
|
|
532
|
+
var CREATE_BLANK_TARGET_TIMEOUT_MS = 5e3;
|
|
531
533
|
async function discoverTargets(cdpUrl) {
|
|
532
534
|
const baseUrl = resolveHttpDiscoveryBase(cdpUrl);
|
|
533
535
|
const [targetsPayload, versionPayload] = await Promise.all([
|
|
@@ -539,6 +541,81 @@ async function discoverTargets(cdpUrl) {
|
|
|
539
541
|
targets: readPageTargets(targetsPayload)
|
|
540
542
|
};
|
|
541
543
|
}
|
|
544
|
+
function createBlankTarget(browserWsUrl) {
|
|
545
|
+
return new Promise((resolve, reject) => {
|
|
546
|
+
const ws = new import_ws.default(browserWsUrl);
|
|
547
|
+
let settled = false;
|
|
548
|
+
function settle(handler) {
|
|
549
|
+
if (settled) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
settled = true;
|
|
553
|
+
clearTimeout(timeout);
|
|
554
|
+
ws.close();
|
|
555
|
+
handler();
|
|
556
|
+
}
|
|
557
|
+
const timeout = setTimeout(() => {
|
|
558
|
+
settle(
|
|
559
|
+
() => reject(new Error("Timed out creating a blank tab via CDP."))
|
|
560
|
+
);
|
|
561
|
+
}, CREATE_BLANK_TARGET_TIMEOUT_MS);
|
|
562
|
+
ws.once("open", () => {
|
|
563
|
+
ws.send(
|
|
564
|
+
JSON.stringify({
|
|
565
|
+
id: CREATE_BLANK_TARGET_COMMAND_ID,
|
|
566
|
+
method: "Target.createTarget",
|
|
567
|
+
params: { url: "about:blank" }
|
|
568
|
+
})
|
|
569
|
+
);
|
|
570
|
+
});
|
|
571
|
+
ws.on("message", (data, isBinary) => {
|
|
572
|
+
if (isBinary) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const message = parseMessage(data);
|
|
576
|
+
if (!message || asNumber(message.id) !== CREATE_BLANK_TARGET_COMMAND_ID) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const cdpError = asObject(message.error);
|
|
580
|
+
if (cdpError) {
|
|
581
|
+
settle(
|
|
582
|
+
() => reject(
|
|
583
|
+
new Error(
|
|
584
|
+
`Target.createTarget failed: ${asString(cdpError.message) ?? JSON.stringify(cdpError)}`
|
|
585
|
+
)
|
|
586
|
+
)
|
|
587
|
+
);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const targetId = asString(asObject(message.result)?.targetId);
|
|
591
|
+
if (targetId) {
|
|
592
|
+
settle(() => resolve(targetId));
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
settle(
|
|
596
|
+
() => reject(
|
|
597
|
+
new Error(
|
|
598
|
+
"Target.createTarget succeeded but no targetId was returned."
|
|
599
|
+
)
|
|
600
|
+
)
|
|
601
|
+
);
|
|
602
|
+
});
|
|
603
|
+
ws.once("error", (err) => {
|
|
604
|
+
settle(
|
|
605
|
+
() => reject(new Error(`Failed to create blank tab: ${errorMessage(err)}`))
|
|
606
|
+
);
|
|
607
|
+
});
|
|
608
|
+
ws.once("close", () => {
|
|
609
|
+
settle(
|
|
610
|
+
() => reject(
|
|
611
|
+
new Error(
|
|
612
|
+
"CDP browser websocket closed before blank tab creation completed."
|
|
613
|
+
)
|
|
614
|
+
)
|
|
615
|
+
);
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
}
|
|
542
619
|
var CDPProxy = class {
|
|
543
620
|
constructor(browserWsUrl, targetId) {
|
|
544
621
|
this.browserWsUrl = browserWsUrl;
|
|
@@ -1022,12 +1099,13 @@ var BrowserPool = class {
|
|
|
1022
1099
|
let cdpProxy = null;
|
|
1023
1100
|
try {
|
|
1024
1101
|
const { browserWsUrl, targets } = await discoverTargets(cdpUrl);
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1102
|
+
let targetId;
|
|
1103
|
+
if (targets.length > 0) {
|
|
1104
|
+
targetId = targets[0].id;
|
|
1105
|
+
} else {
|
|
1106
|
+
targetId = await createBlankTarget(browserWsUrl);
|
|
1029
1107
|
}
|
|
1030
|
-
cdpProxy = new CDPProxy(browserWsUrl,
|
|
1108
|
+
cdpProxy = new CDPProxy(browserWsUrl, targetId);
|
|
1031
1109
|
const proxyWsUrl = await cdpProxy.start();
|
|
1032
1110
|
browser = await import_playwright.chromium.connectOverCDP(proxyWsUrl, {
|
|
1033
1111
|
timeout: timeout ?? 3e4
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
package/skills/electron/SKILL.md
CHANGED
|
@@ -12,14 +12,14 @@ Read [opensteer-electron-workflow.md](references/opensteer-electron-workflow.md)
|
|
|
12
12
|
## Core Workflow
|
|
13
13
|
|
|
14
14
|
1. Launch the Electron app with `--remote-debugging-port=<port>`.
|
|
15
|
-
2. Connect Opensteer with `open --
|
|
15
|
+
2. Connect Opensteer with `open --cdp-url http://127.0.0.1:<port>`.
|
|
16
16
|
3. List windows/webviews with `tabs`, then switch with `tab-switch`.
|
|
17
17
|
4. Run `snapshot action`, interact (`click`, `input`, `press`), then re-snapshot.
|
|
18
18
|
5. Use `snapshot extraction` and `extract` for structured data.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
# Connect Opensteer to a running Electron app on port 9222
|
|
22
|
-
opensteer open --
|
|
22
|
+
opensteer open --cdp-url http://127.0.0.1:9222 --session slack-desktop --name slack-desktop
|
|
23
23
|
|
|
24
24
|
# Discover available windows/webviews
|
|
25
25
|
opensteer tabs --session slack-desktop
|
|
@@ -65,8 +65,8 @@ Use `--description` when possible so selector paths persist for replay.
|
|
|
65
65
|
Use one Opensteer session per app:
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
opensteer open --
|
|
69
|
-
opensteer open --
|
|
68
|
+
opensteer open --cdp-url http://127.0.0.1:9222 --session slack --name slack-electron
|
|
69
|
+
opensteer open --cdp-url http://127.0.0.1:9223 --session vscode --name vscode-electron
|
|
70
70
|
|
|
71
71
|
opensteer snapshot action --session slack
|
|
72
72
|
opensteer snapshot action --session vscode
|
|
@@ -78,6 +78,8 @@ opensteer snapshot action --session vscode
|
|
|
78
78
|
- Re-snapshot after each navigation or large UI change before reusing counters.
|
|
79
79
|
- Keep `--name` stable inside a session for deterministic selector replay.
|
|
80
80
|
- Close sessions when done: `opensteer close --session <id>`.
|
|
81
|
+
- If the app has no visible page targets, Opensteer creates one automatically.
|
|
82
|
+
- If `--cdp-url` connection fails, verify with `curl -s http://127.0.0.1:<port>/json/version`.
|
|
81
83
|
|
|
82
84
|
## References
|
|
83
85
|
|
|
@@ -29,7 +29,7 @@ curl -s http://127.0.0.1:9222/json/version
|
|
|
29
29
|
## Connect and Select Target
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
opensteer open --
|
|
32
|
+
opensteer open --cdp-url http://127.0.0.1:9222 --session electron --name electron
|
|
33
33
|
opensteer tabs --session electron
|
|
34
34
|
opensteer tab-switch 0 --session electron
|
|
35
35
|
opensteer snapshot action --session electron
|
|
@@ -63,10 +63,10 @@ opensteer extract '{"items":[{"title":{"element":15},"meta":{"element":16}}]}' \
|
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
65
|
# Slack
|
|
66
|
-
opensteer open --
|
|
66
|
+
opensteer open --cdp-url http://127.0.0.1:9222 --session slack --name slack-electron
|
|
67
67
|
|
|
68
68
|
# VS Code
|
|
69
|
-
opensteer open --
|
|
69
|
+
opensteer open --cdp-url http://127.0.0.1:9223 --session vscode --name vscode-electron
|
|
70
70
|
|
|
71
71
|
opensteer snapshot action --session slack
|
|
72
72
|
opensteer snapshot action --session vscode
|
|
@@ -84,3 +84,5 @@ opensteer snapshot action --session vscode
|
|
|
84
84
|
- UI changed and counters are stale; take a fresh `snapshot action`.
|
|
85
85
|
- Wrong selectors on replay:
|
|
86
86
|
- `--description` string differs from the original text; use exact wording.
|
|
87
|
+
- Connection works but extraction returns empty:
|
|
88
|
+
- The Electron app may render in a webview. Use `opensteer tabs` + `opensteer tab-switch` to find the correct target.
|
|
@@ -7,12 +7,12 @@ This document describes the Opensteer-native flow for automating Electron apps.
|
|
|
7
7
|
Electron apps embed Chromium. Opensteer connects through Chrome DevTools Protocol (CDP):
|
|
8
8
|
|
|
9
9
|
- Launch app with `--remote-debugging-port=<port>`
|
|
10
|
-
- Attach with `opensteer open --
|
|
10
|
+
- Attach with `opensteer open --cdp-url http://127.0.0.1:<port>`
|
|
11
11
|
|
|
12
12
|
Example:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
opensteer open --
|
|
15
|
+
opensteer open --cdp-url http://127.0.0.1:9222 --session electron --name electron
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
`--session` controls runtime routing (which daemon/browser instance handles commands).
|
|
@@ -166,11 +166,22 @@ Run with: `npx tsx scraper.ts`
|
|
|
166
166
|
|
|
167
167
|
## Edge Cases
|
|
168
168
|
|
|
169
|
-
**Connect to
|
|
169
|
+
**Connect to a running browser (CDP):**
|
|
170
170
|
```bash
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
# Verify CDP is reachable first:
|
|
172
|
+
curl -s http://127.0.0.1:9222/json/version
|
|
173
|
+
|
|
174
|
+
# Connect (works even if Chrome has zero open tabs):
|
|
175
|
+
opensteer open --cdp-url http://localhost:9222 --name "my-scraper"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Real browser mode (your actual Chrome profile):**
|
|
179
|
+
```bash
|
|
180
|
+
opensteer open https://example.com --browser real --name "my-scraper" # headless
|
|
181
|
+
opensteer open https://example.com --browser real --headed --name "my-scraper" # visible window
|
|
182
|
+
opensteer open https://example.com --browser real --profile "Profile 1" --headed # specific profile
|
|
173
183
|
```
|
|
184
|
+
`--browser real` clones your local Chrome profile. Defaults to headless — add `--headed` to see the window. Profile cloning takes several seconds; do not assume the command hung.
|
|
174
185
|
|
|
175
186
|
**Tab management:**
|
|
176
187
|
```bash
|
|
@@ -184,6 +195,9 @@ opensteer tab-close 1
|
|
|
184
195
|
1. SPA content not loaded — add `opensteer.waitForText()` before extraction.
|
|
185
196
|
2. Missing cache — re-run Phase 1 caching step for the page type that failed.
|
|
186
197
|
3. Obstacle blocking target — cookie banner, modal, or login wall. Dismiss it first.
|
|
198
|
+
4. Timeout on navigation — increase timeout: `opensteer navigate <url> --timeout 60000`.
|
|
199
|
+
5. CDP connection refused — verify `curl -s http://127.0.0.1:<port>/json/version` returns JSON.
|
|
200
|
+
6. Stale counters — take a fresh `snapshot action` and re-identify elements.
|
|
187
201
|
|
|
188
202
|
### Advanced: Direct Page Access (rare)
|
|
189
203
|
|
|
@@ -16,7 +16,10 @@ Global flags: `--session <id>`, `--name <namespace>`, `--headless`, `--descripti
|
|
|
16
16
|
opensteer open <url> # Open browser, navigate to URL
|
|
17
17
|
opensteer open <url> --name "my-scraper" # Set selector cache namespace
|
|
18
18
|
opensteer open <url> --headless # Headless mode
|
|
19
|
-
opensteer open --
|
|
19
|
+
opensteer open --cdp-url http://localhost:9222 # Connect to running browser via CDP
|
|
20
|
+
opensteer open <url> --browser real # Use real Chrome profile (headless)
|
|
21
|
+
opensteer open <url> --browser real --headed # Real Chrome, visible window
|
|
22
|
+
opensteer open <url> --browser real --profile "Work" # Specific Chrome profile
|
|
20
23
|
opensteer navigate <url> # Navigate with visual stability wait
|
|
21
24
|
opensteer navigate <url> --timeout 60000 # Custom timeout (default 30s)
|
|
22
25
|
opensteer back # Go back in history
|