bitfab-cli 0.2.97 → 0.2.99
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 +97 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9834,7 +9834,7 @@ async function createStudioSession({ serviceUrl, apiKey, sessionId, initialPath
|
|
|
9834
9834
|
import net2 from "net";
|
|
9835
9835
|
|
|
9836
9836
|
// ../bitfab-plugin-lib/dist/daemon/ensure.js
|
|
9837
|
-
import { fork } from "child_process";
|
|
9837
|
+
import { execFileSync as execFileSync4, fork } from "child_process";
|
|
9838
9838
|
import crypto5 from "crypto";
|
|
9839
9839
|
import fs9 from "fs";
|
|
9840
9840
|
import net from "net";
|
|
@@ -9921,6 +9921,21 @@ async function waitForSocket(socketPath, timeoutMs) {
|
|
|
9921
9921
|
}
|
|
9922
9922
|
throw new Error(`daemon did not become ready within ${timeoutMs}ms`);
|
|
9923
9923
|
}
|
|
9924
|
+
async function waitForLockHolderDaemon(socketPath, timeoutMs, localBuild = localBuildFingerprint()) {
|
|
9925
|
+
const deadline = Date.now() + timeoutMs;
|
|
9926
|
+
while (Date.now() < deadline) {
|
|
9927
|
+
const ping = await pingSocket(socketPath);
|
|
9928
|
+
if (ping.alive && (localBuild === "unknown" || !ping.build || ping.build === localBuild)) {
|
|
9929
|
+
return;
|
|
9930
|
+
}
|
|
9931
|
+
await new Promise((r) => setTimeout(r, ENSURE_POLL_INTERVAL_MS));
|
|
9932
|
+
}
|
|
9933
|
+
const finalPing = await pingSocket(socketPath);
|
|
9934
|
+
if (finalPing.alive) {
|
|
9935
|
+
return;
|
|
9936
|
+
}
|
|
9937
|
+
throw new Error(`daemon did not become ready within ${timeoutMs}ms`);
|
|
9938
|
+
}
|
|
9924
9939
|
function localBuildFingerprint() {
|
|
9925
9940
|
try {
|
|
9926
9941
|
const thisDir = path8.dirname(fileURLToPath2(import.meta.url));
|
|
@@ -9931,17 +9946,63 @@ function localBuildFingerprint() {
|
|
|
9931
9946
|
return "unknown";
|
|
9932
9947
|
}
|
|
9933
9948
|
}
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9949
|
+
function findDaemonPids(socketPath) {
|
|
9950
|
+
let out;
|
|
9951
|
+
try {
|
|
9952
|
+
out = execFileSync4("ps", ["-axww", "-o", "pid=,command="], {
|
|
9953
|
+
encoding: "utf-8"
|
|
9954
|
+
});
|
|
9955
|
+
} catch {
|
|
9956
|
+
return [];
|
|
9957
|
+
}
|
|
9958
|
+
const pids = [];
|
|
9959
|
+
for (const line of out.split("\n")) {
|
|
9960
|
+
const match = line.trim().match(/^(\d+)\s+(.*)$/);
|
|
9961
|
+
if (!match) {
|
|
9962
|
+
continue;
|
|
9963
|
+
}
|
|
9964
|
+
const pid = Number.parseInt(match[1], 10);
|
|
9965
|
+
const command = match[2];
|
|
9966
|
+
if (pid === process.pid || Number.isNaN(pid)) {
|
|
9967
|
+
continue;
|
|
9968
|
+
}
|
|
9969
|
+
if (command.includes("daemon/main.js") && commandTargetsSocket(command, socketPath)) {
|
|
9970
|
+
pids.push(pid);
|
|
9971
|
+
}
|
|
9972
|
+
}
|
|
9973
|
+
return pids;
|
|
9974
|
+
}
|
|
9975
|
+
function commandTargetsSocket(command, socketPath) {
|
|
9976
|
+
let idx = command.indexOf(socketPath);
|
|
9977
|
+
while (idx !== -1) {
|
|
9978
|
+
const after = command[idx + socketPath.length];
|
|
9979
|
+
if (after === void 0 || after === " ") {
|
|
9980
|
+
return true;
|
|
9981
|
+
}
|
|
9982
|
+
idx = command.indexOf(socketPath, idx + 1);
|
|
9983
|
+
}
|
|
9984
|
+
return false;
|
|
9985
|
+
}
|
|
9986
|
+
async function reapAllDaemons(socketPath, pidPath) {
|
|
9987
|
+
const pids = new Set(findDaemonPids(socketPath));
|
|
9988
|
+
const pidfilePid = readPid(pidPath);
|
|
9989
|
+
if (pidfilePid !== null) {
|
|
9990
|
+
pids.add(pidfilePid);
|
|
9991
|
+
}
|
|
9992
|
+
for (const pid of pids) {
|
|
9937
9993
|
try {
|
|
9938
9994
|
process.kill(pid, "SIGTERM");
|
|
9939
9995
|
} catch {
|
|
9940
9996
|
}
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9997
|
+
}
|
|
9998
|
+
const deadline = Date.now() + 5e3;
|
|
9999
|
+
while (Date.now() < deadline) {
|
|
10000
|
+
if (![...pids].some(processIsAlive)) {
|
|
10001
|
+
break;
|
|
9944
10002
|
}
|
|
10003
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
10004
|
+
}
|
|
10005
|
+
for (const pid of pids) {
|
|
9945
10006
|
if (processIsAlive(pid)) {
|
|
9946
10007
|
try {
|
|
9947
10008
|
process.kill(pid, "SIGKILL");
|
|
@@ -10015,18 +10076,17 @@ async function ensureDaemon(socketPath = SOCKET_PATH, pidPath = PID_FILE_PATH) {
|
|
|
10015
10076
|
const localBuild = localBuildFingerprint();
|
|
10016
10077
|
if (ping.build && ping.build !== localBuild && localBuild !== "unknown") {
|
|
10017
10078
|
console.error(`[daemon] build mismatch (running: ${ping.build}, local: ${localBuild}), restarting`);
|
|
10018
|
-
await killDaemon(pidPath, socketPath);
|
|
10019
10079
|
} else {
|
|
10020
10080
|
return;
|
|
10021
10081
|
}
|
|
10022
10082
|
}
|
|
10023
10083
|
}
|
|
10024
10084
|
if (!acquireLock(socketPath)) {
|
|
10025
|
-
await
|
|
10085
|
+
await waitForLockHolderDaemon(socketPath, ENSURE_TIMEOUT_MS);
|
|
10026
10086
|
return;
|
|
10027
10087
|
}
|
|
10028
10088
|
try {
|
|
10029
|
-
|
|
10089
|
+
await reapAllDaemons(socketPath, pidPath);
|
|
10030
10090
|
spawnDaemon(socketPath, pidPath);
|
|
10031
10091
|
await waitForSocket(socketPath, ENSURE_TIMEOUT_MS);
|
|
10032
10092
|
} finally {
|
|
@@ -10128,6 +10188,19 @@ var DaemonClient = class {
|
|
|
10128
10188
|
throw new Error(res.error);
|
|
10129
10189
|
}
|
|
10130
10190
|
}
|
|
10191
|
+
/**
|
|
10192
|
+
* Forget a session from the daemon's in-memory map (the recovery path after
|
|
10193
|
+
* a `not-responding` gate). Matched daemon-side on the studio sessionId, so a
|
|
10194
|
+
* session re-bound under the same key is never touched. Returns how many
|
|
10195
|
+
* entries were dropped (0 or 1).
|
|
10196
|
+
*/
|
|
10197
|
+
async clear(sessionId) {
|
|
10198
|
+
const res = await this.sendCommand({ cmd: "clear", sessionId });
|
|
10199
|
+
if (!res.ok) {
|
|
10200
|
+
throw new Error(res.error);
|
|
10201
|
+
}
|
|
10202
|
+
return res.cleared;
|
|
10203
|
+
}
|
|
10131
10204
|
async detach(key) {
|
|
10132
10205
|
const res = await this.sendCommand({ cmd: "detach", key });
|
|
10133
10206
|
if (!res.ok) {
|
|
@@ -10239,6 +10312,8 @@ var DirectChannel = class {
|
|
|
10239
10312
|
forceCloseWindow(sessionId) {
|
|
10240
10313
|
closeStudioWindowsBySession(sessionId);
|
|
10241
10314
|
}
|
|
10315
|
+
async clearSession(_sessionId) {
|
|
10316
|
+
}
|
|
10242
10317
|
subscribe(sessionId, onEvent, onError) {
|
|
10243
10318
|
const abortController = new AbortController();
|
|
10244
10319
|
const done = (async () => {
|
|
@@ -10330,6 +10405,10 @@ var DaemonChannel = class _DaemonChannel {
|
|
|
10330
10405
|
}
|
|
10331
10406
|
forceCloseWindow(_sessionId) {
|
|
10332
10407
|
}
|
|
10408
|
+
async clearSession(sessionId) {
|
|
10409
|
+
await this.client.clear(sessionId).catch(() => {
|
|
10410
|
+
});
|
|
10411
|
+
}
|
|
10333
10412
|
subscribe(_sessionId, onEvent, onError) {
|
|
10334
10413
|
const done = new Promise((resolve) => {
|
|
10335
10414
|
this.doneResolve = resolve;
|
|
@@ -10385,6 +10464,9 @@ function withDirectFallback(primary, apiKey, serviceUrl) {
|
|
|
10385
10464
|
forceCloseWindow(sessionId) {
|
|
10386
10465
|
active.forceCloseWindow(sessionId);
|
|
10387
10466
|
},
|
|
10467
|
+
async clearSession(sessionId) {
|
|
10468
|
+
await active.clearSession(sessionId);
|
|
10469
|
+
},
|
|
10388
10470
|
subscribe(sessionId, onEvent, onError) {
|
|
10389
10471
|
return active.subscribe(sessionId, onEvent, onError);
|
|
10390
10472
|
},
|
|
@@ -10453,13 +10535,13 @@ async function reportHandoff(apiKey, pluginVersion, platform2, body) {
|
|
|
10453
10535
|
import crypto7 from "crypto";
|
|
10454
10536
|
|
|
10455
10537
|
// ../bitfab-plugin-lib/dist/frontmostApp.js
|
|
10456
|
-
import { execFileSync as
|
|
10538
|
+
import { execFileSync as execFileSync5, spawn as spawn2 } from "child_process";
|
|
10457
10539
|
import os10 from "os";
|
|
10458
10540
|
function findAncestorApp() {
|
|
10459
10541
|
try {
|
|
10460
10542
|
let pid = process.ppid;
|
|
10461
10543
|
while (pid > 1) {
|
|
10462
|
-
const output =
|
|
10544
|
+
const output = execFileSync5("ps", ["-o", "ppid=,comm=", "-p", String(pid)], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
10463
10545
|
const match = output.match(/^\s*(\d+)\s+(.+)$/);
|
|
10464
10546
|
if (!match) {
|
|
10465
10547
|
break;
|
|
@@ -10518,19 +10600,19 @@ function getFrontmostApp() {
|
|
|
10518
10600
|
const platform2 = os10.platform();
|
|
10519
10601
|
try {
|
|
10520
10602
|
if (platform2 === "darwin") {
|
|
10521
|
-
return
|
|
10603
|
+
return execFileSync5("osascript", [
|
|
10522
10604
|
"-e",
|
|
10523
10605
|
'tell application "System Events" to get name of first process whose frontmost is true'
|
|
10524
10606
|
], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
10525
10607
|
}
|
|
10526
10608
|
if (platform2 === "linux") {
|
|
10527
|
-
return
|
|
10609
|
+
return execFileSync5("xdotool", ["getactivewindow"], {
|
|
10528
10610
|
stdio: "pipe",
|
|
10529
10611
|
encoding: "utf-8"
|
|
10530
10612
|
}).trim();
|
|
10531
10613
|
}
|
|
10532
10614
|
if (platform2 === "win32") {
|
|
10533
|
-
return
|
|
10615
|
+
return execFileSync5("powershell.exe", [
|
|
10534
10616
|
"-NoProfile",
|
|
10535
10617
|
"-Command",
|
|
10536
10618
|
`Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();' -Name WinFocus -Namespace Bitfab; [Bitfab.WinFocus]::GetForegroundWindow().ToInt64()`
|