dev3000 0.0.174 → 0.0.175
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/README.md +0 -4
- package/dist/cdp-monitor.d.ts +3 -0
- package/dist/cdp-monitor.d.ts.map +1 -1
- package/dist/cdp-monitor.js +225 -38
- package/dist/cdp-monitor.js.map +1 -1
- package/dist/cli.js +172 -217
- package/dist/cli.js.map +1 -1
- package/dist/commands/crawl.d.ts.map +1 -1
- package/dist/commands/crawl.js +4 -43
- package/dist/commands/crawl.js.map +1 -1
- package/dist/commands/errors.d.ts.map +1 -1
- package/dist/commands/errors.js +4 -53
- package/dist/commands/errors.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +5 -74
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +4 -53
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/skill-runner.d.ts +14 -0
- package/dist/commands/skill-runner.d.ts.map +1 -0
- package/dist/commands/skill-runner.js +494 -0
- package/dist/commands/skill-runner.js.map +1 -0
- package/dist/dev-environment.d.ts +4 -3
- package/dist/dev-environment.d.ts.map +1 -1
- package/dist/dev-environment.js +111 -95
- package/dist/dev-environment.js.map +1 -1
- package/dist/skills/d3k/internal-skill.md +145 -0
- package/dist/skills/index.test.ts +28 -1
- package/dist/skills/index.ts +58 -7
- package/dist/utils/agent-browser.d.ts.map +1 -1
- package/dist/utils/agent-browser.js +6 -3
- package/dist/utils/agent-browser.js.map +1 -1
- package/dist/utils/agent-detection.d.ts +1 -0
- package/dist/utils/agent-detection.d.ts.map +1 -1
- package/dist/utils/agent-detection.js +11 -0
- package/dist/utils/agent-detection.js.map +1 -1
- package/dist/utils/agent-selection.js +3 -3
- package/dist/utils/agent-selection.js.map +1 -1
- package/dist/utils/browser-command-argv.d.ts +1 -1
- package/dist/utils/browser-command-argv.d.ts.map +1 -1
- package/dist/utils/browser-command-argv.js +1 -1
- package/dist/utils/browser-command-argv.js.map +1 -1
- package/dist/utils/project-name.d.ts +2 -0
- package/dist/utils/project-name.d.ts.map +1 -1
- package/dist/utils/project-name.js +6 -0
- package/dist/utils/project-name.js.map +1 -1
- package/dist/utils/session.d.ts +14 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/dist/utils/session.js +65 -0
- package/dist/utils/session.js.map +1 -0
- package/dist/utils/version-check.js +2 -2
- package/dist/utils/version-check.js.map +1 -1
- package/package.json +8 -18
- package/dist/commands/cloud-check-pr.d.ts +0 -9
- package/dist/commands/cloud-check-pr.d.ts.map +0 -1
- package/dist/commands/cloud-check-pr.js +0 -243
- package/dist/commands/cloud-check-pr.js.map +0 -1
- package/dist/commands/cloud-fix.d.ts +0 -13
- package/dist/commands/cloud-fix.d.ts.map +0 -1
- package/dist/commands/cloud-fix.js +0 -79
- package/dist/commands/cloud-fix.js.map +0 -1
- package/dist/commands/find-component.d.ts +0 -8
- package/dist/commands/find-component.d.ts.map +0 -1
- package/dist/commands/find-component.js +0 -182
- package/dist/commands/find-component.js.map +0 -1
- package/dist/skills/d3k/SKILL.md +0 -126
- package/dist/skills/index.d.ts +0 -46
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js +0 -174
- package/dist/skills/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -62,9 +62,6 @@ d3k fix --time 30 # Analyze last 30 minutes (default: 10)
|
|
|
62
62
|
d3k crawl # Discover URLs by crawling the app
|
|
63
63
|
d3k crawl --depth all # Exhaustive crawl (default: 1 level)
|
|
64
64
|
|
|
65
|
-
d3k find-component "nav.header" # Find React component source
|
|
66
|
-
d3k find-component "[data-testid='button']"
|
|
67
|
-
|
|
68
65
|
d3k restart # Restart the development server (rarely needed)
|
|
69
66
|
```
|
|
70
67
|
|
|
@@ -74,7 +71,6 @@ d3k restart # Restart the development server (rarely needed)
|
|
|
74
71
|
d3k skill [name] # Get skill content or list available skills
|
|
75
72
|
d3k upgrade # Upgrade d3k to the latest version
|
|
76
73
|
d3k agent-browser # Run the bundled agent-browser CLI
|
|
77
|
-
d3k cloud # Cloud-based tools using Vercel Sandbox
|
|
78
74
|
```
|
|
79
75
|
|
|
80
76
|
## Options
|
package/dist/cdp-monitor.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface CDPTargetInfo {
|
|
|
17
17
|
url?: string;
|
|
18
18
|
webSocketDebuggerUrl?: string;
|
|
19
19
|
}
|
|
20
|
+
export declare const CHROME_CRASH_RESTORE_SUPPRESSION_FLAGS: string[];
|
|
21
|
+
export declare function resetChromeCrashRestoreState(profileDir: string): number;
|
|
20
22
|
export declare function getLoadingHtmlCandidates(currentDir: string, execPath?: string): string[];
|
|
21
23
|
export declare function selectCDPTarget(targets: CDPTargetInfo[], options?: {
|
|
22
24
|
appServerPort?: string;
|
|
@@ -114,6 +116,7 @@ export declare class CDPMonitor {
|
|
|
114
116
|
*/
|
|
115
117
|
prepareShutdown(): void;
|
|
116
118
|
private waitForBrowserExit;
|
|
119
|
+
private sendBrowserCloseCommand;
|
|
117
120
|
shutdown(): Promise<void>;
|
|
118
121
|
private killInstanceChromeProcesses;
|
|
119
122
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdp-monitor.d.ts","sourceRoot":"","sources":["../src/cdp-monitor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AAE9B,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,SAAS,CAAA;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;
|
|
1
|
+
{"version":3,"file":"cdp-monitor.d.ts","sourceRoot":"","sources":["../src/cdp-monitor.ts"],"names":[],"mappings":"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"}
|
package/dist/cdp-monitor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
-
import { existsSync, mkdtempSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { existsSync, mkdtempSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import { tmpdir } from "os";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
@@ -45,6 +45,98 @@ const EMBEDDED_LOADING_HTML = `<!DOCTYPE html>
|
|
|
45
45
|
</html>`;
|
|
46
46
|
const DEFAULT_CDP_COMMAND_TIMEOUT_MS = 10000;
|
|
47
47
|
const DEFAULT_NAVIGATION_TIMEOUT_MS = 60000;
|
|
48
|
+
export const CHROME_CRASH_RESTORE_SUPPRESSION_FLAGS = [
|
|
49
|
+
"--disable-session-crashed-bubble",
|
|
50
|
+
"--disable-restore-session-state",
|
|
51
|
+
"--hide-crash-restore-bubble"
|
|
52
|
+
];
|
|
53
|
+
function isRecord(value) {
|
|
54
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
55
|
+
}
|
|
56
|
+
function patchChromePreferences(data) {
|
|
57
|
+
let changed = false;
|
|
58
|
+
const profile = isRecord(data.profile) ? data.profile : {};
|
|
59
|
+
if (data.profile !== profile) {
|
|
60
|
+
data.profile = profile;
|
|
61
|
+
changed = true;
|
|
62
|
+
}
|
|
63
|
+
if (profile.exit_type !== "Normal") {
|
|
64
|
+
profile.exit_type = "Normal";
|
|
65
|
+
changed = true;
|
|
66
|
+
}
|
|
67
|
+
if (profile.exited_cleanly !== true) {
|
|
68
|
+
profile.exited_cleanly = true;
|
|
69
|
+
changed = true;
|
|
70
|
+
}
|
|
71
|
+
return changed;
|
|
72
|
+
}
|
|
73
|
+
function patchChromeLocalState(data) {
|
|
74
|
+
let changed = false;
|
|
75
|
+
if (data.exit_type === "Crashed") {
|
|
76
|
+
data.exit_type = "Normal";
|
|
77
|
+
changed = true;
|
|
78
|
+
}
|
|
79
|
+
if (data.exited_cleanly === false) {
|
|
80
|
+
data.exited_cleanly = true;
|
|
81
|
+
changed = true;
|
|
82
|
+
}
|
|
83
|
+
if (isRecord(data.profile)) {
|
|
84
|
+
if (data.profile.exit_type === "Crashed") {
|
|
85
|
+
data.profile.exit_type = "Normal";
|
|
86
|
+
changed = true;
|
|
87
|
+
}
|
|
88
|
+
if (data.profile.exited_cleanly === false) {
|
|
89
|
+
data.profile.exited_cleanly = true;
|
|
90
|
+
changed = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return changed;
|
|
94
|
+
}
|
|
95
|
+
function patchJsonFile(filePath, patch) {
|
|
96
|
+
if (!existsSync(filePath)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const data = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
101
|
+
if (!isRecord(data) || !patch(data)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
writeFileSync(filePath, JSON.stringify(data));
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function getChromePreferencesFiles(profileDir) {
|
|
112
|
+
const files = new Set([join(profileDir, "Default", "Preferences")]);
|
|
113
|
+
if (!existsSync(profileDir)) {
|
|
114
|
+
return Array.from(files);
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
for (const entry of readdirSync(profileDir, { withFileTypes: true })) {
|
|
118
|
+
if (entry.isDirectory() && (entry.name === "Default" || entry.name.startsWith("Profile "))) {
|
|
119
|
+
files.add(join(profileDir, entry.name, "Preferences"));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Ignore unreadable profile directories.
|
|
125
|
+
}
|
|
126
|
+
return Array.from(files);
|
|
127
|
+
}
|
|
128
|
+
export function resetChromeCrashRestoreState(profileDir) {
|
|
129
|
+
let changedFiles = 0;
|
|
130
|
+
for (const preferencesFile of getChromePreferencesFiles(profileDir)) {
|
|
131
|
+
if (patchJsonFile(preferencesFile, patchChromePreferences)) {
|
|
132
|
+
changedFiles++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (patchJsonFile(join(profileDir, "Local State"), patchChromeLocalState)) {
|
|
136
|
+
changedFiles++;
|
|
137
|
+
}
|
|
138
|
+
return changedFiles;
|
|
139
|
+
}
|
|
48
140
|
export function getLoadingHtmlCandidates(currentDir, execPath = process.execPath) {
|
|
49
141
|
const candidates = [join(currentDir, "src/loading.html"), join(currentDir, "loading.html")];
|
|
50
142
|
const packageRoot = dirname(dirname(execPath));
|
|
@@ -438,10 +530,21 @@ export class CDPMonitor {
|
|
|
438
530
|
*/
|
|
439
531
|
async killExistingChromeWithProfile() {
|
|
440
532
|
try {
|
|
441
|
-
//
|
|
533
|
+
// Build a set of PIDs that must never be killed: this Node process and
|
|
534
|
+
// its parent. d3k's own argv contains the profile path (via --profile-dir),
|
|
535
|
+
// which previously caused a substring match here and made d3k SIGTERM itself.
|
|
536
|
+
const selfPids = new Set();
|
|
537
|
+
if (typeof process.pid === "number")
|
|
538
|
+
selfPids.add(process.pid);
|
|
539
|
+
if (typeof process.ppid === "number")
|
|
540
|
+
selfPids.add(process.ppid);
|
|
541
|
+
// Find Chrome processes using this profile directory. We only match the
|
|
542
|
+
// canonical `--user-data-dir=<profile>` form Chrome consumes; matching the
|
|
543
|
+
// bare path was too loose and caught unrelated processes (including d3k itself).
|
|
442
544
|
const processes = await this.listProcesses();
|
|
443
545
|
const pids = processes
|
|
444
|
-
.filter((proc) =>
|
|
546
|
+
.filter((proc) => !selfPids.has(proc.pid))
|
|
547
|
+
.filter((proc) => proc.command.includes(`--user-data-dir=${this.profileDir}`))
|
|
445
548
|
.map((proc) => proc.pid)
|
|
446
549
|
.filter((pid) => pid !== this.browser?.pid);
|
|
447
550
|
for (const pid of pids) {
|
|
@@ -465,6 +568,10 @@ export class CDPMonitor {
|
|
|
465
568
|
async launchChrome() {
|
|
466
569
|
// Kill any existing Chrome using this profile to prevent CDP conflicts
|
|
467
570
|
await this.killExistingChromeWithProfile();
|
|
571
|
+
const resetProfileFiles = resetChromeCrashRestoreState(this.profileDir);
|
|
572
|
+
if (resetProfileFiles > 0) {
|
|
573
|
+
this.debugLog(`Reset Chrome crash restore state in ${resetProfileFiles} profile file(s)`);
|
|
574
|
+
}
|
|
468
575
|
return new Promise((resolve, reject) => {
|
|
469
576
|
// Use custom browser path if provided, otherwise try different Chrome executables based on platform
|
|
470
577
|
const chromeCommands = this.browserPath
|
|
@@ -474,6 +581,8 @@ export class CDPMonitor {
|
|
|
474
581
|
"google-chrome",
|
|
475
582
|
"chrome",
|
|
476
583
|
"chromium",
|
|
584
|
+
"brave",
|
|
585
|
+
"brave-browser",
|
|
477
586
|
"/Applications/Arc.app/Contents/MacOS/Arc",
|
|
478
587
|
"/Applications/Comet.app/Contents/MacOS/Comet",
|
|
479
588
|
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
|
|
@@ -513,8 +622,7 @@ export class CDPMonitor {
|
|
|
513
622
|
"--disable-sync",
|
|
514
623
|
"--metrics-recording-only",
|
|
515
624
|
"--disable-default-apps",
|
|
516
|
-
|
|
517
|
-
"--disable-restore-session-state"
|
|
625
|
+
...CHROME_CRASH_RESTORE_SUPPRESSION_FLAGS
|
|
518
626
|
];
|
|
519
627
|
if (shouldEnableReactDevTools && reactDevToolsExtensionPath) {
|
|
520
628
|
chromeArgs.push(`--disable-extensions-except=${reactDevToolsExtensionPath}`);
|
|
@@ -1774,49 +1882,128 @@ export class CDPMonitor {
|
|
|
1774
1882
|
browser.once("exit", onExit);
|
|
1775
1883
|
});
|
|
1776
1884
|
}
|
|
1885
|
+
async sendBrowserCloseCommand() {
|
|
1886
|
+
try {
|
|
1887
|
+
await this.sendCDPCommand("Browser.close", {}, 3000);
|
|
1888
|
+
this.debugLog("Sent Browser.close command");
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
catch (error) {
|
|
1892
|
+
this.debugLog(`Browser.close on page target failed: ${error}`);
|
|
1893
|
+
}
|
|
1894
|
+
const versionResponse = await fetch(`http://localhost:${this.debugPort}/json/version`, {
|
|
1895
|
+
signal: AbortSignal.timeout(1000)
|
|
1896
|
+
});
|
|
1897
|
+
if (!versionResponse.ok) {
|
|
1898
|
+
throw new Error(`Failed to get browser CDP endpoint: HTTP ${versionResponse.status}`);
|
|
1899
|
+
}
|
|
1900
|
+
const version = (await versionResponse.json());
|
|
1901
|
+
if (!version.webSocketDebuggerUrl) {
|
|
1902
|
+
throw new Error("Browser CDP endpoint did not include webSocketDebuggerUrl");
|
|
1903
|
+
}
|
|
1904
|
+
await new Promise((resolve, reject) => {
|
|
1905
|
+
const ws = new WebSocket(version.webSocketDebuggerUrl);
|
|
1906
|
+
let commandSent = false;
|
|
1907
|
+
let settled = false;
|
|
1908
|
+
const settle = (callback) => {
|
|
1909
|
+
if (settled)
|
|
1910
|
+
return;
|
|
1911
|
+
settled = true;
|
|
1912
|
+
clearTimeout(timeout);
|
|
1913
|
+
try {
|
|
1914
|
+
ws.close();
|
|
1915
|
+
}
|
|
1916
|
+
catch {
|
|
1917
|
+
// Ignore close errors.
|
|
1918
|
+
}
|
|
1919
|
+
callback();
|
|
1920
|
+
};
|
|
1921
|
+
const timeout = setTimeout(() => {
|
|
1922
|
+
settle(() => reject(new Error("Browser.close command timed out")));
|
|
1923
|
+
}, 3000);
|
|
1924
|
+
ws.on("open", () => {
|
|
1925
|
+
commandSent = true;
|
|
1926
|
+
ws.send(JSON.stringify({ id: 1, method: "Browser.close", params: {} }), (error) => {
|
|
1927
|
+
if (error) {
|
|
1928
|
+
settle(() => reject(error));
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
});
|
|
1932
|
+
ws.on("message", (data) => {
|
|
1933
|
+
try {
|
|
1934
|
+
const message = JSON.parse(data.toString());
|
|
1935
|
+
if (message.id !== 1) {
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
const responseError = message.error;
|
|
1939
|
+
if (responseError) {
|
|
1940
|
+
settle(() => reject(new Error(responseError.message || "Browser.close failed")));
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
settle(resolve);
|
|
1944
|
+
}
|
|
1945
|
+
catch (error) {
|
|
1946
|
+
settle(() => reject(error instanceof Error ? error : new Error(String(error))));
|
|
1947
|
+
}
|
|
1948
|
+
});
|
|
1949
|
+
ws.on("error", (error) => {
|
|
1950
|
+
settle(() => reject(error));
|
|
1951
|
+
});
|
|
1952
|
+
ws.on("close", () => {
|
|
1953
|
+
if (commandSent) {
|
|
1954
|
+
settle(resolve);
|
|
1955
|
+
}
|
|
1956
|
+
else {
|
|
1957
|
+
settle(() => reject(new Error("Browser CDP websocket closed before Browser.close was sent")));
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
});
|
|
1961
|
+
this.debugLog("Sent Browser.close command via browser CDP endpoint");
|
|
1962
|
+
}
|
|
1777
1963
|
async shutdown() {
|
|
1778
1964
|
this.isShuttingDown = true;
|
|
1779
1965
|
let browserClosedCleanly = false;
|
|
1780
1966
|
// Ask the browser process to exit first so Chrome doesn't think it crashed.
|
|
1781
|
-
if (this.connection
|
|
1967
|
+
if (this.connection) {
|
|
1782
1968
|
try {
|
|
1783
|
-
await this.
|
|
1784
|
-
this.
|
|
1785
|
-
browserClosedCleanly = await this.waitForBrowserExit(2000);
|
|
1969
|
+
await this.sendBrowserCloseCommand();
|
|
1970
|
+
browserClosedCleanly = await this.waitForBrowserExit(5000);
|
|
1786
1971
|
}
|
|
1787
1972
|
catch (_e) {
|
|
1788
1973
|
this.debugLog("Browser.close failed, trying page/tab close fallback");
|
|
1789
1974
|
}
|
|
1790
|
-
try {
|
|
1791
|
-
// Try to close the page
|
|
1792
|
-
await this.sendCDPCommand("Page.close");
|
|
1793
|
-
this.debugLog("Sent Page.close command");
|
|
1794
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1795
|
-
}
|
|
1796
|
-
catch (_e) {
|
|
1797
|
-
this.debugLog("Page.close failed, trying Target.closeTarget");
|
|
1798
|
-
}
|
|
1799
|
-
try {
|
|
1800
|
-
// Get the list of targets to find our specific tab
|
|
1801
|
-
const targets = (await this.sendCDPCommand("Target.getTargets"));
|
|
1802
|
-
this.debugLog(`Found ${targets.targetInfos?.length || 0} targets`);
|
|
1803
|
-
// Find our page target
|
|
1804
|
-
const pageTarget = targets.targetInfos?.find((t) => t.type === "page");
|
|
1805
|
-
if (pageTarget) {
|
|
1806
|
-
this.debugLog(`Closing page target: ${pageTarget.targetId}`);
|
|
1807
|
-
await this.sendCDPCommand("Target.closeTarget", {
|
|
1808
|
-
targetId: pageTarget.targetId
|
|
1809
|
-
});
|
|
1810
|
-
this.debugLog("Closed Chrome tab via CDP");
|
|
1811
|
-
}
|
|
1812
|
-
// Give it more time for the tab to close
|
|
1813
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
1814
|
-
}
|
|
1815
|
-
catch (_e) {
|
|
1816
|
-
this.debugLog("Failed to close tab via CDP, will force close Chrome");
|
|
1817
|
-
}
|
|
1818
1975
|
if (!browserClosedCleanly) {
|
|
1819
|
-
|
|
1976
|
+
try {
|
|
1977
|
+
// Try to close the page
|
|
1978
|
+
await this.sendCDPCommand("Page.close");
|
|
1979
|
+
this.debugLog("Sent Page.close command");
|
|
1980
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1981
|
+
}
|
|
1982
|
+
catch (_e) {
|
|
1983
|
+
this.debugLog("Page.close failed, trying Target.closeTarget");
|
|
1984
|
+
}
|
|
1985
|
+
try {
|
|
1986
|
+
// Get the list of targets to find our specific tab
|
|
1987
|
+
const targets = (await this.sendCDPCommand("Target.getTargets"));
|
|
1988
|
+
this.debugLog(`Found ${targets.targetInfos?.length || 0} targets`);
|
|
1989
|
+
// Find our page target
|
|
1990
|
+
const pageTarget = targets.targetInfos?.find((t) => t.type === "page");
|
|
1991
|
+
if (pageTarget) {
|
|
1992
|
+
this.debugLog(`Closing page target: ${pageTarget.targetId}`);
|
|
1993
|
+
await this.sendCDPCommand("Target.closeTarget", {
|
|
1994
|
+
targetId: pageTarget.targetId
|
|
1995
|
+
});
|
|
1996
|
+
this.debugLog("Closed Chrome tab via CDP");
|
|
1997
|
+
}
|
|
1998
|
+
// Give it more time for the tab to close
|
|
1999
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2000
|
+
}
|
|
2001
|
+
catch (_e) {
|
|
2002
|
+
this.debugLog("Failed to close tab via CDP, will force close Chrome");
|
|
2003
|
+
}
|
|
2004
|
+
if (!browserClosedCleanly) {
|
|
2005
|
+
browserClosedCleanly = await this.waitForBrowserExit(1500);
|
|
2006
|
+
}
|
|
1820
2007
|
}
|
|
1821
2008
|
}
|
|
1822
2009
|
// Close CDP connection
|