adhdev 0.1.6 → 0.1.8
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 +364 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -162,18 +162,18 @@ function checkPathExists(paths) {
|
|
|
162
162
|
return null;
|
|
163
163
|
}
|
|
164
164
|
async function detectIDEs() {
|
|
165
|
-
const
|
|
165
|
+
const os2 = (0, import_os.platform)();
|
|
166
166
|
const results = [];
|
|
167
167
|
for (const def of IDE_DEFINITIONS) {
|
|
168
168
|
const cliPath = findCliCommand(def.cli);
|
|
169
|
-
const appPath = checkPathExists(def.paths[
|
|
169
|
+
const appPath = checkPathExists(def.paths[os2] || []);
|
|
170
170
|
const installed = !!(cliPath || appPath);
|
|
171
171
|
let resolvedCli = cliPath;
|
|
172
|
-
if (!resolvedCli && appPath &&
|
|
172
|
+
if (!resolvedCli && appPath && os2 === "darwin") {
|
|
173
173
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
174
174
|
if ((0, import_fs.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
175
175
|
}
|
|
176
|
-
if (!resolvedCli && appPath &&
|
|
176
|
+
if (!resolvedCli && appPath && os2 === "win32") {
|
|
177
177
|
const { dirname } = await import("path");
|
|
178
178
|
const appDir = dirname(appPath);
|
|
179
179
|
const candidates = [
|
|
@@ -772,15 +772,15 @@ async function loginFlow() {
|
|
|
772
772
|
async function injectTokenToIDE(ide, connectionToken) {
|
|
773
773
|
if (!ide.cliCommand) return;
|
|
774
774
|
try {
|
|
775
|
-
const
|
|
775
|
+
const os2 = await import("os");
|
|
776
776
|
const fs = await import("fs");
|
|
777
777
|
const path = await import("path");
|
|
778
|
-
const
|
|
779
|
-
const home =
|
|
778
|
+
const platform3 = os2.platform();
|
|
779
|
+
const home = os2.homedir();
|
|
780
780
|
const getSettingsPath = (appName2) => {
|
|
781
|
-
if (
|
|
781
|
+
if (platform3 === "darwin") {
|
|
782
782
|
return path.join(home, "Library", "Application Support", appName2, "User", "settings.json");
|
|
783
|
-
} else if (
|
|
783
|
+
} else if (platform3 === "win32") {
|
|
784
784
|
return path.join(process.env.APPDATA || path.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
|
|
785
785
|
} else {
|
|
786
786
|
return path.join(home, ".config", appName2, "User", "settings.json");
|
|
@@ -853,12 +853,366 @@ async function addExtensionsFlow() {
|
|
|
853
853
|
console.log(import_chalk.default.green("\n\u2713 Extensions added!"));
|
|
854
854
|
}
|
|
855
855
|
|
|
856
|
+
// src/launch.ts
|
|
857
|
+
var import_child_process3 = require("child_process");
|
|
858
|
+
var net = __toESM(require("net"));
|
|
859
|
+
var os = __toESM(require("os"));
|
|
860
|
+
var CDP_PORTS = {
|
|
861
|
+
cursor: [9333, 9334],
|
|
862
|
+
antigravity: [9335, 9336],
|
|
863
|
+
vscode: [9229, 9230],
|
|
864
|
+
windsurf: [9337, 9338],
|
|
865
|
+
"vscode-insiders": [9231, 9232],
|
|
866
|
+
vscodium: [9233, 9234]
|
|
867
|
+
};
|
|
868
|
+
var MAC_APP_IDENTIFIERS = {
|
|
869
|
+
cursor: "Cursor",
|
|
870
|
+
antigravity: "Antigravity",
|
|
871
|
+
vscode: "Visual Studio Code",
|
|
872
|
+
windsurf: "Windsurf",
|
|
873
|
+
"vscode-insiders": "Visual Studio Code - Insiders",
|
|
874
|
+
vscodium: "VSCodium"
|
|
875
|
+
};
|
|
876
|
+
var WIN_PROCESS_NAMES = {
|
|
877
|
+
cursor: "Cursor.exe",
|
|
878
|
+
antigravity: "Antigravity.exe",
|
|
879
|
+
vscode: "Code.exe",
|
|
880
|
+
windsurf: "Windsurf.exe",
|
|
881
|
+
"vscode-insiders": "Code - Insiders.exe",
|
|
882
|
+
vscodium: "VSCodium.exe"
|
|
883
|
+
};
|
|
884
|
+
async function findFreePort(ports) {
|
|
885
|
+
for (const port2 of ports) {
|
|
886
|
+
const free = await checkPortFree(port2);
|
|
887
|
+
if (free) return port2;
|
|
888
|
+
}
|
|
889
|
+
let port = ports[1] + 1;
|
|
890
|
+
while (port < ports[1] + 10) {
|
|
891
|
+
if (await checkPortFree(port)) return port;
|
|
892
|
+
port++;
|
|
893
|
+
}
|
|
894
|
+
throw new Error("No free port found");
|
|
895
|
+
}
|
|
896
|
+
function checkPortFree(port) {
|
|
897
|
+
return new Promise((resolve) => {
|
|
898
|
+
const server = net.createServer();
|
|
899
|
+
server.unref();
|
|
900
|
+
server.on("error", () => resolve(false));
|
|
901
|
+
server.listen(port, "127.0.0.1", () => {
|
|
902
|
+
server.close(() => resolve(true));
|
|
903
|
+
});
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
async function isCdpActive(port) {
|
|
907
|
+
return new Promise((resolve) => {
|
|
908
|
+
const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
909
|
+
timeout: 2e3
|
|
910
|
+
}, (res) => {
|
|
911
|
+
let data = "";
|
|
912
|
+
res.on("data", (c) => data += c);
|
|
913
|
+
res.on("end", () => {
|
|
914
|
+
try {
|
|
915
|
+
const info = JSON.parse(data);
|
|
916
|
+
resolve(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
917
|
+
} catch {
|
|
918
|
+
resolve(false);
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
});
|
|
922
|
+
req.on("error", () => resolve(false));
|
|
923
|
+
req.on("timeout", () => {
|
|
924
|
+
req.destroy();
|
|
925
|
+
resolve(false);
|
|
926
|
+
});
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
async function killIdeProcess(ideId) {
|
|
930
|
+
const platform3 = os.platform();
|
|
931
|
+
const appName = MAC_APP_IDENTIFIERS[ideId];
|
|
932
|
+
const winProcess = WIN_PROCESS_NAMES[ideId];
|
|
933
|
+
try {
|
|
934
|
+
if (platform3 === "darwin" && appName) {
|
|
935
|
+
try {
|
|
936
|
+
(0, import_child_process3.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
|
|
937
|
+
timeout: 5e3
|
|
938
|
+
});
|
|
939
|
+
} catch {
|
|
940
|
+
try {
|
|
941
|
+
(0, import_child_process3.execSync)(`pkill -f "${appName}" 2>/dev/null`);
|
|
942
|
+
} catch {
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
} else if (platform3 === "win32" && winProcess) {
|
|
946
|
+
try {
|
|
947
|
+
(0, import_child_process3.execSync)(`taskkill /IM "${winProcess}" /F 2>nul`, { timeout: 5e3 });
|
|
948
|
+
} catch {
|
|
949
|
+
}
|
|
950
|
+
} else {
|
|
951
|
+
try {
|
|
952
|
+
(0, import_child_process3.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
|
|
953
|
+
} catch {
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
for (let i = 0; i < 30; i++) {
|
|
957
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
958
|
+
if (!isIdeRunning(ideId)) return true;
|
|
959
|
+
}
|
|
960
|
+
if (platform3 === "darwin" && appName) {
|
|
961
|
+
try {
|
|
962
|
+
(0, import_child_process3.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
|
|
963
|
+
} catch {
|
|
964
|
+
}
|
|
965
|
+
} else if (platform3 === "win32" && winProcess) {
|
|
966
|
+
try {
|
|
967
|
+
(0, import_child_process3.execSync)(`taskkill /IM "${winProcess}" /F 2>nul`);
|
|
968
|
+
} catch {
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
972
|
+
return !isIdeRunning(ideId);
|
|
973
|
+
} catch {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
function isIdeRunning(ideId) {
|
|
978
|
+
const platform3 = os.platform();
|
|
979
|
+
try {
|
|
980
|
+
if (platform3 === "darwin") {
|
|
981
|
+
const appName = MAC_APP_IDENTIFIERS[ideId];
|
|
982
|
+
if (!appName) return false;
|
|
983
|
+
const result = (0, import_child_process3.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
|
|
984
|
+
return result.trim().length > 0;
|
|
985
|
+
} else if (platform3 === "win32") {
|
|
986
|
+
const winProc = WIN_PROCESS_NAMES[ideId];
|
|
987
|
+
if (!winProc) return false;
|
|
988
|
+
const result = (0, import_child_process3.execSync)(`tasklist /FI "IMAGENAME eq ${winProc}" /NH 2>nul`, { encoding: "utf-8" });
|
|
989
|
+
return result.includes(winProc);
|
|
990
|
+
} else {
|
|
991
|
+
const result = (0, import_child_process3.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
|
|
992
|
+
return result.trim().length > 0;
|
|
993
|
+
}
|
|
994
|
+
} catch {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
function detectCurrentWorkspace(ideId) {
|
|
999
|
+
const platform3 = os.platform();
|
|
1000
|
+
if (platform3 !== "darwin") return void 0;
|
|
1001
|
+
try {
|
|
1002
|
+
const appName = MAC_APP_IDENTIFIERS[ideId];
|
|
1003
|
+
if (!appName) return void 0;
|
|
1004
|
+
const result = (0, import_child_process3.execSync)(
|
|
1005
|
+
`lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
|
|
1006
|
+
{ encoding: "utf-8", timeout: 3e3 }
|
|
1007
|
+
);
|
|
1008
|
+
const dir = result.trim();
|
|
1009
|
+
if (dir && dir !== "/") return dir;
|
|
1010
|
+
} catch {
|
|
1011
|
+
}
|
|
1012
|
+
return void 0;
|
|
1013
|
+
}
|
|
1014
|
+
async function launchWithCdp(options = {}) {
|
|
1015
|
+
const platform3 = os.platform();
|
|
1016
|
+
let targetIde;
|
|
1017
|
+
const ides = await detectIDEs();
|
|
1018
|
+
if (options.ideId) {
|
|
1019
|
+
targetIde = ides.find((i) => i.id === options.ideId && i.installed);
|
|
1020
|
+
if (!targetIde) {
|
|
1021
|
+
return {
|
|
1022
|
+
success: false,
|
|
1023
|
+
ideId: options.ideId,
|
|
1024
|
+
ideName: options.ideId,
|
|
1025
|
+
port: 0,
|
|
1026
|
+
action: "failed",
|
|
1027
|
+
message: "",
|
|
1028
|
+
error: `IDE '${options.ideId}' not found or not installed`
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
} else {
|
|
1032
|
+
const config = loadConfig();
|
|
1033
|
+
if (config.selectedIde) {
|
|
1034
|
+
targetIde = ides.find((i) => i.id === config.selectedIde && i.installed);
|
|
1035
|
+
}
|
|
1036
|
+
if (!targetIde) {
|
|
1037
|
+
targetIde = ides.find((i) => i.installed);
|
|
1038
|
+
}
|
|
1039
|
+
if (!targetIde) {
|
|
1040
|
+
return {
|
|
1041
|
+
success: false,
|
|
1042
|
+
ideId: "unknown",
|
|
1043
|
+
ideName: "Unknown",
|
|
1044
|
+
port: 0,
|
|
1045
|
+
action: "failed",
|
|
1046
|
+
message: "",
|
|
1047
|
+
error: "No IDE found. Install VS Code, Cursor, or Antigravity first."
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const portPair = CDP_PORTS[targetIde.id] || [9333, 9334];
|
|
1052
|
+
for (const port2 of portPair) {
|
|
1053
|
+
if (await isCdpActive(port2)) {
|
|
1054
|
+
return {
|
|
1055
|
+
success: true,
|
|
1056
|
+
ideId: targetIde.id,
|
|
1057
|
+
ideName: targetIde.displayName,
|
|
1058
|
+
port: port2,
|
|
1059
|
+
action: "reused",
|
|
1060
|
+
message: `CDP already active on port ${port2}`
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
const alreadyRunning = isIdeRunning(targetIde.id);
|
|
1065
|
+
const workspace = options.workspace || (alreadyRunning ? detectCurrentWorkspace(targetIde.id) : void 0);
|
|
1066
|
+
if (alreadyRunning) {
|
|
1067
|
+
const killed = await killIdeProcess(targetIde.id);
|
|
1068
|
+
if (!killed) {
|
|
1069
|
+
return {
|
|
1070
|
+
success: false,
|
|
1071
|
+
ideId: targetIde.id,
|
|
1072
|
+
ideName: targetIde.displayName,
|
|
1073
|
+
port: 0,
|
|
1074
|
+
action: "failed",
|
|
1075
|
+
message: "",
|
|
1076
|
+
error: `Could not stop ${targetIde.displayName}. Close it manually and try again.`
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
1080
|
+
}
|
|
1081
|
+
const port = await findFreePort(portPair);
|
|
1082
|
+
try {
|
|
1083
|
+
if (platform3 === "darwin") {
|
|
1084
|
+
await launchMacOS(targetIde, port, workspace, options.newWindow);
|
|
1085
|
+
} else if (platform3 === "win32") {
|
|
1086
|
+
await launchWindows(targetIde, port, workspace, options.newWindow);
|
|
1087
|
+
} else {
|
|
1088
|
+
await launchLinux(targetIde, port, workspace, options.newWindow);
|
|
1089
|
+
}
|
|
1090
|
+
let cdpReady = false;
|
|
1091
|
+
for (let i = 0; i < 30; i++) {
|
|
1092
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
1093
|
+
if (await isCdpActive(port)) {
|
|
1094
|
+
cdpReady = true;
|
|
1095
|
+
break;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
return {
|
|
1099
|
+
success: true,
|
|
1100
|
+
ideId: targetIde.id,
|
|
1101
|
+
ideName: targetIde.displayName,
|
|
1102
|
+
port,
|
|
1103
|
+
action: alreadyRunning ? "restarted" : "started",
|
|
1104
|
+
message: cdpReady ? `${targetIde.displayName} launched with CDP on port ${port}` : `${targetIde.displayName} launched (CDP may take a moment to initialize)`
|
|
1105
|
+
};
|
|
1106
|
+
} catch (e) {
|
|
1107
|
+
return {
|
|
1108
|
+
success: false,
|
|
1109
|
+
ideId: targetIde.id,
|
|
1110
|
+
ideName: targetIde.displayName,
|
|
1111
|
+
port,
|
|
1112
|
+
action: "failed",
|
|
1113
|
+
message: "",
|
|
1114
|
+
error: e?.message || String(e)
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
async function launchMacOS(ide, port, workspace, newWindow) {
|
|
1119
|
+
const appName = MAC_APP_IDENTIFIERS[ide.id];
|
|
1120
|
+
const args = ["--remote-debugging-port=" + port];
|
|
1121
|
+
if (newWindow) args.push("--new-window");
|
|
1122
|
+
if (workspace) args.push(workspace);
|
|
1123
|
+
if (appName) {
|
|
1124
|
+
const openArgs = ["-a", appName, "--args", ...args];
|
|
1125
|
+
(0, import_child_process3.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
|
|
1126
|
+
} else if (ide.cliCommand) {
|
|
1127
|
+
(0, import_child_process3.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
|
|
1128
|
+
} else {
|
|
1129
|
+
throw new Error(`No app identifier or CLI for ${ide.displayName}`);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
async function launchWindows(ide, port, workspace, newWindow) {
|
|
1133
|
+
const cli = ide.cliCommand;
|
|
1134
|
+
if (!cli) {
|
|
1135
|
+
throw new Error(`No CLI command for ${ide.displayName}. Please add it to PATH.`);
|
|
1136
|
+
}
|
|
1137
|
+
const args = ["--remote-debugging-port=" + port];
|
|
1138
|
+
if (newWindow) args.push("--new-window");
|
|
1139
|
+
if (workspace) args.push(workspace);
|
|
1140
|
+
(0, import_child_process3.spawn)(cli, args, {
|
|
1141
|
+
detached: true,
|
|
1142
|
+
stdio: "ignore",
|
|
1143
|
+
shell: true
|
|
1144
|
+
}).unref();
|
|
1145
|
+
}
|
|
1146
|
+
async function launchLinux(ide, port, workspace, newWindow) {
|
|
1147
|
+
const cli = ide.cliCommand;
|
|
1148
|
+
if (!cli) {
|
|
1149
|
+
throw new Error(`No CLI command for ${ide.displayName}. Make sure it's in PATH.`);
|
|
1150
|
+
}
|
|
1151
|
+
const args = ["--remote-debugging-port=" + port];
|
|
1152
|
+
if (newWindow) args.push("--new-window");
|
|
1153
|
+
if (workspace) args.push(workspace);
|
|
1154
|
+
(0, import_child_process3.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
|
|
1155
|
+
}
|
|
1156
|
+
|
|
856
1157
|
// src/index.ts
|
|
857
1158
|
var program = new import_commander.Command();
|
|
858
|
-
program.name("adhdev").description("\u{1F309} ADHDev \u2014 Agent Dashboard Hub for your IDE").version("0.1.
|
|
1159
|
+
program.name("adhdev").description("\u{1F309} ADHDev \u2014 Agent Dashboard Hub for your IDE").version("0.1.6");
|
|
859
1160
|
program.command("setup", { isDefault: true }).description("Run the interactive setup wizard").option("-f, --force", "Force re-run setup even if already configured").action(async (options) => {
|
|
860
1161
|
await runWizard({ force: options.force });
|
|
861
1162
|
});
|
|
1163
|
+
program.command("launch [ide]").description("Launch or relaunch IDE with CDP debugging port (kills existing process first)").option("-w, --workspace <path>", "Workspace/folder to open").option("-n, --new-window", "Open in a new window").action(async (ideArg, options) => {
|
|
1164
|
+
const ora2 = await import("ora");
|
|
1165
|
+
const spinner = ora2.default("Detecting IDE...").start();
|
|
1166
|
+
try {
|
|
1167
|
+
const result = await launchWithCdp({
|
|
1168
|
+
ideId: ideArg,
|
|
1169
|
+
workspace: options.workspace,
|
|
1170
|
+
newWindow: options.newWindow
|
|
1171
|
+
});
|
|
1172
|
+
spinner.stop();
|
|
1173
|
+
if (!result.success) {
|
|
1174
|
+
console.log(import_chalk2.default.red(`
|
|
1175
|
+
\u2717 ${result.error}
|
|
1176
|
+
`));
|
|
1177
|
+
console.log(import_chalk2.default.gray(" Available IDEs:"));
|
|
1178
|
+
const ides = await detectIDEs();
|
|
1179
|
+
ides.forEach((ide) => {
|
|
1180
|
+
if (ide.installed) {
|
|
1181
|
+
console.log(` ${import_chalk2.default.green("\u2713")} ${ide.icon} ${import_chalk2.default.bold(ide.id)} \u2014 ${ide.displayName}`);
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
console.log(import_chalk2.default.gray(`
|
|
1185
|
+
Usage: adhdev launch <ide-id>
|
|
1186
|
+
`));
|
|
1187
|
+
process.exit(1);
|
|
1188
|
+
}
|
|
1189
|
+
console.log();
|
|
1190
|
+
console.log(import_chalk2.default.bold(" \u{1F680} IDE Launched with CDP\n"));
|
|
1191
|
+
console.log(` ${import_chalk2.default.bold("IDE:")} ${result.ideName}`);
|
|
1192
|
+
console.log(` ${import_chalk2.default.bold("CDP:")} ${import_chalk2.default.cyan(`ws://127.0.0.1:${result.port}`)}`);
|
|
1193
|
+
switch (result.action) {
|
|
1194
|
+
case "reused":
|
|
1195
|
+
console.log(` ${import_chalk2.default.bold("Action:")} ${import_chalk2.default.yellow("CDP already active \u2014 reusing existing session")}`);
|
|
1196
|
+
break;
|
|
1197
|
+
case "restarted":
|
|
1198
|
+
console.log(` ${import_chalk2.default.bold("Action:")} ${import_chalk2.default.green("\u2713 Killed existing process \u2192 Restarted with CDP")}`);
|
|
1199
|
+
break;
|
|
1200
|
+
case "started":
|
|
1201
|
+
console.log(` ${import_chalk2.default.bold("Action:")} ${import_chalk2.default.green("\u2713 Started fresh with CDP")}`);
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1204
|
+
console.log();
|
|
1205
|
+
console.log(import_chalk2.default.gray(" Bridge extension will auto-connect to CDP."));
|
|
1206
|
+
console.log(import_chalk2.default.gray(` Test: curl http://127.0.0.1:${result.port}/json/version
|
|
1207
|
+
`));
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
spinner.stop();
|
|
1210
|
+
console.log(import_chalk2.default.red(`
|
|
1211
|
+
\u2717 Launch failed: ${e?.message || e}
|
|
1212
|
+
`));
|
|
1213
|
+
process.exit(1);
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
862
1216
|
program.command("status").description("Show current ADHDev setup status").action(() => {
|
|
863
1217
|
const config = loadConfig();
|
|
864
1218
|
console.log(import_chalk2.default.bold("\n\u{1F309} ADHDev Status\n"));
|