bitfab-cli 0.2.12 → 0.2.14

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.
Files changed (2) hide show
  1. package/dist/index.js +92 -72
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7652,9 +7652,6 @@ async function createStudioSession({ serviceUrl, apiKey, sessionId, initialPath
7652
7652
  return { sessionId, serviceUrl };
7653
7653
  }
7654
7654
 
7655
- // ../bitfab-plugin-lib/dist/commands/login.js
7656
- import crypto5 from "crypto";
7657
-
7658
7655
  // ../bitfab-plugin-lib/dist/analytics.js
7659
7656
  async function reportHandoff(apiKey, pluginVersion, platform2, body) {
7660
7657
  const config2 = getConfig();
@@ -7676,6 +7673,9 @@ async function reportHandoff(apiKey, pluginVersion, platform2, body) {
7676
7673
  }
7677
7674
  }
7678
7675
 
7676
+ // ../bitfab-plugin-lib/dist/commands/openStudioTo.js
7677
+ import crypto4 from "crypto";
7678
+
7679
7679
  // ../bitfab-plugin-lib/dist/frontmostApp.js
7680
7680
  import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
7681
7681
  import os8 from "os";
@@ -7821,14 +7821,42 @@ function recordFocus() {
7821
7821
  return () => focusApp(frontmost);
7822
7822
  }
7823
7823
 
7824
- // ../bitfab-plugin-lib/dist/commands/openStudioTo.js
7825
- import crypto4 from "crypto";
7826
-
7827
7824
  // ../bitfab-plugin-lib/dist/commands/loginForSession.js
7828
7825
  var LOGIN_TIMEOUT_MS = 10 * 60 * 1e3;
7826
+ var SESSION_READY_TIMEOUT_MS = 3e4;
7827
+ var SESSION_READY_POLL_MS = 500;
7828
+ async function waitForSessionReady(opts) {
7829
+ const deadline = Date.now() + SESSION_READY_TIMEOUT_MS;
7830
+ let since = null;
7831
+ while (Date.now() < deadline) {
7832
+ try {
7833
+ const url2 = new URL(`${opts.serviceUrl}/api/studio/events`);
7834
+ url2.searchParams.set("session", opts.sessionId);
7835
+ if (since) {
7836
+ url2.searchParams.set("since", since);
7837
+ }
7838
+ const res = await fetch(url2.toString(), {
7839
+ headers: { Authorization: `Bearer ${opts.apiKey}` }
7840
+ });
7841
+ if (res.ok) {
7842
+ const body = await res.json();
7843
+ for (const event of body.events) {
7844
+ since = event.id;
7845
+ if (event.type === "studio:session-started") {
7846
+ return;
7847
+ }
7848
+ }
7849
+ }
7850
+ } catch {
7851
+ }
7852
+ await new Promise((resolve) => setTimeout(resolve, SESSION_READY_POLL_MS));
7853
+ }
7854
+ console.error("Warning: Studio session did not confirm readiness within 30s. Proceeding anyway.");
7855
+ }
7829
7856
 
7830
7857
  // ../bitfab-plugin-lib/dist/commands/openStudioTo.js
7831
7858
  var SESSION_CLOSE_GRACE_PERIOD_MS = 1e4;
7859
+ var LOGIN_TIMEOUT_MS2 = 10 * 60 * 1e3;
7832
7860
  var StudioNavigationError = class extends Error {
7833
7861
  reason;
7834
7862
  blockedReason;
@@ -7847,9 +7875,45 @@ async function openStudioTo(path14, opts) {
7847
7875
  };
7848
7876
  const restoreFocus = recordFocus();
7849
7877
  if (!opts.apiKey) {
7850
- const separator = path14.includes("?") ? "&" : "?";
7851
- const url2 = `${opts.serviceUrl}${path14}${separator}session=${encodeURIComponent(sessionId)}`;
7852
- openChromelessWindow(url2);
7878
+ const targetWithSession = `${path14}${path14.includes("?") ? "&" : "?"}session=${encodeURIComponent(sessionId)}&pluginLogin=true`;
7879
+ const signInUrl = `${opts.serviceUrl}/studio/sign-in?redirect_url=${encodeURIComponent(targetWithSession)}`;
7880
+ openChromelessWindow(signInUrl);
7881
+ opts.onLoginRequired?.(sessionId);
7882
+ const abortController = new AbortController();
7883
+ const timer = setTimeout(() => abortController.abort(), LOGIN_TIMEOUT_MS2);
7884
+ const keepalive = setInterval(() => process.stderr.write(""), 3e4);
7885
+ let apiKey;
7886
+ try {
7887
+ apiKey = await pollLoginEvents({
7888
+ serviceUrl: opts.serviceUrl,
7889
+ sessionId,
7890
+ abortSignal: abortController.signal
7891
+ });
7892
+ } catch (err) {
7893
+ clearTimeout(timer);
7894
+ clearInterval(keepalive);
7895
+ throw err;
7896
+ }
7897
+ clearTimeout(timer);
7898
+ clearInterval(keepalive);
7899
+ saveCredentials(apiKey);
7900
+ opts.onAuthenticated?.(sessionId);
7901
+ if (opts.onEvent) {
7902
+ await waitForSessionReady({
7903
+ serviceUrl: opts.serviceUrl,
7904
+ apiKey,
7905
+ sessionId
7906
+ });
7907
+ writeActiveStudioSession({ sessionId, serviceUrl: opts.serviceUrl });
7908
+ const poller2 = startEventPoller(opts.serviceUrl, apiKey, sessionId, opts.onEvent, restoreFocus);
7909
+ return {
7910
+ sessionId,
7911
+ serviceUrl: opts.serviceUrl,
7912
+ opened: true,
7913
+ ...poller2
7914
+ };
7915
+ }
7916
+ restoreFocus();
7853
7917
  return {
7854
7918
  sessionId,
7855
7919
  serviceUrl: opts.serviceUrl,
@@ -7965,7 +8029,6 @@ function startEventPoller(serviceUrl, apiKey, sessionId, onEvent, restoreFocus)
7965
8029
  }
7966
8030
 
7967
8031
  // ../bitfab-plugin-lib/dist/commands/login.js
7968
- var LOGIN_TIMEOUT_MS2 = 10 * 60 * 1e3;
7969
8032
  async function verifyToken(serviceUrl, token) {
7970
8033
  try {
7971
8034
  const res = await fetch(`${serviceUrl}/api/plugin/whoami`, {
@@ -7982,75 +8045,32 @@ async function verifyToken(serviceUrl, token) {
7982
8045
  async function runLogin(platform2, pluginVersion, options) {
7983
8046
  const exitOnComplete = options?.exitOnComplete ?? true;
7984
8047
  const config2 = getConfig();
7985
- const restoreFocus = recordFocus();
7986
- const sessionId = crypto5.randomUUID();
7987
- const redirectPath = `/studio/close?pluginLogin=true&session=${sessionId}&autoClose=true&message=${encodeURIComponent("Login complete")}`;
7988
- const signInPath = `/studio/sign-in?redirect_url=${encodeURIComponent(redirectPath)}`;
7989
8048
  console.log("\nOpening Studio to sign in...");
7990
8049
  console.log("(If the browser didn't open, visit the Studio URL manually.)");
8050
+ const closePath = `/studio/close?pluginLogin=true&autoClose=true&message=${encodeURIComponent("Login complete")}`;
7991
8051
  try {
7992
- await openStudioTo(signInPath, {
7993
- apiKey: hasCredentials() ? config2.apiKey : null,
7994
- serviceUrl: config2.serviceUrl,
7995
- sessionId
8052
+ const result = await openStudioTo(closePath, {
8053
+ serviceUrl: config2.serviceUrl
7996
8054
  });
7997
- } catch (err) {
7998
- if (err instanceof StudioNavigationError) {
7999
- await openStudioTo(signInPath, {
8000
- apiKey: null,
8001
- serviceUrl: config2.serviceUrl,
8002
- sessionId
8055
+ result.abort();
8056
+ const apiKey = getConfig().apiKey;
8057
+ if (apiKey) {
8058
+ await reportHandoff(apiKey, pluginVersion, platform2, {
8059
+ flow: "auth.login",
8060
+ wonBy: "studio",
8061
+ loopbackAvailable: false,
8062
+ ticketAvailable: false
8003
8063
  });
8004
- } else {
8005
- throw err;
8006
- }
8007
- }
8008
- const abortController = new AbortController();
8009
- let loginTimer;
8010
- const timeoutPromise = new Promise((_resolve, reject) => {
8011
- loginTimer = setTimeout(() => {
8012
- abortController.abort();
8013
- reject(new Error("Authentication timed out after 10 minutes. Run login again."));
8014
- }, LOGIN_TIMEOUT_MS2);
8015
- });
8016
- const keepaliveTimer = setInterval(() => {
8017
- process.stdout.write("");
8018
- }, 3e4);
8019
- try {
8020
- const token = await Promise.race([
8021
- pollLoginEvents({
8022
- serviceUrl: config2.serviceUrl,
8023
- sessionId,
8024
- abortSignal: abortController.signal
8025
- }),
8026
- timeoutPromise
8027
- ]);
8028
- if (loginTimer) {
8029
- clearTimeout(loginTimer);
8030
- }
8031
- clearInterval(keepaliveTimer);
8032
- saveCredentials(token);
8033
- await reportHandoff(token, pluginVersion, platform2, {
8034
- flow: "auth.login",
8035
- wonBy: "studio",
8036
- loopbackAvailable: false,
8037
- ticketAvailable: false
8038
- });
8039
- restoreFocus();
8040
- const who = await verifyToken(config2.serviceUrl, token);
8041
- const greeting = who?.user.email ? `Logged in as ${who.user.email}.` : "Authentication successful.";
8042
- console.log(`
8064
+ const who = await verifyToken(config2.serviceUrl, apiKey);
8065
+ const greeting = who?.user.email ? `Logged in as ${who.user.email}.` : "Authentication successful.";
8066
+ console.log(`
8043
8067
  ${greeting}`);
8044
- console.log("Bitfab MCP tools are now active. (via studio)");
8068
+ console.log("Bitfab MCP tools are now active. (via studio)");
8069
+ }
8045
8070
  if (exitOnComplete) {
8046
8071
  process.exit(0);
8047
8072
  }
8048
8073
  } catch (err) {
8049
- if (loginTimer) {
8050
- clearTimeout(loginTimer);
8051
- }
8052
- clearInterval(keepaliveTimer);
8053
- abortController.abort();
8054
8074
  if (exitOnComplete) {
8055
8075
  console.error(`
8056
8076
  ${err.message}`);
@@ -8072,7 +8092,7 @@ function runLogout() {
8072
8092
  }
8073
8093
 
8074
8094
  // ../bitfab-plugin-lib/dist/commands/openTracePlan.js
8075
- import crypto6 from "crypto";
8095
+ import crypto5 from "crypto";
8076
8096
  var OPEN_TRACE_PLAN_TIMEOUT_MS = 30 * 60 * 1e3;
8077
8097
 
8078
8098
  // ../bitfab-plugin-lib/dist/commands/persistReplayLabels.js
@@ -21873,10 +21893,10 @@ var inputFileSchema = external_exports.object({
21873
21893
  });
21874
21894
 
21875
21895
  // ../bitfab-plugin-lib/dist/commands/startDataset.js
21876
- import crypto7 from "crypto";
21896
+ import crypto6 from "crypto";
21877
21897
 
21878
21898
  // ../bitfab-plugin-lib/dist/commands/startTemplatePreview.js
21879
- import crypto8 from "crypto";
21899
+ import crypto7 from "crypto";
21880
21900
 
21881
21901
  // ../bitfab-plugin-lib/dist/activePreviewSession.js
21882
21902
  import fs8 from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitfab-cli",
3
- "version": "0.2.12",
3
+ "version": "0.2.14",
4
4
  "description": "Install and configure the Bitfab plugin in Claude Code, Codex, or Cursor.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",