bitfab-cli 0.2.4 → 0.2.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 +430 -779
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3482,7 +3482,7 @@ var require_schemes = __commonJS({
|
|
|
3482
3482
|
urnComponent.nss = (uuidComponent.uuid || "").toLowerCase();
|
|
3483
3483
|
return urnComponent;
|
|
3484
3484
|
}
|
|
3485
|
-
var
|
|
3485
|
+
var http = (
|
|
3486
3486
|
/** @type {SchemeHandler} */
|
|
3487
3487
|
{
|
|
3488
3488
|
scheme: "http",
|
|
@@ -3495,7 +3495,7 @@ var require_schemes = __commonJS({
|
|
|
3495
3495
|
/** @type {SchemeHandler} */
|
|
3496
3496
|
{
|
|
3497
3497
|
scheme: "https",
|
|
3498
|
-
domainHost:
|
|
3498
|
+
domainHost: http.domainHost,
|
|
3499
3499
|
parse: httpParse,
|
|
3500
3500
|
serialize: httpSerialize
|
|
3501
3501
|
}
|
|
@@ -3539,7 +3539,7 @@ var require_schemes = __commonJS({
|
|
|
3539
3539
|
var SCHEMES = (
|
|
3540
3540
|
/** @type {Record<SchemeName, SchemeHandler>} */
|
|
3541
3541
|
{
|
|
3542
|
-
http
|
|
3542
|
+
http,
|
|
3543
3543
|
https,
|
|
3544
3544
|
ws,
|
|
3545
3545
|
wss,
|
|
@@ -6805,15 +6805,215 @@ import { cancel as cancel2 } from "@clack/prompts";
|
|
|
6805
6805
|
import { execSync as execSync3 } from "child_process";
|
|
6806
6806
|
import * as p4 from "@clack/prompts";
|
|
6807
6807
|
|
|
6808
|
-
// ../bitfab-plugin-lib/dist/
|
|
6809
|
-
import
|
|
6808
|
+
// ../bitfab-plugin-lib/dist/buildInfo.js
|
|
6809
|
+
import crypto from "crypto";
|
|
6810
|
+
import fs from "fs";
|
|
6811
|
+
import os from "os";
|
|
6812
|
+
import path from "path";
|
|
6813
|
+
import { fileURLToPath } from "url";
|
|
6814
|
+
|
|
6815
|
+
// ../bitfab-plugin-lib/dist/chatSessions/index.js
|
|
6816
|
+
import { execFileSync } from "child_process";
|
|
6817
|
+
import fs5 from "fs";
|
|
6818
|
+
import os4 from "os";
|
|
6819
|
+
import path4 from "path";
|
|
6820
|
+
|
|
6821
|
+
// ../bitfab-plugin-lib/dist/skills.js
|
|
6822
|
+
var BITFAB_SKILLS = ["setup", "assistant", "update"];
|
|
6823
|
+
|
|
6824
|
+
// ../bitfab-plugin-lib/dist/hooks/skillDetection.js
|
|
6825
|
+
var SKILL_PATTERN = new RegExp(`^\\s*\\/bitfab[:-](?<skill>${BITFAB_SKILLS.join("|")})(?=\\s|$)`, "i");
|
|
6826
|
+
|
|
6827
|
+
// ../bitfab-plugin-lib/dist/chatSessions/arming.js
|
|
6828
|
+
import fs2 from "fs";
|
|
6829
|
+
import os2 from "os";
|
|
6830
|
+
import path2 from "path";
|
|
6831
|
+
|
|
6832
|
+
// ../bitfab-plugin-lib/dist/config.js
|
|
6833
|
+
import crypto2 from "crypto";
|
|
6834
|
+
import fs3 from "fs";
|
|
6835
|
+
import os3 from "os";
|
|
6836
|
+
import path3 from "path";
|
|
6837
|
+
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
6838
|
+
var GLOBAL_CONFIG_DIR = path3.join(os3.homedir(), ".config", "bitfab");
|
|
6839
|
+
var GLOBAL_CONFIG_FILE = path3.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
6840
|
+
var GLOBAL_CREDENTIALS_FILE = path3.join(GLOBAL_CONFIG_DIR, "credentials.json");
|
|
6841
|
+
var PROJECT_CONFIG_RELATIVE = path3.join(".bitfab", "config.local.json");
|
|
6842
|
+
function readJsonFile(filePath) {
|
|
6843
|
+
try {
|
|
6844
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
6845
|
+
return JSON.parse(content);
|
|
6846
|
+
} catch {
|
|
6847
|
+
return null;
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
function findProjectConfigPath(startDir = process.cwd()) {
|
|
6851
|
+
let dir = startDir;
|
|
6852
|
+
while (true) {
|
|
6853
|
+
const candidate = path3.join(dir, PROJECT_CONFIG_RELATIVE);
|
|
6854
|
+
if (fs3.existsSync(candidate)) {
|
|
6855
|
+
return candidate;
|
|
6856
|
+
}
|
|
6857
|
+
const parent = path3.dirname(dir);
|
|
6858
|
+
if (parent === dir) {
|
|
6859
|
+
return null;
|
|
6860
|
+
}
|
|
6861
|
+
dir = parent;
|
|
6862
|
+
}
|
|
6863
|
+
}
|
|
6864
|
+
function getProjectConfigData() {
|
|
6865
|
+
const filePath = findProjectConfigPath();
|
|
6866
|
+
if (!filePath) {
|
|
6867
|
+
return null;
|
|
6868
|
+
}
|
|
6869
|
+
return readJsonFile(filePath);
|
|
6870
|
+
}
|
|
6871
|
+
function getConfigData() {
|
|
6872
|
+
return readJsonFile(GLOBAL_CONFIG_FILE) ?? {};
|
|
6873
|
+
}
|
|
6874
|
+
function getCredentialsData() {
|
|
6875
|
+
return readJsonFile(GLOBAL_CREDENTIALS_FILE) ?? {};
|
|
6876
|
+
}
|
|
6877
|
+
function getServiceUrl() {
|
|
6878
|
+
if (process.env.BITFAB_SERVICE_URL) {
|
|
6879
|
+
return process.env.BITFAB_SERVICE_URL;
|
|
6880
|
+
}
|
|
6881
|
+
const project = getProjectConfigData();
|
|
6882
|
+
if (project && typeof project.serviceUrl === "string") {
|
|
6883
|
+
return project.serviceUrl;
|
|
6884
|
+
}
|
|
6885
|
+
const config2 = getConfigData();
|
|
6886
|
+
return typeof config2.serviceUrl === "string" ? config2.serviceUrl : DEFAULT_SERVICE_URL;
|
|
6887
|
+
}
|
|
6888
|
+
function getApiKey() {
|
|
6889
|
+
if (process.env.BITFAB_API_KEY) {
|
|
6890
|
+
return process.env.BITFAB_API_KEY;
|
|
6891
|
+
}
|
|
6892
|
+
const creds = getCredentialsData();
|
|
6893
|
+
return typeof creds.apiKey === "string" ? creds.apiKey : null;
|
|
6894
|
+
}
|
|
6895
|
+
function getVerbose() {
|
|
6896
|
+
if (process.env.BITFAB_VERBOSE === "true" || process.env.BITFAB_VERBOSE === "1") {
|
|
6897
|
+
return true;
|
|
6898
|
+
}
|
|
6899
|
+
if (process.env.BITFAB_VERBOSE === "false" || process.env.BITFAB_VERBOSE === "0") {
|
|
6900
|
+
return false;
|
|
6901
|
+
}
|
|
6902
|
+
const config2 = getConfigData();
|
|
6903
|
+
return config2.verbose === true;
|
|
6904
|
+
}
|
|
6905
|
+
function getDebug() {
|
|
6906
|
+
if (process.env.BITFAB_DEBUG === "true" || process.env.BITFAB_DEBUG === "1") {
|
|
6907
|
+
return true;
|
|
6908
|
+
}
|
|
6909
|
+
const config2 = getConfigData();
|
|
6910
|
+
return config2.debug === true;
|
|
6911
|
+
}
|
|
6912
|
+
function getSessionLogConsentValue() {
|
|
6913
|
+
const config2 = getConfigData();
|
|
6914
|
+
if (config2.sessionLogConsent === true) {
|
|
6915
|
+
return true;
|
|
6916
|
+
}
|
|
6917
|
+
if (config2.sessionLogConsent === false) {
|
|
6918
|
+
return false;
|
|
6919
|
+
}
|
|
6920
|
+
return null;
|
|
6921
|
+
}
|
|
6922
|
+
function getConfig() {
|
|
6923
|
+
return {
|
|
6924
|
+
serviceUrl: getServiceUrl(),
|
|
6925
|
+
apiKey: getApiKey(),
|
|
6926
|
+
verbose: getVerbose(),
|
|
6927
|
+
debug: getDebug(),
|
|
6928
|
+
sessionLogConsent: getSessionLogConsentValue()
|
|
6929
|
+
};
|
|
6930
|
+
}
|
|
6931
|
+
function saveCredentials(apiKey) {
|
|
6932
|
+
fs3.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
6933
|
+
fs3.writeFileSync(GLOBAL_CREDENTIALS_FILE, `${JSON.stringify({ apiKey }, null, 2)}
|
|
6934
|
+
`);
|
|
6935
|
+
}
|
|
6936
|
+
function deleteCredentials() {
|
|
6937
|
+
try {
|
|
6938
|
+
fs3.unlinkSync(GLOBAL_CREDENTIALS_FILE);
|
|
6939
|
+
} catch {
|
|
6940
|
+
}
|
|
6941
|
+
}
|
|
6942
|
+
function hasCredentials() {
|
|
6943
|
+
return getApiKey() !== null;
|
|
6944
|
+
}
|
|
6945
|
+
function getOrCreateInstallId() {
|
|
6946
|
+
const config2 = getConfigData();
|
|
6947
|
+
if (typeof config2.installId === "string" && config2.installId.length > 0) {
|
|
6948
|
+
return config2.installId;
|
|
6949
|
+
}
|
|
6950
|
+
const installId = crypto2.randomUUID();
|
|
6951
|
+
try {
|
|
6952
|
+
fs3.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
6953
|
+
fs3.writeFileSync(GLOBAL_CONFIG_FILE, `${JSON.stringify({ ...config2, installId }, null, 2)}
|
|
6954
|
+
`);
|
|
6955
|
+
} catch {
|
|
6956
|
+
}
|
|
6957
|
+
return installId;
|
|
6958
|
+
}
|
|
6959
|
+
|
|
6960
|
+
// ../bitfab-plugin-lib/dist/chatSessions/transcriptReader.js
|
|
6961
|
+
import fs4 from "fs";
|
|
6962
|
+
|
|
6963
|
+
// ../bitfab-plugin-lib/dist/clientHeaders.js
|
|
6964
|
+
import os5 from "os";
|
|
6965
|
+
function buildBitfabClientHeaders(pluginVersion, platform2) {
|
|
6966
|
+
const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
|
|
6967
|
+
return {
|
|
6968
|
+
"x-bitfab-client-name": platform2.cliBinary,
|
|
6969
|
+
"x-bitfab-client-display-name": platform2.displayName,
|
|
6970
|
+
"x-bitfab-client-version": pluginVersion,
|
|
6971
|
+
"x-bitfab-client-timezone": resolvedOptions.timeZone,
|
|
6972
|
+
"x-bitfab-client-locale": resolvedOptions.locale,
|
|
6973
|
+
"x-bitfab-client-os": os5.platform(),
|
|
6974
|
+
"x-bitfab-client-arch": os5.arch(),
|
|
6975
|
+
"x-bitfab-client-node-version": process.version,
|
|
6976
|
+
"x-bitfab-install-id": getOrCreateInstallId()
|
|
6977
|
+
};
|
|
6978
|
+
}
|
|
6979
|
+
function buildBitfabRequestHeaders(apiKey, pluginVersion, platform2) {
|
|
6980
|
+
return {
|
|
6981
|
+
"Content-Type": "application/json",
|
|
6982
|
+
Authorization: `Bearer ${apiKey}`,
|
|
6983
|
+
...buildBitfabClientHeaders(pluginVersion, platform2)
|
|
6984
|
+
};
|
|
6985
|
+
}
|
|
6986
|
+
|
|
6987
|
+
// ../bitfab-plugin-lib/dist/commands/login.js
|
|
6988
|
+
import crypto3 from "crypto";
|
|
6989
|
+
|
|
6990
|
+
// ../bitfab-plugin-lib/dist/analytics.js
|
|
6991
|
+
async function reportHandoff(apiKey, pluginVersion, platform2, body) {
|
|
6992
|
+
const config2 = getConfig();
|
|
6993
|
+
const headers = buildBitfabRequestHeaders(apiKey, pluginVersion, platform2);
|
|
6994
|
+
try {
|
|
6995
|
+
const response = await fetch(`${config2.serviceUrl}/api/plugin/analytics/handoff`, {
|
|
6996
|
+
method: "POST",
|
|
6997
|
+
headers,
|
|
6998
|
+
body: JSON.stringify(body)
|
|
6999
|
+
});
|
|
7000
|
+
if (config2.debug && !response.ok) {
|
|
7001
|
+
console.error(`reportHandoff: server returned ${response.status} for ${body.flow}`);
|
|
7002
|
+
}
|
|
7003
|
+
} catch (err) {
|
|
7004
|
+
if (config2.debug) {
|
|
7005
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7006
|
+
console.error(`reportHandoff: request failed for ${body.flow}: ${message}`);
|
|
7007
|
+
}
|
|
7008
|
+
}
|
|
7009
|
+
}
|
|
6810
7010
|
|
|
6811
7011
|
// ../bitfab-plugin-lib/dist/browser.js
|
|
6812
7012
|
import { execSync, spawn } from "child_process";
|
|
6813
|
-
import
|
|
6814
|
-
import
|
|
7013
|
+
import fs6 from "fs";
|
|
7014
|
+
import os6 from "os";
|
|
6815
7015
|
function getChromiumBrowsers() {
|
|
6816
|
-
const platform2 =
|
|
7016
|
+
const platform2 = os6.platform();
|
|
6817
7017
|
if (platform2 === "darwin") {
|
|
6818
7018
|
return [
|
|
6819
7019
|
{
|
|
@@ -6901,7 +7101,7 @@ function getChromiumBrowsers() {
|
|
|
6901
7101
|
function findExistingBinary(paths) {
|
|
6902
7102
|
for (const candidate of paths) {
|
|
6903
7103
|
if (candidate.includes("/") || candidate.includes("\\")) {
|
|
6904
|
-
if (
|
|
7104
|
+
if (fs6.existsSync(candidate)) {
|
|
6905
7105
|
return candidate;
|
|
6906
7106
|
}
|
|
6907
7107
|
} else {
|
|
@@ -6915,10 +7115,10 @@ function findExistingBinary(paths) {
|
|
|
6915
7115
|
return null;
|
|
6916
7116
|
}
|
|
6917
7117
|
function getDefaultBrowserId() {
|
|
6918
|
-
const platform2 =
|
|
7118
|
+
const platform2 = os6.platform();
|
|
6919
7119
|
try {
|
|
6920
7120
|
if (platform2 === "darwin") {
|
|
6921
|
-
const plistPath = `${
|
|
7121
|
+
const plistPath = `${os6.homedir()}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`;
|
|
6922
7122
|
const json2 = execSync(`plutil -convert json -o - "${plistPath}"`, {
|
|
6923
7123
|
stdio: ["ignore", "pipe", "ignore"],
|
|
6924
7124
|
encoding: "utf-8",
|
|
@@ -6959,7 +7159,7 @@ function matchChromiumBrowser(defaultId, browsers) {
|
|
|
6959
7159
|
var SCREEN_FRACTION = 0.95;
|
|
6960
7160
|
function getWorkArea() {
|
|
6961
7161
|
try {
|
|
6962
|
-
const platform2 =
|
|
7162
|
+
const platform2 = os6.platform();
|
|
6963
7163
|
if (platform2 === "darwin") {
|
|
6964
7164
|
const out = execSync(`osascript -l JavaScript -e 'ObjC.import("AppKit"); const s = $.NSScreen.mainScreen; const f = s.frame; const v = s.visibleFrame; const topY = f.size.height - (v.origin.y + v.size.height); JSON.stringify([v.origin.x, topY, v.size.width, v.size.height])'`, {
|
|
6965
7165
|
stdio: ["ignore", "pipe", "ignore"],
|
|
@@ -6992,631 +7192,91 @@ function getWorkArea() {
|
|
|
6992
7192
|
timeout: 3e3
|
|
6993
7193
|
});
|
|
6994
7194
|
const match = out.match(/(-?\d+),(-?\d+),(\d+),(\d+)/);
|
|
6995
|
-
if (match) {
|
|
6996
|
-
return {
|
|
6997
|
-
x: Number(match[1]),
|
|
6998
|
-
y: Number(match[2]),
|
|
6999
|
-
width: Number(match[3]),
|
|
7000
|
-
height: Number(match[4])
|
|
7001
|
-
};
|
|
7002
|
-
}
|
|
7003
|
-
}
|
|
7004
|
-
} catch {
|
|
7005
|
-
}
|
|
7006
|
-
return null;
|
|
7007
|
-
}
|
|
7008
|
-
function computeWindowArgs(area) {
|
|
7009
|
-
if (!area) {
|
|
7010
|
-
return [];
|
|
7011
|
-
}
|
|
7012
|
-
const w = Math.floor(area.width * SCREEN_FRACTION);
|
|
7013
|
-
const h = Math.floor(area.height * SCREEN_FRACTION);
|
|
7014
|
-
const x = area.x + Math.floor((area.width - w) / 2);
|
|
7015
|
-
const y = area.y + Math.floor((area.height - h) / 2);
|
|
7016
|
-
return [`--window-size=${w},${h}`, `--window-position=${x},${y}`];
|
|
7017
|
-
}
|
|
7018
|
-
function getWindowSizeArgs() {
|
|
7019
|
-
return computeWindowArgs(getWorkArea());
|
|
7020
|
-
}
|
|
7021
|
-
function spawnDetached(command, args) {
|
|
7022
|
-
const child = spawn(command, [...args], { detached: true, stdio: "ignore" });
|
|
7023
|
-
child.on("error", () => {
|
|
7024
|
-
});
|
|
7025
|
-
child.unref();
|
|
7026
|
-
}
|
|
7027
|
-
function openChromiumApp(binaryPath, url2, sizeArgs) {
|
|
7028
|
-
spawnDetached(binaryPath, [`--app=${url2}`, ...sizeArgs]);
|
|
7029
|
-
}
|
|
7030
|
-
function openOsDefault(url2) {
|
|
7031
|
-
const platform2 = os.platform();
|
|
7032
|
-
if (platform2 === "darwin") {
|
|
7033
|
-
spawnDetached("open", [url2]);
|
|
7034
|
-
} else if (platform2 === "win32") {
|
|
7035
|
-
spawnDetached("cmd", ["/c", "start", "", url2]);
|
|
7036
|
-
} else {
|
|
7037
|
-
spawnDetached("xdg-open", [url2]);
|
|
7038
|
-
}
|
|
7039
|
-
}
|
|
7040
|
-
function isCodexOnMacos() {
|
|
7041
|
-
if (process.platform !== "darwin") {
|
|
7042
|
-
return false;
|
|
7043
|
-
}
|
|
7044
|
-
return process.env.CODEX_SANDBOX === "seatbelt" || process.env.CODEX_CI === "1" || process.env.CODEX_THREAD_ID != null;
|
|
7045
|
-
}
|
|
7046
|
-
function shouldDisableChromelessWindows() {
|
|
7047
|
-
if (process.env.BITFAB_DISABLE_CHROME_APP_WINDOWS === "1") {
|
|
7048
|
-
return true;
|
|
7049
|
-
}
|
|
7050
|
-
return isCodexOnMacos();
|
|
7051
|
-
}
|
|
7052
|
-
function openChromelessWindow(url2) {
|
|
7053
|
-
if (shouldDisableChromelessWindows()) {
|
|
7054
|
-
openOsDefault(url2);
|
|
7055
|
-
return;
|
|
7056
|
-
}
|
|
7057
|
-
const browsers = getChromiumBrowsers();
|
|
7058
|
-
const defaultId = getDefaultBrowserId();
|
|
7059
|
-
const defaultChromium = matchChromiumBrowser(defaultId, browsers);
|
|
7060
|
-
const sizeArgs = getWindowSizeArgs();
|
|
7061
|
-
if (defaultChromium) {
|
|
7062
|
-
const binary = findExistingBinary(defaultChromium.binaryPaths);
|
|
7063
|
-
if (binary) {
|
|
7064
|
-
openChromiumApp(binary, url2, sizeArgs);
|
|
7065
|
-
return;
|
|
7066
|
-
}
|
|
7067
|
-
}
|
|
7068
|
-
if (defaultId !== null && defaultChromium === null) {
|
|
7069
|
-
openOsDefault(url2);
|
|
7070
|
-
return;
|
|
7071
|
-
}
|
|
7072
|
-
for (const browser of browsers) {
|
|
7073
|
-
const binary = findExistingBinary(browser.binaryPaths);
|
|
7074
|
-
if (binary) {
|
|
7075
|
-
openChromiumApp(binary, url2, sizeArgs);
|
|
7076
|
-
return;
|
|
7077
|
-
}
|
|
7078
|
-
}
|
|
7079
|
-
openOsDefault(url2);
|
|
7080
|
-
}
|
|
7081
|
-
|
|
7082
|
-
// ../bitfab-plugin-lib/dist/handoffTickets.js
|
|
7083
|
-
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
7084
|
-
async function createHandoffTicket(serviceUrl, kind, opts) {
|
|
7085
|
-
const headers = {
|
|
7086
|
-
"Content-Type": "application/json"
|
|
7087
|
-
};
|
|
7088
|
-
if (opts?.bearer) {
|
|
7089
|
-
headers.Authorization = `Bearer ${opts.bearer}`;
|
|
7090
|
-
}
|
|
7091
|
-
const res = await fetch(`${serviceUrl}/api/plugin/handoff-tickets`, {
|
|
7092
|
-
method: "POST",
|
|
7093
|
-
headers,
|
|
7094
|
-
body: JSON.stringify({
|
|
7095
|
-
kind,
|
|
7096
|
-
pkceChallenge: opts?.pkceChallenge,
|
|
7097
|
-
pkceMethod: opts?.pkceMethod,
|
|
7098
|
-
ttlSeconds: opts?.ttlSeconds
|
|
7099
|
-
})
|
|
7100
|
-
});
|
|
7101
|
-
if (!res.ok) {
|
|
7102
|
-
const body = await res.json().catch(() => ({}));
|
|
7103
|
-
throw new Error(body.error ?? `Failed to create handoff ticket (${res.status})`);
|
|
7104
|
-
}
|
|
7105
|
-
return await res.json();
|
|
7106
|
-
}
|
|
7107
|
-
async function pollHandoffTicket(serviceUrl, ticketId, opts) {
|
|
7108
|
-
const interval = opts.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
7109
|
-
const deadline = Date.now() + opts.timeoutMs;
|
|
7110
|
-
while (Date.now() < deadline) {
|
|
7111
|
-
if (opts.abortSignal?.aborted) {
|
|
7112
|
-
return { expired: true };
|
|
7113
|
-
}
|
|
7114
|
-
const url2 = new URL(`${serviceUrl}/api/plugin/handoff-tickets/${ticketId}`);
|
|
7115
|
-
if (opts.verifier) {
|
|
7116
|
-
url2.searchParams.set("verifier", opts.verifier);
|
|
7117
|
-
}
|
|
7118
|
-
const headers = {};
|
|
7119
|
-
if (opts.bearer) {
|
|
7120
|
-
headers.Authorization = `Bearer ${opts.bearer}`;
|
|
7121
|
-
}
|
|
7122
|
-
try {
|
|
7123
|
-
const res = await fetch(url2.toString(), { headers });
|
|
7124
|
-
if (res.ok) {
|
|
7125
|
-
const body = await res.json();
|
|
7126
|
-
if (body.status === "completed" && body.data) {
|
|
7127
|
-
return { data: body.data };
|
|
7128
|
-
}
|
|
7129
|
-
if (body.status === "expired" || body.status === "cancelled") {
|
|
7130
|
-
return { expired: true };
|
|
7131
|
-
}
|
|
7132
|
-
}
|
|
7133
|
-
} catch {
|
|
7134
|
-
}
|
|
7135
|
-
await new Promise((resolve, reject) => {
|
|
7136
|
-
const timer = setTimeout(resolve, interval);
|
|
7137
|
-
opts.abortSignal?.addEventListener("abort", () => {
|
|
7138
|
-
clearTimeout(timer);
|
|
7139
|
-
reject(new DOMException("Aborted", "AbortError"));
|
|
7140
|
-
}, { once: true });
|
|
7141
|
-
}).catch(() => {
|
|
7142
|
-
});
|
|
7143
|
-
}
|
|
7144
|
-
return { expired: true };
|
|
7145
|
-
}
|
|
7146
|
-
|
|
7147
|
-
// ../bitfab-plugin-lib/dist/pkce.js
|
|
7148
|
-
import crypto from "crypto";
|
|
7149
|
-
function generatePkce() {
|
|
7150
|
-
const verifier = crypto.randomBytes(32).toString("base64url");
|
|
7151
|
-
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");
|
|
7152
|
-
return { verifier, challenge };
|
|
7153
|
-
}
|
|
7154
|
-
|
|
7155
|
-
// ../bitfab-plugin-lib/dist/handoffTicketChannel.js
|
|
7156
|
-
async function startHandoffTicketChannel(opts) {
|
|
7157
|
-
const { verifier, challenge } = generatePkce();
|
|
7158
|
-
const abort = new AbortController();
|
|
7159
|
-
let done = false;
|
|
7160
|
-
let resolveFn = () => {
|
|
7161
|
-
};
|
|
7162
|
-
let rejectFn = () => {
|
|
7163
|
-
};
|
|
7164
|
-
const promise2 = new Promise((resolve, reject) => {
|
|
7165
|
-
resolveFn = (value) => {
|
|
7166
|
-
if (done) {
|
|
7167
|
-
return;
|
|
7168
|
-
}
|
|
7169
|
-
done = true;
|
|
7170
|
-
resolve(value);
|
|
7171
|
-
};
|
|
7172
|
-
rejectFn = (err) => {
|
|
7173
|
-
if (done) {
|
|
7174
|
-
return;
|
|
7175
|
-
}
|
|
7176
|
-
done = true;
|
|
7177
|
-
reject(err);
|
|
7178
|
-
};
|
|
7179
|
-
});
|
|
7180
|
-
let startError = null;
|
|
7181
|
-
let ticket = null;
|
|
7182
|
-
try {
|
|
7183
|
-
ticket = await createHandoffTicket(opts.serviceUrl, opts.kind, {
|
|
7184
|
-
pkceChallenge: challenge,
|
|
7185
|
-
pkceMethod: "S256",
|
|
7186
|
-
bearer: opts.bearer,
|
|
7187
|
-
ttlSeconds: opts.ttlSeconds
|
|
7188
|
-
});
|
|
7189
|
-
} catch (err) {
|
|
7190
|
-
startError = err instanceof Error ? err : new Error(String(err));
|
|
7191
|
-
}
|
|
7192
|
-
const available = ticket !== null;
|
|
7193
|
-
if (ticket) {
|
|
7194
|
-
pollHandoffTicket(opts.serviceUrl, ticket.id, {
|
|
7195
|
-
verifier,
|
|
7196
|
-
bearer: opts.bearer,
|
|
7197
|
-
timeoutMs: opts.timeoutMs,
|
|
7198
|
-
intervalMs: ticket.pollIntervalMs,
|
|
7199
|
-
abortSignal: abort.signal
|
|
7200
|
-
}).then((result) => {
|
|
7201
|
-
if ("expired" in result) {
|
|
7202
|
-
rejectFn(new Error("Handoff ticket expired before completion."));
|
|
7203
|
-
return;
|
|
7204
|
-
}
|
|
7205
|
-
resolveFn(result.data);
|
|
7206
|
-
}).catch((err) => {
|
|
7207
|
-
rejectFn(err instanceof Error ? err : new Error(String(err)));
|
|
7208
|
-
});
|
|
7209
|
-
} else {
|
|
7210
|
-
promise2.catch(() => {
|
|
7211
|
-
});
|
|
7212
|
-
}
|
|
7213
|
-
return {
|
|
7214
|
-
promise: promise2,
|
|
7215
|
-
get done() {
|
|
7216
|
-
return done;
|
|
7217
|
-
},
|
|
7218
|
-
available,
|
|
7219
|
-
startError,
|
|
7220
|
-
ticketId: ticket?.id ?? null,
|
|
7221
|
-
reject: rejectFn,
|
|
7222
|
-
close: () => {
|
|
7223
|
-
abort.abort();
|
|
7224
|
-
rejectFn(new Error("Handoff ticket channel closed."));
|
|
7225
|
-
}
|
|
7226
|
-
};
|
|
7227
|
-
}
|
|
7228
|
-
|
|
7229
|
-
// ../bitfab-plugin-lib/dist/loopback.js
|
|
7230
|
-
import http from "http";
|
|
7231
|
-
async function startLoopbackServer(port, routes) {
|
|
7232
|
-
let done = false;
|
|
7233
|
-
let resolveFn = () => {
|
|
7234
|
-
};
|
|
7235
|
-
let rejectFn = () => {
|
|
7236
|
-
};
|
|
7237
|
-
const promise2 = new Promise((resolve, reject) => {
|
|
7238
|
-
resolveFn = (value) => {
|
|
7239
|
-
if (done) {
|
|
7240
|
-
return;
|
|
7241
|
-
}
|
|
7242
|
-
done = true;
|
|
7243
|
-
resolve(value);
|
|
7244
|
-
};
|
|
7245
|
-
rejectFn = (err) => {
|
|
7246
|
-
if (done) {
|
|
7247
|
-
return;
|
|
7248
|
-
}
|
|
7249
|
-
done = true;
|
|
7250
|
-
reject(err);
|
|
7251
|
-
};
|
|
7252
|
-
});
|
|
7253
|
-
const server = http.createServer((req, res) => {
|
|
7254
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
7255
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
7256
|
-
res.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
7257
|
-
if (req.method === "OPTIONS") {
|
|
7258
|
-
res.writeHead(204);
|
|
7259
|
-
res.end();
|
|
7260
|
-
return;
|
|
7261
|
-
}
|
|
7262
|
-
const url2 = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
7263
|
-
if (url2.pathname === "/health") {
|
|
7264
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
7265
|
-
res.end(JSON.stringify({ ok: true }));
|
|
7266
|
-
return;
|
|
7267
|
-
}
|
|
7268
|
-
const route = routes.find((r) => r.path === url2.pathname);
|
|
7269
|
-
if (route) {
|
|
7270
|
-
try {
|
|
7271
|
-
route.handle(url2.searchParams, res, resolveFn);
|
|
7272
|
-
} catch (err) {
|
|
7273
|
-
rejectFn(err);
|
|
7274
|
-
}
|
|
7275
|
-
return;
|
|
7276
|
-
}
|
|
7277
|
-
res.writeHead(404);
|
|
7278
|
-
res.end();
|
|
7279
|
-
});
|
|
7280
|
-
let bindError = null;
|
|
7281
|
-
try {
|
|
7282
|
-
await new Promise((resolve, reject) => {
|
|
7283
|
-
const onError = (err) => {
|
|
7284
|
-
server.removeListener("listening", onListening);
|
|
7285
|
-
reject(err);
|
|
7286
|
-
};
|
|
7287
|
-
const onListening = () => {
|
|
7288
|
-
server.removeListener("error", onError);
|
|
7289
|
-
resolve();
|
|
7290
|
-
};
|
|
7291
|
-
server.once("error", onError);
|
|
7292
|
-
server.once("listening", onListening);
|
|
7293
|
-
server.listen(port, "127.0.0.1");
|
|
7294
|
-
});
|
|
7295
|
-
} catch (err) {
|
|
7296
|
-
bindError = err;
|
|
7297
|
-
}
|
|
7298
|
-
const available = bindError === null;
|
|
7299
|
-
if (available) {
|
|
7300
|
-
server.on("error", (err) => {
|
|
7301
|
-
rejectFn(new Error(`Loopback server error: ${err.message}`));
|
|
7302
|
-
});
|
|
7303
|
-
} else {
|
|
7304
|
-
promise2.catch(() => {
|
|
7305
|
-
});
|
|
7306
|
-
}
|
|
7307
|
-
return {
|
|
7308
|
-
promise: promise2,
|
|
7309
|
-
get done() {
|
|
7310
|
-
return done;
|
|
7311
|
-
},
|
|
7312
|
-
available,
|
|
7313
|
-
bindError,
|
|
7314
|
-
resolve: resolveFn,
|
|
7315
|
-
reject: rejectFn,
|
|
7316
|
-
close: () => {
|
|
7317
|
-
if (available) {
|
|
7318
|
-
server.close();
|
|
7319
|
-
}
|
|
7320
|
-
}
|
|
7321
|
-
};
|
|
7322
|
-
}
|
|
7323
|
-
|
|
7324
|
-
// ../bitfab-plugin-lib/dist/browserHandoff.js
|
|
7325
|
-
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
7326
|
-
var DEFAULT_REDISPLAY_DELAY_MS = 4 * 1e3;
|
|
7327
|
-
var DEFAULT_HEARTBEAT_INTERVAL_MS = 30 * 1e3;
|
|
7328
|
-
function findOpenPort() {
|
|
7329
|
-
return new Promise((resolve, reject) => {
|
|
7330
|
-
const server = http2.createServer();
|
|
7331
|
-
server.on("error", (err) => {
|
|
7332
|
-
server.close(() => reject(err));
|
|
7333
|
-
});
|
|
7334
|
-
server.listen(0, "127.0.0.1", () => {
|
|
7335
|
-
const addr = server.address();
|
|
7336
|
-
if (addr && typeof addr === "object") {
|
|
7337
|
-
const port = addr.port;
|
|
7338
|
-
server.close(() => resolve(port));
|
|
7339
|
-
} else {
|
|
7340
|
-
reject(new Error("Could not find open port"));
|
|
7341
|
-
}
|
|
7342
|
-
});
|
|
7343
|
-
});
|
|
7344
|
-
}
|
|
7345
|
-
async function startBrowserHandoff(opts) {
|
|
7346
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
7347
|
-
const forceTicket = process.env.BITFAB_FORCE_TICKET === "1";
|
|
7348
|
-
let port = null;
|
|
7349
|
-
let portBindError = null;
|
|
7350
|
-
if (!forceTicket) {
|
|
7351
|
-
try {
|
|
7352
|
-
port = await findOpenPort();
|
|
7353
|
-
} catch (err) {
|
|
7354
|
-
portBindError = err;
|
|
7355
|
-
}
|
|
7356
|
-
}
|
|
7357
|
-
const loopbackUnavailable = {
|
|
7358
|
-
promise: new Promise(() => {
|
|
7359
|
-
}),
|
|
7360
|
-
get done() {
|
|
7361
|
-
return false;
|
|
7362
|
-
},
|
|
7363
|
-
available: false,
|
|
7364
|
-
bindError: portBindError ?? new Error("BITFAB_FORCE_TICKET=1 disabled loopback"),
|
|
7365
|
-
resolve: () => {
|
|
7366
|
-
},
|
|
7367
|
-
reject: () => {
|
|
7368
|
-
},
|
|
7369
|
-
close: () => {
|
|
7370
|
-
}
|
|
7371
|
-
};
|
|
7372
|
-
const [loopback, ticket] = await Promise.all([
|
|
7373
|
-
forceTicket || port === null ? Promise.resolve(loopbackUnavailable) : startLoopbackServer(port, opts.loopbackRoutes),
|
|
7374
|
-
startHandoffTicketChannel({
|
|
7375
|
-
serviceUrl: opts.serviceUrl,
|
|
7376
|
-
kind: opts.ticketKind,
|
|
7377
|
-
timeoutMs,
|
|
7378
|
-
ttlSeconds: opts.ticketTtlSeconds,
|
|
7379
|
-
bearer: opts.ticketBearer
|
|
7380
|
-
})
|
|
7381
|
-
]);
|
|
7382
|
-
const browserUrl = opts.buildUrl({
|
|
7383
|
-
port: loopback.available ? port : null,
|
|
7384
|
-
ticketId: ticket.ticketId
|
|
7385
|
-
});
|
|
7386
|
-
return { loopback, ticket, port, browserUrl, timeoutMs };
|
|
7387
|
-
}
|
|
7388
|
-
function attachBrowserHandoffKeepalive(opts) {
|
|
7389
|
-
const redisplayDelay = opts.redisplayDelayMs ?? DEFAULT_REDISPLAY_DELAY_MS;
|
|
7390
|
-
const heartbeatInterval = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
7391
|
-
const startedAt = Date.now();
|
|
7392
|
-
const done = () => opts.loopback.done || opts.ticket.done;
|
|
7393
|
-
const redisplayTimer = setTimeout(() => {
|
|
7394
|
-
if (done()) {
|
|
7395
|
-
return;
|
|
7396
|
-
}
|
|
7397
|
-
console.error("");
|
|
7398
|
-
console.error("Still waiting for browser handoff. If the browser didn't open,");
|
|
7399
|
-
console.error("copy this URL into any browser \u2014 this session is still valid:");
|
|
7400
|
-
console.error("");
|
|
7401
|
-
console.error(` ${opts.browserUrl}`);
|
|
7402
|
-
console.error("");
|
|
7403
|
-
}, redisplayDelay);
|
|
7404
|
-
const heartbeat = process.stdout.isTTY ? null : setInterval(() => {
|
|
7405
|
-
if (done()) {
|
|
7406
|
-
return;
|
|
7407
|
-
}
|
|
7408
|
-
const elapsed = Math.round((Date.now() - startedAt) / 1e3);
|
|
7409
|
-
console.error(`[bitfab] waiting for browser handoff... ${elapsed}s elapsed, session still live`);
|
|
7410
|
-
}, heartbeatInterval);
|
|
7411
|
-
return () => {
|
|
7412
|
-
clearTimeout(redisplayTimer);
|
|
7413
|
-
if (heartbeat) {
|
|
7414
|
-
clearInterval(heartbeat);
|
|
7415
|
-
}
|
|
7416
|
-
};
|
|
7417
|
-
}
|
|
7418
|
-
|
|
7419
|
-
// ../bitfab-plugin-lib/dist/buildInfo.js
|
|
7420
|
-
import crypto2 from "crypto";
|
|
7421
|
-
import fs2 from "fs";
|
|
7422
|
-
import os2 from "os";
|
|
7423
|
-
import path from "path";
|
|
7424
|
-
import { fileURLToPath } from "url";
|
|
7425
|
-
|
|
7426
|
-
// ../bitfab-plugin-lib/dist/chatSessions/index.js
|
|
7427
|
-
import { execFileSync } from "child_process";
|
|
7428
|
-
import fs6 from "fs";
|
|
7429
|
-
import os5 from "os";
|
|
7430
|
-
import path4 from "path";
|
|
7431
|
-
|
|
7432
|
-
// ../bitfab-plugin-lib/dist/skills.js
|
|
7433
|
-
var BITFAB_SKILLS = ["setup", "assistant", "update"];
|
|
7434
|
-
|
|
7435
|
-
// ../bitfab-plugin-lib/dist/hooks/skillDetection.js
|
|
7436
|
-
var SKILL_PATTERN = new RegExp(`^\\s*\\/bitfab[:-](?<skill>${BITFAB_SKILLS.join("|")})(?=\\s|$)`, "i");
|
|
7437
|
-
|
|
7438
|
-
// ../bitfab-plugin-lib/dist/chatSessions/arming.js
|
|
7439
|
-
import fs3 from "fs";
|
|
7440
|
-
import os3 from "os";
|
|
7441
|
-
import path2 from "path";
|
|
7442
|
-
|
|
7443
|
-
// ../bitfab-plugin-lib/dist/config.js
|
|
7444
|
-
import crypto3 from "crypto";
|
|
7445
|
-
import fs4 from "fs";
|
|
7446
|
-
import os4 from "os";
|
|
7447
|
-
import path3 from "path";
|
|
7448
|
-
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
7449
|
-
var GLOBAL_CONFIG_DIR = path3.join(os4.homedir(), ".config", "bitfab");
|
|
7450
|
-
var GLOBAL_CONFIG_FILE = path3.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
7451
|
-
var GLOBAL_CREDENTIALS_FILE = path3.join(GLOBAL_CONFIG_DIR, "credentials.json");
|
|
7452
|
-
var PROJECT_CONFIG_RELATIVE = path3.join(".bitfab", "config.local.json");
|
|
7453
|
-
function readJsonFile(filePath) {
|
|
7454
|
-
try {
|
|
7455
|
-
const content = fs4.readFileSync(filePath, "utf-8");
|
|
7456
|
-
return JSON.parse(content);
|
|
7457
|
-
} catch {
|
|
7458
|
-
return null;
|
|
7459
|
-
}
|
|
7460
|
-
}
|
|
7461
|
-
function findProjectConfigPath(startDir = process.cwd()) {
|
|
7462
|
-
let dir = startDir;
|
|
7463
|
-
while (true) {
|
|
7464
|
-
const candidate = path3.join(dir, PROJECT_CONFIG_RELATIVE);
|
|
7465
|
-
if (fs4.existsSync(candidate)) {
|
|
7466
|
-
return candidate;
|
|
7467
|
-
}
|
|
7468
|
-
const parent = path3.dirname(dir);
|
|
7469
|
-
if (parent === dir) {
|
|
7470
|
-
return null;
|
|
7195
|
+
if (match) {
|
|
7196
|
+
return {
|
|
7197
|
+
x: Number(match[1]),
|
|
7198
|
+
y: Number(match[2]),
|
|
7199
|
+
width: Number(match[3]),
|
|
7200
|
+
height: Number(match[4])
|
|
7201
|
+
};
|
|
7202
|
+
}
|
|
7471
7203
|
}
|
|
7472
|
-
|
|
7204
|
+
} catch {
|
|
7473
7205
|
}
|
|
7206
|
+
return null;
|
|
7474
7207
|
}
|
|
7475
|
-
function
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
return null;
|
|
7208
|
+
function computeWindowArgs(area) {
|
|
7209
|
+
if (!area) {
|
|
7210
|
+
return [];
|
|
7479
7211
|
}
|
|
7480
|
-
|
|
7212
|
+
const w = Math.floor(area.width * SCREEN_FRACTION);
|
|
7213
|
+
const h = Math.floor(area.height * SCREEN_FRACTION);
|
|
7214
|
+
const x = area.x + Math.floor((area.width - w) / 2);
|
|
7215
|
+
const y = area.y + Math.floor((area.height - h) / 2);
|
|
7216
|
+
return [`--window-size=${w},${h}`, `--window-position=${x},${y}`];
|
|
7481
7217
|
}
|
|
7482
|
-
function
|
|
7483
|
-
return
|
|
7218
|
+
function getWindowSizeArgs() {
|
|
7219
|
+
return computeWindowArgs(getWorkArea());
|
|
7484
7220
|
}
|
|
7485
|
-
function
|
|
7486
|
-
|
|
7221
|
+
function spawnDetached(command, args) {
|
|
7222
|
+
const child = spawn(command, [...args], { detached: true, stdio: "ignore" });
|
|
7223
|
+
child.on("error", () => {
|
|
7224
|
+
});
|
|
7225
|
+
child.unref();
|
|
7487
7226
|
}
|
|
7488
|
-
function
|
|
7489
|
-
|
|
7490
|
-
return process.env.BITFAB_SERVICE_URL;
|
|
7491
|
-
}
|
|
7492
|
-
const project = getProjectConfigData();
|
|
7493
|
-
if (project && typeof project.serviceUrl === "string") {
|
|
7494
|
-
return project.serviceUrl;
|
|
7495
|
-
}
|
|
7496
|
-
const config2 = getConfigData();
|
|
7497
|
-
return typeof config2.serviceUrl === "string" ? config2.serviceUrl : DEFAULT_SERVICE_URL;
|
|
7227
|
+
function openChromiumApp(binaryPath, url2, sizeArgs) {
|
|
7228
|
+
spawnDetached(binaryPath, [`--app=${url2}`, ...sizeArgs]);
|
|
7498
7229
|
}
|
|
7499
|
-
function
|
|
7500
|
-
|
|
7501
|
-
|
|
7230
|
+
function openOsDefault(url2) {
|
|
7231
|
+
const platform2 = os6.platform();
|
|
7232
|
+
if (platform2 === "darwin") {
|
|
7233
|
+
spawnDetached("open", [url2]);
|
|
7234
|
+
} else if (platform2 === "win32") {
|
|
7235
|
+
spawnDetached("cmd", ["/c", "start", "", url2]);
|
|
7236
|
+
} else {
|
|
7237
|
+
spawnDetached("xdg-open", [url2]);
|
|
7502
7238
|
}
|
|
7503
|
-
const creds = getCredentialsData();
|
|
7504
|
-
return typeof creds.apiKey === "string" ? creds.apiKey : null;
|
|
7505
7239
|
}
|
|
7506
|
-
function
|
|
7507
|
-
if (process.
|
|
7508
|
-
return true;
|
|
7509
|
-
}
|
|
7510
|
-
if (process.env.BITFAB_VERBOSE === "false" || process.env.BITFAB_VERBOSE === "0") {
|
|
7240
|
+
function isCodexOnMacos() {
|
|
7241
|
+
if (process.platform !== "darwin") {
|
|
7511
7242
|
return false;
|
|
7512
7243
|
}
|
|
7513
|
-
|
|
7514
|
-
return config2.verbose === true;
|
|
7515
|
-
}
|
|
7516
|
-
function getDebug() {
|
|
7517
|
-
if (process.env.BITFAB_DEBUG === "true" || process.env.BITFAB_DEBUG === "1") {
|
|
7518
|
-
return true;
|
|
7519
|
-
}
|
|
7520
|
-
const config2 = getConfigData();
|
|
7521
|
-
return config2.debug === true;
|
|
7244
|
+
return process.env.CODEX_SANDBOX === "seatbelt" || process.env.CODEX_CI === "1" || process.env.CODEX_THREAD_ID != null;
|
|
7522
7245
|
}
|
|
7523
|
-
function
|
|
7524
|
-
|
|
7525
|
-
if (config2.sessionLogConsent === true) {
|
|
7246
|
+
function shouldDisableChromelessWindows() {
|
|
7247
|
+
if (process.env.BITFAB_DISABLE_CHROME_APP_WINDOWS === "1") {
|
|
7526
7248
|
return true;
|
|
7527
7249
|
}
|
|
7528
|
-
|
|
7529
|
-
return false;
|
|
7530
|
-
}
|
|
7531
|
-
return null;
|
|
7532
|
-
}
|
|
7533
|
-
function getConfig() {
|
|
7534
|
-
return {
|
|
7535
|
-
serviceUrl: getServiceUrl(),
|
|
7536
|
-
apiKey: getApiKey(),
|
|
7537
|
-
verbose: getVerbose(),
|
|
7538
|
-
debug: getDebug(),
|
|
7539
|
-
sessionLogConsent: getSessionLogConsentValue()
|
|
7540
|
-
};
|
|
7541
|
-
}
|
|
7542
|
-
function saveCredentials(apiKey) {
|
|
7543
|
-
fs4.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
7544
|
-
fs4.writeFileSync(GLOBAL_CREDENTIALS_FILE, `${JSON.stringify({ apiKey }, null, 2)}
|
|
7545
|
-
`);
|
|
7250
|
+
return isCodexOnMacos();
|
|
7546
7251
|
}
|
|
7547
|
-
function
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7252
|
+
function openChromelessWindow(url2) {
|
|
7253
|
+
if (shouldDisableChromelessWindows()) {
|
|
7254
|
+
openOsDefault(url2);
|
|
7255
|
+
return;
|
|
7551
7256
|
}
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7257
|
+
const browsers = getChromiumBrowsers();
|
|
7258
|
+
const defaultId = getDefaultBrowserId();
|
|
7259
|
+
const defaultChromium = matchChromiumBrowser(defaultId, browsers);
|
|
7260
|
+
const sizeArgs = getWindowSizeArgs();
|
|
7261
|
+
if (defaultChromium) {
|
|
7262
|
+
const binary = findExistingBinary(defaultChromium.binaryPaths);
|
|
7263
|
+
if (binary) {
|
|
7264
|
+
openChromiumApp(binary, url2, sizeArgs);
|
|
7265
|
+
return;
|
|
7266
|
+
}
|
|
7560
7267
|
}
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
fs4.writeFileSync(GLOBAL_CONFIG_FILE, `${JSON.stringify({ ...config2, installId }, null, 2)}
|
|
7565
|
-
`);
|
|
7566
|
-
} catch {
|
|
7268
|
+
if (defaultId !== null && defaultChromium === null) {
|
|
7269
|
+
openOsDefault(url2);
|
|
7270
|
+
return;
|
|
7567
7271
|
}
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
// ../bitfab-plugin-lib/dist/clientHeaders.js
|
|
7575
|
-
import os6 from "os";
|
|
7576
|
-
function buildBitfabClientHeaders(pluginVersion, platform2) {
|
|
7577
|
-
const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
|
|
7578
|
-
return {
|
|
7579
|
-
"x-bitfab-client-name": platform2.cliBinary,
|
|
7580
|
-
"x-bitfab-client-display-name": platform2.displayName,
|
|
7581
|
-
"x-bitfab-client-version": pluginVersion,
|
|
7582
|
-
"x-bitfab-client-timezone": resolvedOptions.timeZone,
|
|
7583
|
-
"x-bitfab-client-locale": resolvedOptions.locale,
|
|
7584
|
-
"x-bitfab-client-os": os6.platform(),
|
|
7585
|
-
"x-bitfab-client-arch": os6.arch(),
|
|
7586
|
-
"x-bitfab-client-node-version": process.version,
|
|
7587
|
-
"x-bitfab-install-id": getOrCreateInstallId()
|
|
7588
|
-
};
|
|
7589
|
-
}
|
|
7590
|
-
function buildBitfabRequestHeaders(apiKey, pluginVersion, platform2) {
|
|
7591
|
-
return {
|
|
7592
|
-
"Content-Type": "application/json",
|
|
7593
|
-
Authorization: `Bearer ${apiKey}`,
|
|
7594
|
-
...buildBitfabClientHeaders(pluginVersion, platform2)
|
|
7595
|
-
};
|
|
7596
|
-
}
|
|
7597
|
-
|
|
7598
|
-
// ../bitfab-plugin-lib/dist/commands/login.js
|
|
7599
|
-
import readline from "readline";
|
|
7600
|
-
|
|
7601
|
-
// ../bitfab-plugin-lib/dist/analytics.js
|
|
7602
|
-
async function reportHandoff(apiKey, pluginVersion, platform2, body) {
|
|
7603
|
-
const config2 = getConfig();
|
|
7604
|
-
const headers = buildBitfabRequestHeaders(apiKey, pluginVersion, platform2);
|
|
7605
|
-
try {
|
|
7606
|
-
const response = await fetch(`${config2.serviceUrl}/api/plugin/analytics/handoff`, {
|
|
7607
|
-
method: "POST",
|
|
7608
|
-
headers,
|
|
7609
|
-
body: JSON.stringify(body)
|
|
7610
|
-
});
|
|
7611
|
-
if (config2.debug && !response.ok) {
|
|
7612
|
-
console.error(`reportHandoff: server returned ${response.status} for ${body.flow}`);
|
|
7613
|
-
}
|
|
7614
|
-
} catch (err) {
|
|
7615
|
-
if (config2.debug) {
|
|
7616
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
7617
|
-
console.error(`reportHandoff: request failed for ${body.flow}: ${message}`);
|
|
7272
|
+
for (const browser of browsers) {
|
|
7273
|
+
const binary = findExistingBinary(browser.binaryPaths);
|
|
7274
|
+
if (binary) {
|
|
7275
|
+
openChromiumApp(binary, url2, sizeArgs);
|
|
7276
|
+
return;
|
|
7618
7277
|
}
|
|
7619
7278
|
}
|
|
7279
|
+
openOsDefault(url2);
|
|
7620
7280
|
}
|
|
7621
7281
|
|
|
7622
7282
|
// ../bitfab-plugin-lib/dist/frontmostApp.js
|
|
@@ -7766,16 +7426,7 @@ function recordFocus() {
|
|
|
7766
7426
|
|
|
7767
7427
|
// ../bitfab-plugin-lib/dist/commands/login.js
|
|
7768
7428
|
var LOGIN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
7769
|
-
var
|
|
7770
|
-
var CALLBACK_HTML = `<html>
|
|
7771
|
-
<body style="margin:0;background:#f8fafc;color:#0f172a;font-family:system-ui,-apple-system,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;overflow:hidden">
|
|
7772
|
-
<div style="text-align:center;max-width:400px">
|
|
7773
|
-
<h1 style="font-size:24px;font-weight:600;margin:0 0 16px 0">Bitfab</h1>
|
|
7774
|
-
<p style="margin:0;color:#059669">Authenticated! You can close this window.</p>
|
|
7775
|
-
<button onclick="window.close()" style="margin-top:16px;padding:8px 16px;background:#0f172a;color:white;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer">Close Window</button>
|
|
7776
|
-
</div>
|
|
7777
|
-
</body>
|
|
7778
|
-
</html>`;
|
|
7429
|
+
var POLL_INTERVAL_MS = 1500;
|
|
7779
7430
|
async function verifyToken(serviceUrl, token) {
|
|
7780
7431
|
try {
|
|
7781
7432
|
const res = await fetch(`${serviceUrl}/api/plugin/whoami`, {
|
|
@@ -7789,141 +7440,86 @@ async function verifyToken(serviceUrl, token) {
|
|
|
7789
7440
|
return null;
|
|
7790
7441
|
}
|
|
7791
7442
|
}
|
|
7443
|
+
async function pollLoginStatus(serviceUrl, loginId, signal) {
|
|
7444
|
+
while (!signal.aborted) {
|
|
7445
|
+
try {
|
|
7446
|
+
const url2 = `${serviceUrl}/api/studio/login-status?loginId=${encodeURIComponent(loginId)}`;
|
|
7447
|
+
const res = await fetch(url2, { signal });
|
|
7448
|
+
if (res.ok) {
|
|
7449
|
+
const body = await res.json();
|
|
7450
|
+
if (body.status === "complete" && body.token) {
|
|
7451
|
+
return body.token;
|
|
7452
|
+
}
|
|
7453
|
+
}
|
|
7454
|
+
} catch {
|
|
7455
|
+
if (signal.aborted) {
|
|
7456
|
+
throw new Error("Login polling aborted");
|
|
7457
|
+
}
|
|
7458
|
+
}
|
|
7459
|
+
await new Promise((resolve) => {
|
|
7460
|
+
const timer = setTimeout(resolve, POLL_INTERVAL_MS);
|
|
7461
|
+
signal.addEventListener("abort", () => {
|
|
7462
|
+
clearTimeout(timer);
|
|
7463
|
+
resolve();
|
|
7464
|
+
}, { once: true });
|
|
7465
|
+
});
|
|
7466
|
+
}
|
|
7467
|
+
throw new Error("Login polling aborted");
|
|
7468
|
+
}
|
|
7792
7469
|
async function runLogin(platform2, pluginVersion, options) {
|
|
7793
7470
|
const exitOnComplete = options?.exitOnComplete ?? true;
|
|
7794
7471
|
const config2 = getConfig();
|
|
7795
7472
|
const restoreFocus = recordFocus();
|
|
7796
|
-
const
|
|
7797
|
-
const
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
timeoutMs: LOGIN_TIMEOUT_MS,
|
|
7801
|
-
buildUrl: ({ port, ticketId }) => {
|
|
7802
|
-
const urlParams = new URLSearchParams();
|
|
7803
|
-
if (port !== null) {
|
|
7804
|
-
urlParams.set("callbackPort", String(port));
|
|
7805
|
-
}
|
|
7806
|
-
if (ticketId !== null) {
|
|
7807
|
-
urlParams.set("ticket", ticketId);
|
|
7808
|
-
}
|
|
7809
|
-
const base = `${config2.serviceUrl}/plugin/auth/${platform2.authPath}`;
|
|
7810
|
-
const qs = urlParams.toString();
|
|
7811
|
-
return qs ? `${base}?${qs}` : base;
|
|
7812
|
-
},
|
|
7813
|
-
loopbackRoutes: [
|
|
7814
|
-
{
|
|
7815
|
-
path: "/callback",
|
|
7816
|
-
handle: (params, res, resolve) => {
|
|
7817
|
-
const token = params.get("token");
|
|
7818
|
-
if (token) {
|
|
7819
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
7820
|
-
res.end(CALLBACK_HTML);
|
|
7821
|
-
resolve({ token });
|
|
7822
|
-
} else {
|
|
7823
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
7824
|
-
res.end(JSON.stringify({ ok: false, error: "No token received" }));
|
|
7825
|
-
}
|
|
7826
|
-
}
|
|
7827
|
-
}
|
|
7828
|
-
]
|
|
7829
|
-
});
|
|
7830
|
-
console.log("\nOpening your browser to sign in...");
|
|
7473
|
+
const loginId = crypto3.randomUUID();
|
|
7474
|
+
const redirectUrl = `/studio/close?pluginLogin=true&loginId=${loginId}`;
|
|
7475
|
+
const browserUrl = `${config2.serviceUrl}/studio/sign-in?redirect_url=${encodeURIComponent(redirectUrl)}`;
|
|
7476
|
+
console.log("\nOpening Studio to sign in...");
|
|
7831
7477
|
console.log(` ${browserUrl}`);
|
|
7832
7478
|
console.log("");
|
|
7833
7479
|
console.log("(If the browser didn't open, visit the URL above manually.)");
|
|
7834
7480
|
openChromelessWindow(browserUrl);
|
|
7835
|
-
const
|
|
7836
|
-
loopback,
|
|
7837
|
-
ticket,
|
|
7838
|
-
browserUrl
|
|
7839
|
-
});
|
|
7840
|
-
let resolvePaste = () => {
|
|
7841
|
-
};
|
|
7842
|
-
let pasteDone = false;
|
|
7843
|
-
const pastePromise = new Promise((resolve) => {
|
|
7844
|
-
resolvePaste = (value) => {
|
|
7845
|
-
if (pasteDone) {
|
|
7846
|
-
return;
|
|
7847
|
-
}
|
|
7848
|
-
pasteDone = true;
|
|
7849
|
-
resolve(value);
|
|
7850
|
-
};
|
|
7851
|
-
});
|
|
7852
|
-
const rl = interactive ? readline.createInterface({
|
|
7853
|
-
input: process.stdin,
|
|
7854
|
-
output: process.stdout
|
|
7855
|
-
}) : null;
|
|
7856
|
-
const hintTimer = interactive ? setTimeout(() => {
|
|
7857
|
-
if (loopback.done || ticket.done || pasteDone) {
|
|
7858
|
-
return;
|
|
7859
|
-
}
|
|
7860
|
-
console.log("");
|
|
7861
|
-
console.log("Having trouble? If your browser shows a token, paste it here and press Enter:");
|
|
7862
|
-
}, PASTE_HINT_DELAY_MS) : null;
|
|
7863
|
-
rl?.on("line", async (line) => {
|
|
7864
|
-
if (loopback.done || ticket.done || pasteDone) {
|
|
7865
|
-
return;
|
|
7866
|
-
}
|
|
7867
|
-
const trimmed = line.trim();
|
|
7868
|
-
if (!trimmed) {
|
|
7869
|
-
return;
|
|
7870
|
-
}
|
|
7871
|
-
process.stdout.write("Verifying token... ");
|
|
7872
|
-
const who = await verifyToken(config2.serviceUrl, trimmed);
|
|
7873
|
-
if (who) {
|
|
7874
|
-
console.log("ok.");
|
|
7875
|
-
resolvePaste({ token: trimmed });
|
|
7876
|
-
} else {
|
|
7877
|
-
console.log("invalid token. Try again or complete the browser flow.");
|
|
7878
|
-
}
|
|
7879
|
-
});
|
|
7481
|
+
const abortController = new AbortController();
|
|
7880
7482
|
let loginTimer;
|
|
7881
7483
|
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
7882
|
-
loginTimer = setTimeout(() =>
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7484
|
+
loginTimer = setTimeout(() => {
|
|
7485
|
+
abortController.abort();
|
|
7486
|
+
reject(new Error("Authentication timed out after 10 minutes. Run login again."));
|
|
7487
|
+
}, LOGIN_TIMEOUT_MS);
|
|
7488
|
+
});
|
|
7489
|
+
const keepaliveTimer = setInterval(() => {
|
|
7490
|
+
process.stdout.write("");
|
|
7491
|
+
}, 3e4);
|
|
7492
|
+
try {
|
|
7493
|
+
const token = await Promise.race([
|
|
7494
|
+
pollLoginStatus(config2.serviceUrl, loginId, abortController.signal),
|
|
7495
|
+
timeoutPromise
|
|
7496
|
+
]);
|
|
7889
7497
|
if (loginTimer) {
|
|
7890
7498
|
clearTimeout(loginTimer);
|
|
7891
7499
|
}
|
|
7892
|
-
|
|
7893
|
-
ticket.close();
|
|
7894
|
-
rl?.close();
|
|
7895
|
-
}
|
|
7896
|
-
const racers = [];
|
|
7897
|
-
if (loopback.available) {
|
|
7898
|
-
racers.push(loopback.promise.then((v) => ({ token: v.token, wonBy: "loopback" })));
|
|
7899
|
-
}
|
|
7900
|
-
if (ticket.available) {
|
|
7901
|
-
racers.push(ticket.promise.then((v) => ({ token: v.token, wonBy: "ticket" })));
|
|
7902
|
-
}
|
|
7903
|
-
if (interactive) {
|
|
7904
|
-
racers.push(pastePromise.then((v) => ({ token: v.token, wonBy: "paste" })));
|
|
7905
|
-
}
|
|
7906
|
-
try {
|
|
7907
|
-
const { token, wonBy } = await Promise.race([...racers, timeoutPromise]);
|
|
7908
|
-
cleanup();
|
|
7500
|
+
clearInterval(keepaliveTimer);
|
|
7909
7501
|
saveCredentials(token);
|
|
7910
7502
|
const who = await verifyToken(config2.serviceUrl, token);
|
|
7911
7503
|
const greeting = who?.user.email ? `Logged in as ${who.user.email}.` : "Authentication successful.";
|
|
7912
7504
|
console.log(`
|
|
7913
7505
|
${greeting}`);
|
|
7914
|
-
console.log(
|
|
7506
|
+
console.log("Bitfab MCP tools are now active. (via studio)");
|
|
7915
7507
|
await reportHandoff(token, pluginVersion, platform2, {
|
|
7916
7508
|
flow: "auth.login",
|
|
7917
|
-
wonBy,
|
|
7918
|
-
loopbackAvailable:
|
|
7919
|
-
ticketAvailable:
|
|
7509
|
+
wonBy: "studio",
|
|
7510
|
+
loopbackAvailable: false,
|
|
7511
|
+
ticketAvailable: false
|
|
7920
7512
|
});
|
|
7921
7513
|
restoreFocus();
|
|
7922
7514
|
if (exitOnComplete) {
|
|
7923
7515
|
process.exit(0);
|
|
7924
7516
|
}
|
|
7925
7517
|
} catch (err) {
|
|
7926
|
-
|
|
7518
|
+
if (loginTimer) {
|
|
7519
|
+
clearTimeout(loginTimer);
|
|
7520
|
+
}
|
|
7521
|
+
clearInterval(keepaliveTimer);
|
|
7522
|
+
abortController.abort();
|
|
7927
7523
|
if (exitOnComplete) {
|
|
7928
7524
|
console.error(`
|
|
7929
7525
|
${err.message}`);
|
|
@@ -7953,6 +7549,9 @@ import fs7 from "fs";
|
|
|
7953
7549
|
import os8 from "os";
|
|
7954
7550
|
import path5 from "path";
|
|
7955
7551
|
|
|
7552
|
+
// ../bitfab-plugin-lib/dist/withStudioSession.js
|
|
7553
|
+
import crypto6 from "crypto";
|
|
7554
|
+
|
|
7956
7555
|
// ../bitfab-plugin-lib/dist/commands/openTracePlan.js
|
|
7957
7556
|
var OPEN_TRACE_PLAN_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
7958
7557
|
|
|
@@ -21753,21 +21352,12 @@ var inputFileSchema = external_exports.object({
|
|
|
21753
21352
|
verdicts: external_exports.array(external_exports.unknown()).min(1)
|
|
21754
21353
|
});
|
|
21755
21354
|
|
|
21756
|
-
// ../bitfab-plugin-lib/dist/commands/startDataset.js
|
|
21757
|
-
var START_DATASET_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
21758
|
-
|
|
21759
|
-
// ../bitfab-plugin-lib/dist/commands/startTemplatePreview.js
|
|
21760
|
-
import { randomUUID } from "crypto";
|
|
21761
|
-
|
|
21762
21355
|
// ../bitfab-plugin-lib/dist/activePreviewSession.js
|
|
21763
21356
|
import fs8 from "fs";
|
|
21764
21357
|
import os9 from "os";
|
|
21765
21358
|
import path6 from "path";
|
|
21766
21359
|
var FILE_PATH = path6.join(os9.homedir(), ".config", "bitfab", "active-preview-session.json");
|
|
21767
21360
|
|
|
21768
|
-
// ../bitfab-plugin-lib/dist/commands/startTemplatePreview.js
|
|
21769
|
-
var START_TEMPLATE_PREVIEW_TIMEOUT_MS = 8 * 60 * 60 * 1e3;
|
|
21770
|
-
|
|
21771
21361
|
// ../bitfab-plugin-lib/dist/updates.js
|
|
21772
21362
|
import fs9 from "fs";
|
|
21773
21363
|
import os10 from "os";
|
|
@@ -21785,7 +21375,7 @@ import fs10 from "fs";
|
|
|
21785
21375
|
import path8 from "path";
|
|
21786
21376
|
|
|
21787
21377
|
// ../bitfab-plugin-lib/dist/commands/waitForTrace.js
|
|
21788
|
-
var
|
|
21378
|
+
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
21789
21379
|
|
|
21790
21380
|
// ../bitfab-plugin-lib/dist/hooks/captureHook.js
|
|
21791
21381
|
import fs12 from "fs";
|
|
@@ -27212,34 +26802,51 @@ function runClaudeInstall() {
|
|
|
27212
26802
|
]);
|
|
27213
26803
|
if (installOut.includes("already")) {
|
|
27214
26804
|
s.stop("Plugin already installed");
|
|
26805
|
+
if (isPluginDisabled()) {
|
|
26806
|
+
runClaude(["plugin", "enable", PLUGIN_KEY]);
|
|
26807
|
+
p.log.step("Plugin enabled");
|
|
26808
|
+
}
|
|
27215
26809
|
} else {
|
|
27216
26810
|
s.stop("Plugin installed");
|
|
27217
26811
|
}
|
|
27218
26812
|
p.log.success("Bitfab plugin ready in Claude Code");
|
|
27219
26813
|
}
|
|
27220
|
-
function runClaudeSetup() {
|
|
26814
|
+
function runClaudeSetup(skipPermissions) {
|
|
27221
26815
|
p.log.info(`Launching ${SETUP_COMMAND}...
|
|
27222
26816
|
`);
|
|
27223
|
-
|
|
26817
|
+
const flags = skipPermissions ? ["--dangerously-skip-permissions"] : [];
|
|
26818
|
+
spawnSync("claude", [...flags, SETUP_COMMAND], {
|
|
26819
|
+
stdio: "inherit",
|
|
26820
|
+
...SHELL_OPTS
|
|
26821
|
+
});
|
|
27224
26822
|
}
|
|
27225
|
-
function runClaudeAssistant(args) {
|
|
26823
|
+
function runClaudeAssistant(args, skipPermissions) {
|
|
27226
26824
|
const cmd = [ASSISTANT_COMMAND, ...args].join(" ");
|
|
27227
26825
|
p.log.info(`Launching ${cmd}...
|
|
27228
26826
|
`);
|
|
27229
|
-
|
|
26827
|
+
const flags = skipPermissions ? ["--dangerously-skip-permissions"] : [];
|
|
26828
|
+
spawnSync("claude", [...flags, ASSISTANT_COMMAND, ...args], {
|
|
27230
26829
|
stdio: "inherit",
|
|
27231
26830
|
...SHELL_OPTS
|
|
27232
26831
|
});
|
|
27233
26832
|
}
|
|
27234
|
-
function runClaudeUpdate(args) {
|
|
26833
|
+
function runClaudeUpdate(args, skipPermissions) {
|
|
27235
26834
|
const cmd = [UPDATE_COMMAND, ...args].join(" ");
|
|
27236
26835
|
p.log.info(`Launching ${cmd}...
|
|
27237
26836
|
`);
|
|
27238
|
-
|
|
26837
|
+
const flags = skipPermissions ? ["--dangerously-skip-permissions"] : [];
|
|
26838
|
+
spawnSync("claude", [...flags, UPDATE_COMMAND, ...args], {
|
|
27239
26839
|
stdio: "inherit",
|
|
27240
26840
|
...SHELL_OPTS
|
|
27241
26841
|
});
|
|
27242
26842
|
}
|
|
26843
|
+
function isPluginDisabled() {
|
|
26844
|
+
const listOut = runClaude(["plugin", "list"]);
|
|
26845
|
+
const pattern = new RegExp(
|
|
26846
|
+
`${PLUGIN_KEY.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n.*\\n.*\\n.*disabled`
|
|
26847
|
+
);
|
|
26848
|
+
return pattern.test(listOut);
|
|
26849
|
+
}
|
|
27243
26850
|
function runClaude(args) {
|
|
27244
26851
|
const result = spawnSync("claude", [...args], {
|
|
27245
26852
|
stdio: "pipe",
|
|
@@ -27316,25 +26923,31 @@ function runCodexInstall() {
|
|
|
27316
26923
|
}
|
|
27317
26924
|
p2.log.success("Bitfab plugin ready in Codex");
|
|
27318
26925
|
}
|
|
27319
|
-
function runCodexSetup() {
|
|
26926
|
+
function runCodexSetup(skipPermissions) {
|
|
27320
26927
|
p2.log.info(`Launching ${SETUP_COMMAND2}...
|
|
27321
26928
|
`);
|
|
27322
|
-
|
|
26929
|
+
const flags = skipPermissions ? ["--full-auto"] : [];
|
|
26930
|
+
spawnSync2("codex", [...flags, SETUP_COMMAND2], {
|
|
26931
|
+
stdio: "inherit",
|
|
26932
|
+
...SHELL_OPTS2
|
|
26933
|
+
});
|
|
27323
26934
|
}
|
|
27324
|
-
function runCodexAssistant(args) {
|
|
26935
|
+
function runCodexAssistant(args, skipPermissions) {
|
|
27325
26936
|
const cmd = [ASSISTANT_COMMAND2, ...args].join(" ");
|
|
27326
26937
|
p2.log.info(`Launching ${cmd}...
|
|
27327
26938
|
`);
|
|
27328
|
-
|
|
26939
|
+
const flags = skipPermissions ? ["--full-auto"] : [];
|
|
26940
|
+
spawnSync2("codex", [...flags, ASSISTANT_COMMAND2, ...args], {
|
|
27329
26941
|
stdio: "inherit",
|
|
27330
26942
|
...SHELL_OPTS2
|
|
27331
26943
|
});
|
|
27332
26944
|
}
|
|
27333
|
-
function runCodexUpdate(args) {
|
|
26945
|
+
function runCodexUpdate(args, skipPermissions) {
|
|
27334
26946
|
const cmd = [UPDATE_COMMAND2, ...args].join(" ");
|
|
27335
26947
|
p2.log.info(`Launching ${cmd}...
|
|
27336
26948
|
`);
|
|
27337
|
-
|
|
26949
|
+
const flags = skipPermissions ? ["--full-auto"] : [];
|
|
26950
|
+
spawnSync2("codex", [...flags, UPDATE_COMMAND2, ...args], {
|
|
27338
26951
|
stdio: "inherit",
|
|
27339
26952
|
...SHELL_OPTS2
|
|
27340
26953
|
});
|
|
@@ -27408,14 +27021,23 @@ function runCursorInstall() {
|
|
|
27408
27021
|
});
|
|
27409
27022
|
child.unref();
|
|
27410
27023
|
}
|
|
27411
|
-
function runCursorSetup() {
|
|
27024
|
+
function runCursorSetup(skipPermissions) {
|
|
27025
|
+
if (skipPermissions) {
|
|
27026
|
+
p3.log.warn("--skip-permissions is not supported for Cursor");
|
|
27027
|
+
}
|
|
27412
27028
|
p3.log.info(`To complete setup, run ${SETUP_COMMAND3} in Cursor.`);
|
|
27413
27029
|
}
|
|
27414
|
-
function runCursorAssistant(args) {
|
|
27030
|
+
function runCursorAssistant(args, skipPermissions) {
|
|
27031
|
+
if (skipPermissions) {
|
|
27032
|
+
p3.log.warn("--skip-permissions is not supported for Cursor");
|
|
27033
|
+
}
|
|
27415
27034
|
const cmd = [ASSISTANT_COMMAND3, ...args].join(" ");
|
|
27416
27035
|
p3.log.info(`To start the assistant, run ${cmd} in Cursor.`);
|
|
27417
27036
|
}
|
|
27418
|
-
function runCursorUpdate(args) {
|
|
27037
|
+
function runCursorUpdate(args, skipPermissions) {
|
|
27038
|
+
if (skipPermissions) {
|
|
27039
|
+
p3.log.warn("--skip-permissions is not supported for Cursor");
|
|
27040
|
+
}
|
|
27419
27041
|
const cmd = [UPDATE_COMMAND3, ...args].join(" ");
|
|
27420
27042
|
p3.log.info(`To update, run ${cmd} in Cursor.`);
|
|
27421
27043
|
}
|
|
@@ -27536,6 +27158,20 @@ async function pickEditor(detected) {
|
|
|
27536
27158
|
}
|
|
27537
27159
|
return choice;
|
|
27538
27160
|
}
|
|
27161
|
+
async function resolveSkipPermissions(value) {
|
|
27162
|
+
if (value !== void 0) {
|
|
27163
|
+
return value;
|
|
27164
|
+
}
|
|
27165
|
+
const answer = await p4.confirm({
|
|
27166
|
+
message: "Skip permission prompts? (runs the agent autonomously)",
|
|
27167
|
+
initialValue: false
|
|
27168
|
+
});
|
|
27169
|
+
if (p4.isCancel(answer)) {
|
|
27170
|
+
p4.cancel("Cancelled.");
|
|
27171
|
+
process.exit(0);
|
|
27172
|
+
}
|
|
27173
|
+
return answer;
|
|
27174
|
+
}
|
|
27539
27175
|
async function resolveEditor({ editor }) {
|
|
27540
27176
|
const detected = detectInstalledEditors();
|
|
27541
27177
|
if (detected.length === 0) {
|
|
@@ -27570,15 +27206,18 @@ async function runInstall(opts) {
|
|
|
27570
27206
|
}
|
|
27571
27207
|
async function runSetup(opts) {
|
|
27572
27208
|
const chosen = await resolveEditor(opts);
|
|
27573
|
-
|
|
27209
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27210
|
+
SETUP_FN[chosen](skip);
|
|
27574
27211
|
}
|
|
27575
27212
|
async function runAssistant(opts, args) {
|
|
27576
27213
|
const chosen = await resolveEditor(opts);
|
|
27577
|
-
|
|
27214
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27215
|
+
ASSISTANT_FN[chosen](args, skip);
|
|
27578
27216
|
}
|
|
27579
27217
|
async function runUpdate2(opts, args) {
|
|
27580
27218
|
const chosen = await resolveEditor(opts);
|
|
27581
|
-
|
|
27219
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27220
|
+
UPDATE_FN[chosen](args, skip);
|
|
27582
27221
|
}
|
|
27583
27222
|
async function runInit(opts) {
|
|
27584
27223
|
p4.intro("bitfab");
|
|
@@ -27592,7 +27231,8 @@ async function runInit(opts) {
|
|
|
27592
27231
|
p4.log.step("Signing in to Bitfab");
|
|
27593
27232
|
await runLoginCommand({ exitOnComplete: false });
|
|
27594
27233
|
}
|
|
27595
|
-
|
|
27234
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27235
|
+
SETUP_FN[chosen](skip);
|
|
27596
27236
|
const detected = detectInstalledEditors();
|
|
27597
27237
|
const others = detected.filter((e) => e !== chosen);
|
|
27598
27238
|
if (others.length > 0) {
|
|
@@ -27640,20 +27280,22 @@ Commands:
|
|
|
27640
27280
|
update [--editor <name>] [args] Launch /bitfab:update in the editor
|
|
27641
27281
|
help Show this help
|
|
27642
27282
|
|
|
27643
|
-
|
|
27283
|
+
Options:
|
|
27284
|
+
--editor, -e <name> Target editor: claude, codex, cursor
|
|
27285
|
+
--skip-permissions Skip permission prompts (runs the agent autonomously)
|
|
27286
|
+
--no-skip-permissions Keep permission prompts (default, skips the interactive question)
|
|
27644
27287
|
|
|
27645
27288
|
Examples:
|
|
27646
|
-
bitfab init
|
|
27647
|
-
bitfab init --editor claude
|
|
27648
|
-
bitfab
|
|
27649
|
-
bitfab
|
|
27650
|
-
bitfab
|
|
27651
|
-
bitfab assistant investigate Investigate traces
|
|
27652
|
-
bitfab update plugin Update the Bitfab plugin
|
|
27289
|
+
bitfab init Full setup (detect editor, install, login, setup)
|
|
27290
|
+
bitfab init --editor claude Full setup for Claude Code
|
|
27291
|
+
bitfab assistant investigate Investigate traces
|
|
27292
|
+
bitfab setup --skip-permissions Setup without permission prompts
|
|
27293
|
+
bitfab assistant --skip-permissions Run assistant autonomously
|
|
27653
27294
|
`;
|
|
27654
27295
|
function parseArgs(argv) {
|
|
27655
27296
|
const [command, ...tail] = argv;
|
|
27656
27297
|
let editor;
|
|
27298
|
+
let skipPermissions;
|
|
27657
27299
|
const rest = [];
|
|
27658
27300
|
for (let i = 0; i < tail.length; i++) {
|
|
27659
27301
|
const arg = tail[i];
|
|
@@ -27666,24 +27308,30 @@ function parseArgs(argv) {
|
|
|
27666
27308
|
}
|
|
27667
27309
|
} else if (arg?.startsWith("--editor=")) {
|
|
27668
27310
|
editor = arg.slice("--editor=".length);
|
|
27311
|
+
} else if (arg === "--skip-permissions") {
|
|
27312
|
+
skipPermissions = true;
|
|
27313
|
+
} else if (arg === "--no-skip-permissions") {
|
|
27314
|
+
skipPermissions = false;
|
|
27669
27315
|
} else if (arg !== void 0) {
|
|
27670
27316
|
rest.push(arg);
|
|
27671
27317
|
}
|
|
27672
27318
|
}
|
|
27673
|
-
return { command, editor, rest };
|
|
27319
|
+
return { command, editor, skipPermissions, rest };
|
|
27674
27320
|
}
|
|
27675
27321
|
async function main() {
|
|
27676
|
-
const { command, editor, rest } = parseArgs(
|
|
27322
|
+
const { command, editor, skipPermissions, rest } = parseArgs(
|
|
27323
|
+
process.argv.slice(2)
|
|
27324
|
+
);
|
|
27677
27325
|
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
27678
27326
|
process.stdout.write(HELP_TEXT);
|
|
27679
27327
|
return;
|
|
27680
27328
|
}
|
|
27681
27329
|
if (command === "init") {
|
|
27682
|
-
await runInit({ editor });
|
|
27330
|
+
await runInit({ editor, skipPermissions });
|
|
27683
27331
|
return;
|
|
27684
27332
|
}
|
|
27685
27333
|
if (command === "plugin-install") {
|
|
27686
|
-
await runInstall({ editor });
|
|
27334
|
+
await runInstall({ editor, skipPermissions });
|
|
27687
27335
|
return;
|
|
27688
27336
|
}
|
|
27689
27337
|
if (command === "login") {
|
|
@@ -27695,15 +27343,15 @@ async function main() {
|
|
|
27695
27343
|
return;
|
|
27696
27344
|
}
|
|
27697
27345
|
if (command === "setup") {
|
|
27698
|
-
await runSetup({ editor });
|
|
27346
|
+
await runSetup({ editor, skipPermissions });
|
|
27699
27347
|
return;
|
|
27700
27348
|
}
|
|
27701
27349
|
if (command === "assistant") {
|
|
27702
|
-
await runAssistant({ editor }, rest);
|
|
27350
|
+
await runAssistant({ editor, skipPermissions }, rest);
|
|
27703
27351
|
return;
|
|
27704
27352
|
}
|
|
27705
27353
|
if (command === "update") {
|
|
27706
|
-
await runUpdate2({ editor }, rest);
|
|
27354
|
+
await runUpdate2({ editor, skipPermissions }, rest);
|
|
27707
27355
|
return;
|
|
27708
27356
|
}
|
|
27709
27357
|
process.stderr.write(`Unknown command: ${command}
|
|
@@ -27716,3 +27364,6 @@ main().catch((err) => {
|
|
|
27716
27364
|
cancel2(message);
|
|
27717
27365
|
process.exit(1);
|
|
27718
27366
|
});
|
|
27367
|
+
export {
|
|
27368
|
+
parseArgs
|
|
27369
|
+
};
|