bitfab-cli 0.2.5 → 0.2.9
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 +427 -757
- 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"],
|
|
@@ -7006,617 +7206,77 @@ function getWorkArea() {
|
|
|
7006
7206
|
return null;
|
|
7007
7207
|
}
|
|
7008
7208
|
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;
|
|
7471
|
-
}
|
|
7472
|
-
dir = parent;
|
|
7473
|
-
}
|
|
7474
|
-
}
|
|
7475
|
-
function getProjectConfigData() {
|
|
7476
|
-
const filePath = findProjectConfigPath();
|
|
7477
|
-
if (!filePath) {
|
|
7478
|
-
return null;
|
|
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,6 +26802,10 @@ 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
|
}
|
|
@@ -27237,14 +26831,36 @@ function runClaudeAssistant(args, skipPermissions) {
|
|
|
27237
26831
|
});
|
|
27238
26832
|
}
|
|
27239
26833
|
function runClaudeUpdate(args, skipPermissions) {
|
|
27240
|
-
const
|
|
27241
|
-
|
|
26834
|
+
const mode = args[0] === "plugin" || args[0] === "sdk" ? args[0] : "all";
|
|
26835
|
+
if (mode === "plugin" || mode === "all") {
|
|
26836
|
+
const s = p.spinner();
|
|
26837
|
+
s.start("Refreshing bitfab marketplace");
|
|
26838
|
+
runClaude(["plugin", "marketplace", "update", MARKETPLACE]);
|
|
26839
|
+
s.stop("Marketplace refreshed");
|
|
26840
|
+
s.start("Updating bitfab plugin");
|
|
26841
|
+
const out = runClaude(["plugin", "update", PLUGIN_KEY, "--scope", "user"]);
|
|
26842
|
+
if (out.includes("already") || out.includes("up to date")) {
|
|
26843
|
+
s.stop("Plugin already up to date");
|
|
26844
|
+
} else {
|
|
26845
|
+
s.stop("Plugin updated");
|
|
26846
|
+
}
|
|
26847
|
+
}
|
|
26848
|
+
if (mode === "sdk" || mode === "all") {
|
|
26849
|
+
p.log.info(`Launching ${UPDATE_COMMAND} sdk...
|
|
27242
26850
|
`);
|
|
27243
|
-
|
|
27244
|
-
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
|
|
26851
|
+
const flags = skipPermissions ? ["--dangerously-skip-permissions"] : [];
|
|
26852
|
+
spawnSync("claude", [...flags, UPDATE_COMMAND, "sdk"], {
|
|
26853
|
+
stdio: "inherit",
|
|
26854
|
+
...SHELL_OPTS
|
|
26855
|
+
});
|
|
26856
|
+
}
|
|
26857
|
+
}
|
|
26858
|
+
function isPluginDisabled() {
|
|
26859
|
+
const listOut = runClaude(["plugin", "list"]);
|
|
26860
|
+
const pattern = new RegExp(
|
|
26861
|
+
`${PLUGIN_KEY.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n.*\\n.*\\n.*disabled`
|
|
26862
|
+
);
|
|
26863
|
+
return pattern.test(listOut);
|
|
27248
26864
|
}
|
|
27249
26865
|
function runClaude(args) {
|
|
27250
26866
|
const result = spawnSync("claude", [...args], {
|
|
@@ -27342,14 +26958,37 @@ function runCodexAssistant(args, skipPermissions) {
|
|
|
27342
26958
|
});
|
|
27343
26959
|
}
|
|
27344
26960
|
function runCodexUpdate(args, skipPermissions) {
|
|
27345
|
-
const
|
|
27346
|
-
|
|
26961
|
+
const mode = args[0] === "plugin" || args[0] === "sdk" ? args[0] : "all";
|
|
26962
|
+
if (mode === "plugin" || mode === "all") {
|
|
26963
|
+
const s = p2.spinner();
|
|
26964
|
+
s.start("Upgrading bitfab marketplace plugin");
|
|
26965
|
+
const result = spawnSync2(
|
|
26966
|
+
"codex",
|
|
26967
|
+
["plugin", "marketplace", "upgrade", "bitfab"],
|
|
26968
|
+
{ stdio: "pipe", ...SHELL_OPTS2 }
|
|
26969
|
+
);
|
|
26970
|
+
if (result.status !== 0) {
|
|
26971
|
+
s.stop("Marketplace upgrade failed");
|
|
26972
|
+
throw new Error(
|
|
26973
|
+
`codex plugin marketplace upgrade failed${result.status === null ? "" : ` with status ${result.status}`}`
|
|
26974
|
+
);
|
|
26975
|
+
}
|
|
26976
|
+
const out = (result.stdout?.toString() ?? "") + (result.stderr?.toString() ?? "");
|
|
26977
|
+
if (out.includes("already") || out.includes("up to date")) {
|
|
26978
|
+
s.stop("Plugin already up to date");
|
|
26979
|
+
} else {
|
|
26980
|
+
s.stop("Plugin updated");
|
|
26981
|
+
}
|
|
26982
|
+
}
|
|
26983
|
+
if (mode === "sdk" || mode === "all") {
|
|
26984
|
+
p2.log.info(`Launching ${UPDATE_COMMAND2} sdk...
|
|
27347
26985
|
`);
|
|
27348
|
-
|
|
27349
|
-
|
|
27350
|
-
|
|
27351
|
-
|
|
27352
|
-
|
|
26986
|
+
const flags = skipPermissions ? ["--full-auto"] : [];
|
|
26987
|
+
spawnSync2("codex", [...flags, UPDATE_COMMAND2, "sdk"], {
|
|
26988
|
+
stdio: "inherit",
|
|
26989
|
+
...SHELL_OPTS2
|
|
26990
|
+
});
|
|
26991
|
+
}
|
|
27353
26992
|
}
|
|
27354
26993
|
function enableCodexPlugin(configPath) {
|
|
27355
26994
|
let content = "";
|
|
@@ -27437,8 +27076,15 @@ function runCursorUpdate(args, skipPermissions) {
|
|
|
27437
27076
|
if (skipPermissions) {
|
|
27438
27077
|
p3.log.warn("--skip-permissions is not supported for Cursor");
|
|
27439
27078
|
}
|
|
27440
|
-
const
|
|
27441
|
-
|
|
27079
|
+
const mode = args[0] === "plugin" || args[0] === "sdk" ? args[0] : "all";
|
|
27080
|
+
const lines = [];
|
|
27081
|
+
if (mode === "plugin" || mode === "all") {
|
|
27082
|
+
lines.push(`Run ${UPDATE_COMMAND3} plugin (updates the plugin)`);
|
|
27083
|
+
}
|
|
27084
|
+
if (mode === "sdk" || mode === "all") {
|
|
27085
|
+
lines.push(`Run ${UPDATE_COMMAND3} sdk (updates installed SDKs)`);
|
|
27086
|
+
}
|
|
27087
|
+
p3.note(lines.join("\n"), "Update Bitfab in Cursor");
|
|
27442
27088
|
}
|
|
27443
27089
|
function copyToClipboard(text) {
|
|
27444
27090
|
const cmd = clipboardCommand();
|
|
@@ -27557,6 +27203,20 @@ async function pickEditor(detected) {
|
|
|
27557
27203
|
}
|
|
27558
27204
|
return choice;
|
|
27559
27205
|
}
|
|
27206
|
+
async function resolveSkipPermissions(value) {
|
|
27207
|
+
if (value !== void 0) {
|
|
27208
|
+
return value;
|
|
27209
|
+
}
|
|
27210
|
+
const answer = await p4.confirm({
|
|
27211
|
+
message: "Skip permission prompts? (runs the agent autonomously)",
|
|
27212
|
+
initialValue: false
|
|
27213
|
+
});
|
|
27214
|
+
if (p4.isCancel(answer)) {
|
|
27215
|
+
p4.cancel("Cancelled.");
|
|
27216
|
+
process.exit(0);
|
|
27217
|
+
}
|
|
27218
|
+
return answer;
|
|
27219
|
+
}
|
|
27560
27220
|
async function resolveEditor({ editor }) {
|
|
27561
27221
|
const detected = detectInstalledEditors();
|
|
27562
27222
|
if (detected.length === 0) {
|
|
@@ -27591,15 +27251,18 @@ async function runInstall(opts) {
|
|
|
27591
27251
|
}
|
|
27592
27252
|
async function runSetup(opts) {
|
|
27593
27253
|
const chosen = await resolveEditor(opts);
|
|
27594
|
-
|
|
27254
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27255
|
+
SETUP_FN[chosen](skip);
|
|
27595
27256
|
}
|
|
27596
27257
|
async function runAssistant(opts, args) {
|
|
27597
27258
|
const chosen = await resolveEditor(opts);
|
|
27598
|
-
|
|
27259
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27260
|
+
ASSISTANT_FN[chosen](args, skip);
|
|
27599
27261
|
}
|
|
27600
27262
|
async function runUpdate2(opts, args) {
|
|
27601
27263
|
const chosen = await resolveEditor(opts);
|
|
27602
|
-
|
|
27264
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27265
|
+
UPDATE_FN[chosen](args, skip);
|
|
27603
27266
|
}
|
|
27604
27267
|
async function runInit(opts) {
|
|
27605
27268
|
p4.intro("bitfab");
|
|
@@ -27613,7 +27276,8 @@ async function runInit(opts) {
|
|
|
27613
27276
|
p4.log.step("Signing in to Bitfab");
|
|
27614
27277
|
await runLoginCommand({ exitOnComplete: false });
|
|
27615
27278
|
}
|
|
27616
|
-
|
|
27279
|
+
const skip = await resolveSkipPermissions(opts.skipPermissions);
|
|
27280
|
+
SETUP_FN[chosen](skip);
|
|
27617
27281
|
const detected = detectInstalledEditors();
|
|
27618
27282
|
const others = detected.filter((e) => e !== chosen);
|
|
27619
27283
|
if (others.length > 0) {
|
|
@@ -27658,12 +27322,13 @@ Commands:
|
|
|
27658
27322
|
logout Remove stored credentials
|
|
27659
27323
|
setup [--editor <name>] Launch /bitfab:setup in the editor
|
|
27660
27324
|
assistant [--editor <name>] [args] Launch /bitfab:assistant in the editor
|
|
27661
|
-
update [--editor <name>] [
|
|
27325
|
+
update [--editor <name>] [mode] Update plugin, then launch SDK update (mode: all|plugin|sdk)
|
|
27662
27326
|
help Show this help
|
|
27663
27327
|
|
|
27664
27328
|
Options:
|
|
27665
27329
|
--editor, -e <name> Target editor: claude, codex, cursor
|
|
27666
|
-
--skip-permissions Skip permission prompts
|
|
27330
|
+
--skip-permissions Skip permission prompts (runs the agent autonomously)
|
|
27331
|
+
--no-skip-permissions Keep permission prompts (default, skips the interactive question)
|
|
27667
27332
|
|
|
27668
27333
|
Examples:
|
|
27669
27334
|
bitfab init Full setup (detect editor, install, login, setup)
|
|
@@ -27675,7 +27340,7 @@ Examples:
|
|
|
27675
27340
|
function parseArgs(argv) {
|
|
27676
27341
|
const [command, ...tail] = argv;
|
|
27677
27342
|
let editor;
|
|
27678
|
-
let skipPermissions
|
|
27343
|
+
let skipPermissions;
|
|
27679
27344
|
const rest = [];
|
|
27680
27345
|
for (let i = 0; i < tail.length; i++) {
|
|
27681
27346
|
const arg = tail[i];
|
|
@@ -27690,6 +27355,8 @@ function parseArgs(argv) {
|
|
|
27690
27355
|
editor = arg.slice("--editor=".length);
|
|
27691
27356
|
} else if (arg === "--skip-permissions") {
|
|
27692
27357
|
skipPermissions = true;
|
|
27358
|
+
} else if (arg === "--no-skip-permissions") {
|
|
27359
|
+
skipPermissions = false;
|
|
27693
27360
|
} else if (arg !== void 0) {
|
|
27694
27361
|
rest.push(arg);
|
|
27695
27362
|
}
|
|
@@ -27742,3 +27409,6 @@ main().catch((err) => {
|
|
|
27742
27409
|
cancel2(message);
|
|
27743
27410
|
process.exit(1);
|
|
27744
27411
|
});
|
|
27412
|
+
export {
|
|
27413
|
+
parseArgs
|
|
27414
|
+
};
|