bitfab-cli 0.2.87 → 0.2.89
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 +163 -82
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9398,77 +9398,8 @@ function updateActiveStudioSession(updates) {
|
|
|
9398
9398
|
return updated;
|
|
9399
9399
|
}
|
|
9400
9400
|
|
|
9401
|
-
// ../bitfab-plugin-lib/dist/parseArgs.js
|
|
9402
|
-
function formatPositionalLabel(spec) {
|
|
9403
|
-
const tag = spec.format && spec.format !== "string" ? `:${spec.format}` : "";
|
|
9404
|
-
if (spec.variadic) {
|
|
9405
|
-
return spec.required !== false ? `<${spec.name}${tag}> [<${spec.name}${tag}>...]` : `[<${spec.name}${tag}>...]`;
|
|
9406
|
-
}
|
|
9407
|
-
return spec.required !== false ? `<${spec.name}${tag}>` : `[${spec.name}${tag}]`;
|
|
9408
|
-
}
|
|
9409
|
-
function formatFlagLabel(spec) {
|
|
9410
|
-
if (spec.boolean) {
|
|
9411
|
-
return `[--${spec.name}]`;
|
|
9412
|
-
}
|
|
9413
|
-
const tag = spec.format && spec.format !== "string" ? `:${spec.format}` : "";
|
|
9414
|
-
const valueHint = spec.format === "number" ? " N" : ` <${spec.name}${tag}>`;
|
|
9415
|
-
const defaultHint = spec.default !== void 0 ? ` (default: ${spec.default})` : "";
|
|
9416
|
-
return `[--${spec.name}${valueHint}${defaultHint}]`;
|
|
9417
|
-
}
|
|
9418
|
-
function buildUsage(command, positional, flags) {
|
|
9419
|
-
const parts = [
|
|
9420
|
-
`Usage: ${command}`,
|
|
9421
|
-
...positional.map(formatPositionalLabel),
|
|
9422
|
-
...(flags ?? []).map(formatFlagLabel)
|
|
9423
|
-
];
|
|
9424
|
-
return parts.join(" ");
|
|
9425
|
-
}
|
|
9426
|
-
function buildHelp(command, positional, flags, description) {
|
|
9427
|
-
const lines = [buildUsage(command, positional, flags)];
|
|
9428
|
-
if (description) {
|
|
9429
|
-
lines.push("", description);
|
|
9430
|
-
}
|
|
9431
|
-
const describedArgs = positional.filter((s) => s.description);
|
|
9432
|
-
const flagSpecs = flags ?? [];
|
|
9433
|
-
const labelWidth = Math.max(0, ...describedArgs.map((s) => s.name.length), ...flagSpecs.map((s) => s.name.length + 2));
|
|
9434
|
-
if (describedArgs.length > 0) {
|
|
9435
|
-
lines.push("", "Arguments:");
|
|
9436
|
-
for (const spec of describedArgs) {
|
|
9437
|
-
lines.push(` ${spec.name.padEnd(labelWidth)} ${spec.description}`);
|
|
9438
|
-
}
|
|
9439
|
-
}
|
|
9440
|
-
if (flagSpecs.length > 0) {
|
|
9441
|
-
lines.push("", "Flags:");
|
|
9442
|
-
for (const spec of flagSpecs) {
|
|
9443
|
-
const detail = [
|
|
9444
|
-
spec.description,
|
|
9445
|
-
spec.default !== void 0 ? `(default: ${spec.default})` : void 0
|
|
9446
|
-
].filter(Boolean).join(" ");
|
|
9447
|
-
lines.push(` ${`--${spec.name}`.padEnd(labelWidth)} ${detail}`.trimEnd());
|
|
9448
|
-
}
|
|
9449
|
-
}
|
|
9450
|
-
return lines.join("\n");
|
|
9451
|
-
}
|
|
9452
|
-
function helpRequested(raw) {
|
|
9453
|
-
return raw.includes("-h") || raw.includes("--help");
|
|
9454
|
-
}
|
|
9455
|
-
function printHelpIfRequested(opts) {
|
|
9456
|
-
const argv = opts.argv ?? process.argv;
|
|
9457
|
-
if (!helpRequested(argv.slice(2))) {
|
|
9458
|
-
return;
|
|
9459
|
-
}
|
|
9460
|
-
console.log(buildHelp(extractCommandName(argv), opts.positional ?? [], opts.flags, opts.description));
|
|
9461
|
-
process.exit(0);
|
|
9462
|
-
}
|
|
9463
|
-
function extractCommandName(argv) {
|
|
9464
|
-
return argv[1]?.replace(/.*\//, "").replace(/\.[jt]s$/, "") ?? "command";
|
|
9465
|
-
}
|
|
9466
|
-
|
|
9467
|
-
// ../bitfab-plugin-lib/dist/studioChannel.js
|
|
9468
|
-
import crypto6 from "crypto";
|
|
9469
|
-
|
|
9470
9401
|
// ../bitfab-plugin-lib/dist/browser.js
|
|
9471
|
-
import { execSync, spawn } from "child_process";
|
|
9402
|
+
import { execFileSync as execFileSync3, execSync, spawn } from "child_process";
|
|
9472
9403
|
import fs8 from "fs";
|
|
9473
9404
|
import os8 from "os";
|
|
9474
9405
|
function getChromiumBrowsers() {
|
|
@@ -9715,6 +9646,47 @@ function shouldDisableChromelessWindows() {
|
|
|
9715
9646
|
var WINDOW_OPEN_RATE_WINDOW_MS = 3e4;
|
|
9716
9647
|
var WINDOW_OPEN_RATE_LIMIT = 3;
|
|
9717
9648
|
var recentOpens = [];
|
|
9649
|
+
function macAppNameFromBinaryPath(binaryPath) {
|
|
9650
|
+
const match = binaryPath.match(/\/([^/]+)\.app\//);
|
|
9651
|
+
return match ? match[1] : null;
|
|
9652
|
+
}
|
|
9653
|
+
function macChromiumAppNames() {
|
|
9654
|
+
return [
|
|
9655
|
+
...new Set(getChromiumBrowsers().flatMap((b) => b.binaryPaths.map(macAppNameFromBinaryPath)).filter((name) => name != null))
|
|
9656
|
+
];
|
|
9657
|
+
}
|
|
9658
|
+
function buildCloseStudioWindowsAppleScript(appName, sessionId) {
|
|
9659
|
+
return [
|
|
9660
|
+
`if application "${appName}" is running then`,
|
|
9661
|
+
` tell application "${appName}"`,
|
|
9662
|
+
` repeat with w in (every window)`,
|
|
9663
|
+
` try`,
|
|
9664
|
+
` repeat with t in (every tab of w)`,
|
|
9665
|
+
` if (URL of t) contains "${sessionId}" then`,
|
|
9666
|
+
` close w`,
|
|
9667
|
+
` exit repeat`,
|
|
9668
|
+
` end if`,
|
|
9669
|
+
` end repeat`,
|
|
9670
|
+
` end try`,
|
|
9671
|
+
` end repeat`,
|
|
9672
|
+
` end tell`,
|
|
9673
|
+
`end if`
|
|
9674
|
+
].join("\n");
|
|
9675
|
+
}
|
|
9676
|
+
function closeStudioWindowsBySession(sessionId) {
|
|
9677
|
+
if (os8.platform() !== "darwin" || !sessionId) {
|
|
9678
|
+
return;
|
|
9679
|
+
}
|
|
9680
|
+
if (/["\\]/.test(sessionId)) {
|
|
9681
|
+
return;
|
|
9682
|
+
}
|
|
9683
|
+
for (const appName of macChromiumAppNames()) {
|
|
9684
|
+
try {
|
|
9685
|
+
execFileSync3("osascript", ["-e", buildCloseStudioWindowsAppleScript(appName, sessionId)], { stdio: "ignore", timeout: 4e3 });
|
|
9686
|
+
} catch {
|
|
9687
|
+
}
|
|
9688
|
+
}
|
|
9689
|
+
}
|
|
9718
9690
|
function openChromelessWindow(url2) {
|
|
9719
9691
|
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
|
9720
9692
|
throw new Error("openChromelessWindow called in a test environment without being mocked");
|
|
@@ -9756,6 +9728,75 @@ function openChromelessWindow(url2) {
|
|
|
9756
9728
|
return null;
|
|
9757
9729
|
}
|
|
9758
9730
|
|
|
9731
|
+
// ../bitfab-plugin-lib/dist/parseArgs.js
|
|
9732
|
+
function formatPositionalLabel(spec) {
|
|
9733
|
+
const tag = spec.format && spec.format !== "string" ? `:${spec.format}` : "";
|
|
9734
|
+
if (spec.variadic) {
|
|
9735
|
+
return spec.required !== false ? `<${spec.name}${tag}> [<${spec.name}${tag}>...]` : `[<${spec.name}${tag}>...]`;
|
|
9736
|
+
}
|
|
9737
|
+
return spec.required !== false ? `<${spec.name}${tag}>` : `[${spec.name}${tag}]`;
|
|
9738
|
+
}
|
|
9739
|
+
function formatFlagLabel(spec) {
|
|
9740
|
+
if (spec.boolean) {
|
|
9741
|
+
return `[--${spec.name}]`;
|
|
9742
|
+
}
|
|
9743
|
+
const tag = spec.format && spec.format !== "string" ? `:${spec.format}` : "";
|
|
9744
|
+
const valueHint = spec.format === "number" ? " N" : ` <${spec.name}${tag}>`;
|
|
9745
|
+
const defaultHint = spec.default !== void 0 ? ` (default: ${spec.default})` : "";
|
|
9746
|
+
return `[--${spec.name}${valueHint}${defaultHint}]`;
|
|
9747
|
+
}
|
|
9748
|
+
function buildUsage(command, positional, flags) {
|
|
9749
|
+
const parts = [
|
|
9750
|
+
`Usage: ${command}`,
|
|
9751
|
+
...positional.map(formatPositionalLabel),
|
|
9752
|
+
...(flags ?? []).map(formatFlagLabel)
|
|
9753
|
+
];
|
|
9754
|
+
return parts.join(" ");
|
|
9755
|
+
}
|
|
9756
|
+
function buildHelp(command, positional, flags, description) {
|
|
9757
|
+
const lines = [buildUsage(command, positional, flags)];
|
|
9758
|
+
if (description) {
|
|
9759
|
+
lines.push("", description);
|
|
9760
|
+
}
|
|
9761
|
+
const describedArgs = positional.filter((s) => s.description);
|
|
9762
|
+
const flagSpecs = flags ?? [];
|
|
9763
|
+
const labelWidth = Math.max(0, ...describedArgs.map((s) => s.name.length), ...flagSpecs.map((s) => s.name.length + 2));
|
|
9764
|
+
if (describedArgs.length > 0) {
|
|
9765
|
+
lines.push("", "Arguments:");
|
|
9766
|
+
for (const spec of describedArgs) {
|
|
9767
|
+
lines.push(` ${spec.name.padEnd(labelWidth)} ${spec.description}`);
|
|
9768
|
+
}
|
|
9769
|
+
}
|
|
9770
|
+
if (flagSpecs.length > 0) {
|
|
9771
|
+
lines.push("", "Flags:");
|
|
9772
|
+
for (const spec of flagSpecs) {
|
|
9773
|
+
const detail = [
|
|
9774
|
+
spec.description,
|
|
9775
|
+
spec.default !== void 0 ? `(default: ${spec.default})` : void 0
|
|
9776
|
+
].filter(Boolean).join(" ");
|
|
9777
|
+
lines.push(` ${`--${spec.name}`.padEnd(labelWidth)} ${detail}`.trimEnd());
|
|
9778
|
+
}
|
|
9779
|
+
}
|
|
9780
|
+
return lines.join("\n");
|
|
9781
|
+
}
|
|
9782
|
+
function helpRequested(raw) {
|
|
9783
|
+
return raw.includes("-h") || raw.includes("--help");
|
|
9784
|
+
}
|
|
9785
|
+
function printHelpIfRequested(opts) {
|
|
9786
|
+
const argv = opts.argv ?? process.argv;
|
|
9787
|
+
if (!helpRequested(argv.slice(2))) {
|
|
9788
|
+
return;
|
|
9789
|
+
}
|
|
9790
|
+
console.log(buildHelp(extractCommandName(argv), opts.positional ?? [], opts.flags, opts.description));
|
|
9791
|
+
process.exit(0);
|
|
9792
|
+
}
|
|
9793
|
+
function extractCommandName(argv) {
|
|
9794
|
+
return argv[1]?.replace(/.*\//, "").replace(/\.[jt]s$/, "") ?? "command";
|
|
9795
|
+
}
|
|
9796
|
+
|
|
9797
|
+
// ../bitfab-plugin-lib/dist/studioChannel.js
|
|
9798
|
+
import crypto6 from "crypto";
|
|
9799
|
+
|
|
9759
9800
|
// ../bitfab-plugin-lib/dist/commands/createStudioSession.js
|
|
9760
9801
|
function ensureStudioPath(p5) {
|
|
9761
9802
|
if (!p5.startsWith("/studio")) {
|
|
@@ -9999,6 +10040,7 @@ var DaemonClient = class {
|
|
|
9999
10040
|
buffer = "";
|
|
10000
10041
|
responseQueue = [];
|
|
10001
10042
|
eventHandler = null;
|
|
10043
|
+
disconnectHandler = null;
|
|
10002
10044
|
socketPath;
|
|
10003
10045
|
constructor(socketPath) {
|
|
10004
10046
|
this.socketPath = socketPath ?? SOCKET_PATH;
|
|
@@ -10020,9 +10062,14 @@ var DaemonClient = class {
|
|
|
10020
10062
|
return;
|
|
10021
10063
|
}
|
|
10022
10064
|
this.socket = null;
|
|
10065
|
+
this.disconnectHandler?.(err);
|
|
10023
10066
|
});
|
|
10024
10067
|
socket.on("close", () => {
|
|
10068
|
+
const wasConnected = this.socket !== null;
|
|
10025
10069
|
this.socket = null;
|
|
10070
|
+
if (wasConnected) {
|
|
10071
|
+
this.disconnectHandler?.(new Error("daemon connection closed"));
|
|
10072
|
+
}
|
|
10026
10073
|
});
|
|
10027
10074
|
});
|
|
10028
10075
|
}
|
|
@@ -10103,8 +10150,13 @@ var DaemonClient = class {
|
|
|
10103
10150
|
onEvent(handler) {
|
|
10104
10151
|
this.eventHandler = handler;
|
|
10105
10152
|
}
|
|
10153
|
+
/** Fires once when the daemon connection drops unexpectedly (not on destroy). */
|
|
10154
|
+
onDisconnect(handler) {
|
|
10155
|
+
this.disconnectHandler = handler;
|
|
10156
|
+
}
|
|
10106
10157
|
destroy() {
|
|
10107
10158
|
this.eventHandler = null;
|
|
10159
|
+
this.disconnectHandler = null;
|
|
10108
10160
|
this.responseQueue = [];
|
|
10109
10161
|
if (this.socket) {
|
|
10110
10162
|
this.socket.destroy();
|
|
@@ -10113,6 +10165,23 @@ var DaemonClient = class {
|
|
|
10113
10165
|
}
|
|
10114
10166
|
};
|
|
10115
10167
|
|
|
10168
|
+
// ../bitfab-plugin-lib/dist/studioUrl.js
|
|
10169
|
+
var DEFAULT_STUDIO_PATH = "/studio";
|
|
10170
|
+
function resolveStudioInitialPath(input) {
|
|
10171
|
+
if (input && isValidStudioRoute(input)) {
|
|
10172
|
+
return input;
|
|
10173
|
+
}
|
|
10174
|
+
return DEFAULT_STUDIO_PATH;
|
|
10175
|
+
}
|
|
10176
|
+
function buildStudioSessionUrl(args) {
|
|
10177
|
+
const { serviceUrl, path: path18, sessionId } = args;
|
|
10178
|
+
if (path18.includes("session=")) {
|
|
10179
|
+
return `${serviceUrl}${path18}`;
|
|
10180
|
+
}
|
|
10181
|
+
const separator = path18.includes("?") ? "&" : "?";
|
|
10182
|
+
return `${serviceUrl}${path18}${separator}session=${encodeURIComponent(sessionId)}`;
|
|
10183
|
+
}
|
|
10184
|
+
|
|
10116
10185
|
// ../bitfab-plugin-lib/dist/studioChannel.js
|
|
10117
10186
|
var DirectChannel = class {
|
|
10118
10187
|
apiKey;
|
|
@@ -10127,11 +10196,12 @@ var DirectChannel = class {
|
|
|
10127
10196
|
async openOrNavigate(path18, opts) {
|
|
10128
10197
|
if (!this.apiKey) {
|
|
10129
10198
|
const sessionId2 = opts?.sessionId ?? crypto6.randomUUID();
|
|
10130
|
-
const initialPath = path18
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10199
|
+
const initialPath = resolveStudioInitialPath(path18);
|
|
10200
|
+
const url2 = buildStudioSessionUrl({
|
|
10201
|
+
serviceUrl: this.serviceUrl,
|
|
10202
|
+
path: initialPath,
|
|
10203
|
+
sessionId: sessionId2
|
|
10204
|
+
});
|
|
10135
10205
|
const windowPid = openChromelessWindow(url2);
|
|
10136
10206
|
writeActiveStudioSession({
|
|
10137
10207
|
sessionId: sessionId2,
|
|
@@ -10166,6 +10236,9 @@ var DirectChannel = class {
|
|
|
10166
10236
|
async close(sessionId, message) {
|
|
10167
10237
|
await closeStudio({ serviceUrl: this.serviceUrl, apiKey: this.apiKey, sessionId }, message);
|
|
10168
10238
|
}
|
|
10239
|
+
forceCloseWindow(sessionId) {
|
|
10240
|
+
closeStudioWindowsBySession(sessionId);
|
|
10241
|
+
}
|
|
10169
10242
|
subscribe(sessionId, onEvent, onError) {
|
|
10170
10243
|
const abortController = new AbortController();
|
|
10171
10244
|
const done = (async () => {
|
|
@@ -10255,18 +10328,23 @@ var DaemonChannel = class _DaemonChannel {
|
|
|
10255
10328
|
})
|
|
10256
10329
|
]);
|
|
10257
10330
|
}
|
|
10258
|
-
|
|
10331
|
+
forceCloseWindow(_sessionId) {
|
|
10332
|
+
}
|
|
10333
|
+
subscribe(_sessionId, onEvent, onError) {
|
|
10259
10334
|
const done = new Promise((resolve) => {
|
|
10260
10335
|
this.doneResolve = resolve;
|
|
10261
10336
|
});
|
|
10262
10337
|
this.client.onEvent((push) => {
|
|
10263
10338
|
const event = {
|
|
10264
|
-
id:
|
|
10339
|
+
id: push.id,
|
|
10265
10340
|
type: push.event,
|
|
10266
10341
|
data: push.data
|
|
10267
10342
|
};
|
|
10268
10343
|
onEvent(event);
|
|
10269
10344
|
});
|
|
10345
|
+
this.client.onDisconnect((err) => {
|
|
10346
|
+
onError(err);
|
|
10347
|
+
});
|
|
10270
10348
|
return {
|
|
10271
10349
|
abort: () => this.destroy(),
|
|
10272
10350
|
done
|
|
@@ -10304,6 +10382,9 @@ function withDirectFallback(primary, apiKey, serviceUrl) {
|
|
|
10304
10382
|
async close(sessionId, message) {
|
|
10305
10383
|
await active.close(sessionId, message);
|
|
10306
10384
|
},
|
|
10385
|
+
forceCloseWindow(sessionId) {
|
|
10386
|
+
active.forceCloseWindow(sessionId);
|
|
10387
|
+
},
|
|
10307
10388
|
subscribe(sessionId, onEvent, onError) {
|
|
10308
10389
|
return active.subscribe(sessionId, onEvent, onError);
|
|
10309
10390
|
},
|
|
@@ -10372,13 +10453,13 @@ async function reportHandoff(apiKey, pluginVersion, platform2, body) {
|
|
|
10372
10453
|
import crypto7 from "crypto";
|
|
10373
10454
|
|
|
10374
10455
|
// ../bitfab-plugin-lib/dist/frontmostApp.js
|
|
10375
|
-
import { execFileSync as
|
|
10456
|
+
import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
|
|
10376
10457
|
import os10 from "os";
|
|
10377
10458
|
function findAncestorApp() {
|
|
10378
10459
|
try {
|
|
10379
10460
|
let pid = process.ppid;
|
|
10380
10461
|
while (pid > 1) {
|
|
10381
|
-
const output =
|
|
10462
|
+
const output = execFileSync4("ps", ["-o", "ppid=,comm=", "-p", String(pid)], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
10382
10463
|
const match = output.match(/^\s*(\d+)\s+(.+)$/);
|
|
10383
10464
|
if (!match) {
|
|
10384
10465
|
break;
|
|
@@ -10437,19 +10518,19 @@ function getFrontmostApp() {
|
|
|
10437
10518
|
const platform2 = os10.platform();
|
|
10438
10519
|
try {
|
|
10439
10520
|
if (platform2 === "darwin") {
|
|
10440
|
-
return
|
|
10521
|
+
return execFileSync4("osascript", [
|
|
10441
10522
|
"-e",
|
|
10442
10523
|
'tell application "System Events" to get name of first process whose frontmost is true'
|
|
10443
10524
|
], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
10444
10525
|
}
|
|
10445
10526
|
if (platform2 === "linux") {
|
|
10446
|
-
return
|
|
10527
|
+
return execFileSync4("xdotool", ["getactivewindow"], {
|
|
10447
10528
|
stdio: "pipe",
|
|
10448
10529
|
encoding: "utf-8"
|
|
10449
10530
|
}).trim();
|
|
10450
10531
|
}
|
|
10451
10532
|
if (platform2 === "win32") {
|
|
10452
|
-
return
|
|
10533
|
+
return execFileSync4("powershell.exe", [
|
|
10453
10534
|
"-NoProfile",
|
|
10454
10535
|
"-Command",
|
|
10455
10536
|
`Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();' -Name WinFocus -Namespace Bitfab; [Bitfab.WinFocus]::GetForegroundWindow().ToInt64()`
|