assistme 0.1.8 → 0.1.10
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/index.js +86 -29
- package/package.json +1 -1
- package/src/tools/browser.ts +110 -31
package/dist/index.js
CHANGED
|
@@ -394,7 +394,7 @@ import {
|
|
|
394
394
|
import { WebSocket } from "ws";
|
|
395
395
|
import { execSync, spawn } from "child_process";
|
|
396
396
|
import { platform } from "os";
|
|
397
|
-
import { existsSync } from "fs";
|
|
397
|
+
import { existsSync, unlinkSync } from "fs";
|
|
398
398
|
var BrowserController = class {
|
|
399
399
|
ws = null;
|
|
400
400
|
debugPort;
|
|
@@ -860,7 +860,7 @@ function isChromeRunning() {
|
|
|
860
860
|
return out2.includes("chrome.exe");
|
|
861
861
|
}
|
|
862
862
|
if (platform() === "darwin") {
|
|
863
|
-
const out2 = execSync('pgrep -f "Google Chrome.app/Contents/MacOS/Google Chrome
|
|
863
|
+
const out2 = execSync('pgrep -f "Google Chrome.app/Contents/MacOS/Google Chrome"', {
|
|
864
864
|
encoding: "utf-8",
|
|
865
865
|
stdio: ["pipe", "pipe", "pipe"]
|
|
866
866
|
});
|
|
@@ -884,7 +884,7 @@ async function killChromeGracefully() {
|
|
|
884
884
|
stdio: ["pipe", "pipe", "pipe"]
|
|
885
885
|
});
|
|
886
886
|
} else if (os === "linux") {
|
|
887
|
-
execSync("pkill -TERM -f chrome", {
|
|
887
|
+
execSync("pkill -TERM -f '(chrome|chromium)'", {
|
|
888
888
|
timeout: 5e3,
|
|
889
889
|
stdio: ["pipe", "pipe", "pipe"]
|
|
890
890
|
});
|
|
@@ -898,44 +898,78 @@ async function killChromeGracefully() {
|
|
|
898
898
|
}
|
|
899
899
|
const start = Date.now();
|
|
900
900
|
while (Date.now() - start < 8e3) {
|
|
901
|
-
if (!isChromeRunning())
|
|
901
|
+
if (!isChromeRunning()) {
|
|
902
|
+
log.debug(`Chrome exited after ${Date.now() - start}ms`);
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
902
905
|
await new Promise((r) => setTimeout(r, 500));
|
|
903
906
|
}
|
|
907
|
+
log.debug("Chrome still running after graceful quit, force-killing...");
|
|
904
908
|
try {
|
|
905
909
|
if (os === "win32") {
|
|
906
910
|
execSync("taskkill /F /IM chrome.exe", {
|
|
907
911
|
stdio: ["pipe", "pipe", "pipe"]
|
|
908
912
|
});
|
|
909
913
|
} else {
|
|
910
|
-
execSync("pkill -9 -f chrome", {
|
|
914
|
+
execSync("pkill -9 -f '(chrome|chromium)'", {
|
|
911
915
|
stdio: ["pipe", "pipe", "pipe"]
|
|
912
916
|
});
|
|
913
917
|
}
|
|
914
918
|
} catch {
|
|
915
919
|
}
|
|
916
920
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
921
|
+
if (os !== "win32") {
|
|
922
|
+
const home = process.env.HOME;
|
|
923
|
+
if (home) {
|
|
924
|
+
const lockPaths = os === "darwin" ? [
|
|
925
|
+
`${home}/Library/Application Support/Google/Chrome/SingletonLock`,
|
|
926
|
+
`${home}/Library/Application Support/Google/Chrome/SingletonSocket`,
|
|
927
|
+
`${home}/Library/Application Support/Google/Chrome/SingletonCookie`
|
|
928
|
+
] : [
|
|
929
|
+
`${home}/.config/google-chrome/SingletonLock`,
|
|
930
|
+
`${home}/.config/google-chrome/SingletonSocket`,
|
|
931
|
+
`${home}/.config/google-chrome/SingletonCookie`,
|
|
932
|
+
`${home}/.config/chromium/SingletonLock`,
|
|
933
|
+
`${home}/.config/chromium/SingletonSocket`,
|
|
934
|
+
`${home}/.config/chromium/SingletonCookie`
|
|
935
|
+
];
|
|
936
|
+
for (const lockPath of lockPaths) {
|
|
937
|
+
try {
|
|
938
|
+
if (existsSync(lockPath)) {
|
|
939
|
+
unlinkSync(lockPath);
|
|
940
|
+
log.debug(`Removed stale lock: ${lockPath}`);
|
|
941
|
+
}
|
|
942
|
+
} catch {
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
917
947
|
}
|
|
918
948
|
function spawnChrome(chromePath, port) {
|
|
919
|
-
const os = platform();
|
|
920
949
|
const cdpFlag = `--remote-debugging-port=${port}`;
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
930
|
-
log.debug(`Spawning Chrome via: ${chromePath} ${cdpFlag} --restore-last-session`);
|
|
931
|
-
child = spawn(chromePath, [cdpFlag, "--restore-last-session"], {
|
|
932
|
-
detached: true,
|
|
933
|
-
stdio: "ignore"
|
|
934
|
-
});
|
|
935
|
-
}
|
|
950
|
+
log.debug(`Spawning Chrome: ${chromePath} ${cdpFlag} --restore-last-session`);
|
|
951
|
+
const child = spawn(chromePath, [cdpFlag, "--restore-last-session"], {
|
|
952
|
+
detached: true,
|
|
953
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
954
|
+
});
|
|
955
|
+
let stderr = "";
|
|
956
|
+
child.stderr?.on("data", (chunk) => {
|
|
957
|
+
stderr += chunk.toString();
|
|
958
|
+
});
|
|
936
959
|
child.on("error", (err) => {
|
|
937
960
|
log.error(`Chrome spawn error: ${err.message}`);
|
|
938
961
|
});
|
|
962
|
+
child.on("exit", (code, signal) => {
|
|
963
|
+
if (code !== null && code !== 0) {
|
|
964
|
+
log.debug(`Chrome exited with code ${code}${signal ? ` (signal: ${signal})` : ""}`);
|
|
965
|
+
if (stderr) {
|
|
966
|
+
const lines = stderr.split("\n").filter(Boolean).slice(0, 5);
|
|
967
|
+
for (const line of lines) {
|
|
968
|
+
log.debug(` chrome stderr: ${line}`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
});
|
|
939
973
|
child.unref();
|
|
940
974
|
return child;
|
|
941
975
|
}
|
|
@@ -989,34 +1023,57 @@ async function ensureBrowserAvailable(port = 9222) {
|
|
|
989
1023
|
if (running) {
|
|
990
1024
|
log.debug("Killing Chrome gracefully for restart with CDP...");
|
|
991
1025
|
await killChromeGracefully();
|
|
992
|
-
|
|
1026
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
1027
|
+
const child2 = spawnChrome(chromePath, port);
|
|
993
1028
|
if (await waitForCDP(browser)) {
|
|
994
1029
|
return { success: true, action: "restarted", chromePath };
|
|
995
1030
|
}
|
|
1031
|
+
if (child2.exitCode !== null) {
|
|
1032
|
+
log.debug(
|
|
1033
|
+
`Chrome process already exited (code ${child2.exitCode}) \u2014 may have crashed or profile is locked`
|
|
1034
|
+
);
|
|
1035
|
+
return {
|
|
1036
|
+
success: false,
|
|
1037
|
+
action: "launch_failed",
|
|
1038
|
+
chromePath,
|
|
1039
|
+
detail: `Chrome exited immediately (code ${child2.exitCode}). This often means the profile is locked by another Chrome instance. Try closing all Chrome windows first, then run assistme again.`
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
996
1042
|
log.debug("First CDP wait timed out after restart, retrying...");
|
|
997
1043
|
if (await waitForCDP(browser, 15e3)) {
|
|
998
1044
|
return { success: true, action: "restarted", chromePath };
|
|
999
1045
|
}
|
|
1046
|
+
const stillRunning2 = isChromeRunning();
|
|
1000
1047
|
return {
|
|
1001
1048
|
success: false,
|
|
1002
1049
|
action: "launch_failed",
|
|
1003
1050
|
chromePath,
|
|
1004
|
-
detail: "Chrome
|
|
1051
|
+
detail: stillRunning2 ? "Chrome is running but CDP port is not responding. Chrome may have started without the --remote-debugging-port flag. Try: 1) Quit Chrome completely, 2) Run assistme again." : "Chrome was restarted but exited unexpectedly. Check if Chrome can start normally from the command line."
|
|
1005
1052
|
};
|
|
1006
1053
|
}
|
|
1007
|
-
spawnChrome(chromePath, port);
|
|
1054
|
+
const child = spawnChrome(chromePath, port);
|
|
1008
1055
|
if (await waitForCDP(browser)) {
|
|
1009
1056
|
return { success: true, action: "launched", chromePath };
|
|
1010
1057
|
}
|
|
1058
|
+
if (child.exitCode !== null) {
|
|
1059
|
+
log.debug(`Chrome process already exited (code ${child.exitCode})`);
|
|
1060
|
+
return {
|
|
1061
|
+
success: false,
|
|
1062
|
+
action: "launch_failed",
|
|
1063
|
+
chromePath,
|
|
1064
|
+
detail: `Chrome exited immediately (code ${child.exitCode}). Try launching Chrome manually to see any error dialogs.`
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1011
1067
|
log.debug("First CDP wait timed out after launch, retrying...");
|
|
1012
1068
|
if (await waitForCDP(browser, 15e3)) {
|
|
1013
1069
|
return { success: true, action: "launched", chromePath };
|
|
1014
1070
|
}
|
|
1071
|
+
const stillRunning = isChromeRunning();
|
|
1015
1072
|
return {
|
|
1016
1073
|
success: false,
|
|
1017
1074
|
action: "launch_failed",
|
|
1018
1075
|
chromePath,
|
|
1019
|
-
detail: "Chrome
|
|
1076
|
+
detail: stillRunning ? "Chrome is running but CDP port is not responding. Try quitting Chrome completely and running assistme again." : "Chrome exited unexpectedly after launch."
|
|
1020
1077
|
};
|
|
1021
1078
|
}
|
|
1022
1079
|
var browserInstance = null;
|
|
@@ -1172,7 +1229,7 @@ import {
|
|
|
1172
1229
|
readFileSync,
|
|
1173
1230
|
writeFileSync,
|
|
1174
1231
|
statSync,
|
|
1175
|
-
unlinkSync,
|
|
1232
|
+
unlinkSync as unlinkSync2,
|
|
1176
1233
|
rmSync
|
|
1177
1234
|
} from "fs";
|
|
1178
1235
|
import { join, basename, dirname } from "path";
|
|
@@ -1592,9 +1649,9 @@ ${content}
|
|
|
1592
1649
|
await execUnzip(`unzip -o "${zipPath}" -d "${skillDir}"`, {
|
|
1593
1650
|
timeout: 15e3
|
|
1594
1651
|
});
|
|
1595
|
-
|
|
1652
|
+
unlinkSync2(zipPath);
|
|
1596
1653
|
} catch {
|
|
1597
|
-
|
|
1654
|
+
unlinkSync2(zipPath);
|
|
1598
1655
|
const fileResp = await fetch(
|
|
1599
1656
|
`${CLAWHUB_API}/skills/${encodeURIComponent(name)}/file?path=SKILL.md&tag=latest`
|
|
1600
1657
|
);
|
|
@@ -1665,7 +1722,7 @@ ${content}
|
|
|
1665
1722
|
if (dir !== SKILLS_DIR) {
|
|
1666
1723
|
rmSync(dir, { recursive: true, force: true });
|
|
1667
1724
|
} else {
|
|
1668
|
-
|
|
1725
|
+
unlinkSync2(skill.filePath);
|
|
1669
1726
|
}
|
|
1670
1727
|
this.skills.delete(name);
|
|
1671
1728
|
return true;
|
package/package.json
CHANGED
package/src/tools/browser.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { WebSocket } from "ws";
|
|
18
18
|
import { execSync, spawn, type ChildProcess } from "node:child_process";
|
|
19
19
|
import { platform } from "node:os";
|
|
20
|
-
import { existsSync } from "node:fs";
|
|
20
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
21
21
|
import { log } from "../utils/logger.js";
|
|
22
22
|
|
|
23
23
|
interface CDPTab {
|
|
@@ -607,8 +607,9 @@ export function isChromeRunning(): boolean {
|
|
|
607
607
|
return out.includes("chrome.exe");
|
|
608
608
|
}
|
|
609
609
|
if (platform() === "darwin") {
|
|
610
|
-
// Match the
|
|
611
|
-
|
|
610
|
+
// Match the main Chrome process (not helper/renderer sub-processes).
|
|
611
|
+
// No trailing $ — the process command line includes flags after the binary.
|
|
612
|
+
const out = execSync('pgrep -f "Google Chrome.app/Contents/MacOS/Google Chrome"', {
|
|
612
613
|
encoding: "utf-8",
|
|
613
614
|
stdio: ["pipe", "pipe", "pipe"],
|
|
614
615
|
});
|
|
@@ -638,7 +639,7 @@ async function killChromeGracefully(): Promise<void> {
|
|
|
638
639
|
stdio: ["pipe", "pipe", "pipe"],
|
|
639
640
|
});
|
|
640
641
|
} else if (os === "linux") {
|
|
641
|
-
execSync("pkill -TERM -f chrome", {
|
|
642
|
+
execSync("pkill -TERM -f '(chrome|chromium)'", {
|
|
642
643
|
timeout: 5000,
|
|
643
644
|
stdio: ["pipe", "pipe", "pipe"],
|
|
644
645
|
});
|
|
@@ -655,10 +656,15 @@ async function killChromeGracefully(): Promise<void> {
|
|
|
655
656
|
// Wait for Chrome to fully exit (up to 8s)
|
|
656
657
|
const start = Date.now();
|
|
657
658
|
while (Date.now() - start < 8000) {
|
|
658
|
-
if (!isChromeRunning())
|
|
659
|
+
if (!isChromeRunning()) {
|
|
660
|
+
log.debug(`Chrome exited after ${Date.now() - start}ms`);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
659
663
|
await new Promise((r) => setTimeout(r, 500));
|
|
660
664
|
}
|
|
661
665
|
|
|
666
|
+
log.debug("Chrome still running after graceful quit, force-killing...");
|
|
667
|
+
|
|
662
668
|
// Force kill if still alive
|
|
663
669
|
try {
|
|
664
670
|
if (os === "win32") {
|
|
@@ -666,14 +672,49 @@ async function killChromeGracefully(): Promise<void> {
|
|
|
666
672
|
stdio: ["pipe", "pipe", "pipe"],
|
|
667
673
|
});
|
|
668
674
|
} else {
|
|
669
|
-
execSync("pkill -9 -f chrome", {
|
|
675
|
+
execSync("pkill -9 -f '(chrome|chromium)'", {
|
|
670
676
|
stdio: ["pipe", "pipe", "pipe"],
|
|
671
677
|
});
|
|
672
678
|
}
|
|
673
679
|
} catch {
|
|
674
680
|
/* already dead */
|
|
675
681
|
}
|
|
682
|
+
|
|
683
|
+
// Wait for processes to fully terminate after SIGKILL
|
|
676
684
|
await new Promise((r) => setTimeout(r, 1000));
|
|
685
|
+
|
|
686
|
+
// On macOS/Linux, remove the Chrome profile SingletonLock that may linger
|
|
687
|
+
// after a force-kill, preventing the next Chrome instance from starting.
|
|
688
|
+
if (os !== "win32") {
|
|
689
|
+
const home = process.env.HOME;
|
|
690
|
+
if (home) {
|
|
691
|
+
const lockPaths =
|
|
692
|
+
os === "darwin"
|
|
693
|
+
? [
|
|
694
|
+
`${home}/Library/Application Support/Google/Chrome/SingletonLock`,
|
|
695
|
+
`${home}/Library/Application Support/Google/Chrome/SingletonSocket`,
|
|
696
|
+
`${home}/Library/Application Support/Google/Chrome/SingletonCookie`,
|
|
697
|
+
]
|
|
698
|
+
: [
|
|
699
|
+
`${home}/.config/google-chrome/SingletonLock`,
|
|
700
|
+
`${home}/.config/google-chrome/SingletonSocket`,
|
|
701
|
+
`${home}/.config/google-chrome/SingletonCookie`,
|
|
702
|
+
`${home}/.config/chromium/SingletonLock`,
|
|
703
|
+
`${home}/.config/chromium/SingletonSocket`,
|
|
704
|
+
`${home}/.config/chromium/SingletonCookie`,
|
|
705
|
+
];
|
|
706
|
+
for (const lockPath of lockPaths) {
|
|
707
|
+
try {
|
|
708
|
+
if (existsSync(lockPath)) {
|
|
709
|
+
unlinkSync(lockPath);
|
|
710
|
+
log.debug(`Removed stale lock: ${lockPath}`);
|
|
711
|
+
}
|
|
712
|
+
} catch {
|
|
713
|
+
/* best effort */
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
677
718
|
}
|
|
678
719
|
|
|
679
720
|
/**
|
|
@@ -681,35 +722,40 @@ async function killChromeGracefully(): Promise<void> {
|
|
|
681
722
|
* Returns the child process so callers can detect early failures.
|
|
682
723
|
*/
|
|
683
724
|
function spawnChrome(chromePath: string, port: number): ChildProcess {
|
|
684
|
-
const os = platform();
|
|
685
725
|
const cdpFlag = `--remote-debugging-port=${port}`;
|
|
686
726
|
|
|
687
|
-
|
|
727
|
+
// Always invoke the Chrome binary directly rather than `open -a`.
|
|
728
|
+
// On macOS, `open -a` silently ignores --args when Chrome is already
|
|
729
|
+
// running, which would cause CDP to never be enabled.
|
|
730
|
+
log.debug(`Spawning Chrome: ${chromePath} ${cdpFlag} --restore-last-session`);
|
|
731
|
+
const child = spawn(chromePath, [cdpFlag, "--restore-last-session"], {
|
|
732
|
+
detached: true,
|
|
733
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
734
|
+
});
|
|
688
735
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
? "Google Chrome Canary"
|
|
695
|
-
: "Google Chrome";
|
|
696
|
-
log.debug(`Spawning Chrome via: open -a "${appName}" --args ${cdpFlag} --restore-last-session`);
|
|
697
|
-
child = spawn("open", ["-a", appName, "--args", cdpFlag, "--restore-last-session"], {
|
|
698
|
-
detached: true,
|
|
699
|
-
stdio: "ignore",
|
|
700
|
-
});
|
|
701
|
-
} else {
|
|
702
|
-
log.debug(`Spawning Chrome via: ${chromePath} ${cdpFlag} --restore-last-session`);
|
|
703
|
-
child = spawn(chromePath, [cdpFlag, "--restore-last-session"], {
|
|
704
|
-
detached: true,
|
|
705
|
-
stdio: "ignore",
|
|
706
|
-
});
|
|
707
|
-
}
|
|
736
|
+
// Capture stderr for diagnostics — Chrome prints errors here
|
|
737
|
+
let stderr = "";
|
|
738
|
+
child.stderr?.on("data", (chunk: Buffer) => {
|
|
739
|
+
stderr += chunk.toString();
|
|
740
|
+
});
|
|
708
741
|
|
|
709
742
|
child.on("error", (err) => {
|
|
710
743
|
log.error(`Chrome spawn error: ${err.message}`);
|
|
711
744
|
});
|
|
712
745
|
|
|
746
|
+
child.on("exit", (code, signal) => {
|
|
747
|
+
if (code !== null && code !== 0) {
|
|
748
|
+
log.debug(`Chrome exited with code ${code}${signal ? ` (signal: ${signal})` : ""}`);
|
|
749
|
+
if (stderr) {
|
|
750
|
+
// Log first few lines of stderr for diagnostics
|
|
751
|
+
const lines = stderr.split("\n").filter(Boolean).slice(0, 5);
|
|
752
|
+
for (const line of lines) {
|
|
753
|
+
log.debug(` chrome stderr: ${line}`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
|
|
713
759
|
child.unref();
|
|
714
760
|
return child;
|
|
715
761
|
}
|
|
@@ -811,44 +857,77 @@ export async function ensureBrowserAvailable(port = 9222): Promise<AutoLaunchRes
|
|
|
811
857
|
if (running) {
|
|
812
858
|
log.debug("Killing Chrome gracefully for restart with CDP...");
|
|
813
859
|
await killChromeGracefully();
|
|
814
|
-
|
|
860
|
+
|
|
861
|
+
// Extra wait for profile lock release after kill
|
|
862
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
863
|
+
|
|
864
|
+
const child = spawnChrome(chromePath, port);
|
|
815
865
|
|
|
816
866
|
if (await waitForCDP(browser)) {
|
|
817
867
|
return { success: true, action: "restarted", chromePath };
|
|
818
868
|
}
|
|
819
869
|
|
|
870
|
+
// Check if Chrome is still alive before retrying
|
|
871
|
+
if (child.exitCode !== null) {
|
|
872
|
+
log.debug(
|
|
873
|
+
`Chrome process already exited (code ${child.exitCode}) — may have crashed or profile is locked`
|
|
874
|
+
);
|
|
875
|
+
return {
|
|
876
|
+
success: false,
|
|
877
|
+
action: "launch_failed",
|
|
878
|
+
chromePath,
|
|
879
|
+
detail: `Chrome exited immediately (code ${child.exitCode}). This often means the profile is locked by another Chrome instance. Try closing all Chrome windows first, then run assistme again.`,
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
|
|
820
883
|
// Retry once — Chrome can be slow to start (extensions, session restore)
|
|
821
884
|
log.debug("First CDP wait timed out after restart, retrying...");
|
|
822
885
|
if (await waitForCDP(browser, 15000)) {
|
|
823
886
|
return { success: true, action: "restarted", chromePath };
|
|
824
887
|
}
|
|
825
888
|
|
|
889
|
+
const stillRunning = isChromeRunning();
|
|
826
890
|
return {
|
|
827
891
|
success: false,
|
|
828
892
|
action: "launch_failed",
|
|
829
893
|
chromePath,
|
|
830
|
-
detail:
|
|
894
|
+
detail: stillRunning
|
|
895
|
+
? "Chrome is running but CDP port is not responding. Chrome may have started without the --remote-debugging-port flag. Try: 1) Quit Chrome completely, 2) Run assistme again."
|
|
896
|
+
: "Chrome was restarted but exited unexpectedly. Check if Chrome can start normally from the command line.",
|
|
831
897
|
};
|
|
832
898
|
}
|
|
833
899
|
|
|
834
900
|
// Case 4: Chrome not running → launch
|
|
835
|
-
spawnChrome(chromePath, port);
|
|
901
|
+
const child = spawnChrome(chromePath, port);
|
|
836
902
|
|
|
837
903
|
if (await waitForCDP(browser)) {
|
|
838
904
|
return { success: true, action: "launched", chromePath };
|
|
839
905
|
}
|
|
840
906
|
|
|
907
|
+
if (child.exitCode !== null) {
|
|
908
|
+
log.debug(`Chrome process already exited (code ${child.exitCode})`);
|
|
909
|
+
return {
|
|
910
|
+
success: false,
|
|
911
|
+
action: "launch_failed",
|
|
912
|
+
chromePath,
|
|
913
|
+
detail: `Chrome exited immediately (code ${child.exitCode}). Try launching Chrome manually to see any error dialogs.`,
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
|
|
841
917
|
// Retry once
|
|
842
918
|
log.debug("First CDP wait timed out after launch, retrying...");
|
|
843
919
|
if (await waitForCDP(browser, 15000)) {
|
|
844
920
|
return { success: true, action: "launched", chromePath };
|
|
845
921
|
}
|
|
846
922
|
|
|
923
|
+
const stillRunning = isChromeRunning();
|
|
847
924
|
return {
|
|
848
925
|
success: false,
|
|
849
926
|
action: "launch_failed",
|
|
850
927
|
chromePath,
|
|
851
|
-
detail:
|
|
928
|
+
detail: stillRunning
|
|
929
|
+
? "Chrome is running but CDP port is not responding. Try quitting Chrome completely and running assistme again."
|
|
930
|
+
: "Chrome exited unexpectedly after launch.",
|
|
852
931
|
};
|
|
853
932
|
}
|
|
854
933
|
|