@boole-digital/cli 0.2.1 → 0.2.3

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 +39 -22
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -16,7 +16,8 @@ import {
16
16
  chmodSync,
17
17
  rmSync
18
18
  } from "node:fs";
19
- var API_BASE = (process.env.BOOLE_API_BASE || "https://trade.boole.markets").replace(/\/+$/, "");
19
+ var API_BASE = (process.env.BOOLE_API_BASE || "https://api.cest-finyx.com").replace(/\/+$/, "");
20
+ var WEB_BASE = (process.env.BOOLE_WEB_BASE || process.env.BOOLE_API_BASE || "https://trade.boole.markets").replace(/\/+$/, "");
20
21
  var CONFIG_DIR = process.env.BOOLE_HOME || join(homedir(), ".boole");
21
22
  var CRED_PATH = join(CONFIG_DIR, "credentials.json");
22
23
  var SESSION_PATH = join(CONFIG_DIR, "session.env");
@@ -145,12 +146,12 @@ function decodePayload(code) {
145
146
  };
146
147
  }
147
148
  function successHtml(email, dashboardUrl) {
148
- const who = email ? `<p>Signed in as <b style="color:#eaeaea">${email.replace(/[<>&]/g, "")}</b></p>` : "";
149
+ const who = email ? `<p class="who">Signed in as: <b>${email.replace(/[<>&]/g, "")}</b></p>` : "";
149
150
  const url = dashboardUrl.replace(/"/g, "");
150
151
  return `<!doctype html><meta charset=utf-8><title>Boole</title>
151
- <style>body{font:16px -apple-system,system-ui,sans-serif;background:#0b0b0b;color:#eaeaea;display:grid;place-items:center;height:100vh;margin:0}div{text-align:center}h1{font-size:22px}p{color:#9a9a9a;margin:6px 0}.btn{display:inline-block;margin-top:18px;padding:10px 20px;border-radius:8px;background:#6d5efc;color:#fff;text-decoration:none;font-weight:600}.btn:hover{background:#5a4ef0}</style>
152
- <div><h1>\u2713 Signed in to Boole</h1>${who}<p style="color:#34d399;font-weight:600">Your CLI is authenticated.</p><p>You can close this tab now and return to your terminal.</p>
153
- <a class="btn" href="${url}">See dashboard \u2192</a></div>`;
152
+ <style>body{font:16px -apple-system,system-ui,sans-serif;background:#0b0b0b;color:#eaeaea;display:grid;place-items:center;height:100vh;margin:0}div{text-align:center}h1{font-size:22px;font-weight:600;margin:0 0 14px}p{margin:6px 0;color:#9a9a9a}.who b{color:#eaeaea;font-weight:600}.tag{color:#7a7a7a;margin-top:16px}.btn{display:inline-block;margin-top:22px;padding:10px 22px;border-radius:8px;background:#1c1c22;color:#c8c8d0;text-decoration:none;font-weight:500;border:1px solid #2e2e38}.btn:hover{background:#26262e;color:#eaeaea}</style>
153
+ <div><h1>Authenticated to Boole</h1>${who}<p class="tag">Go build something great</p>
154
+ <a class="btn" href="${url}">Continue to Boole</a></div>`;
154
155
  }
155
156
  function emailFromCode(code) {
156
157
  try {
@@ -160,7 +161,7 @@ function emailFromCode(code) {
160
161
  }
161
162
  }
162
163
  async function loginPaste() {
163
- const url = `${API_BASE}/cli-auth?paste=1`;
164
+ const url = `${WEB_BASE}/cli-auth?paste=1`;
164
165
  info("Opening the Boole login page\u2026");
165
166
  log(` ${c.dim("If it does not open, visit:")} ${c.cyan(url)}`);
166
167
  openBrowser(url);
@@ -190,7 +191,7 @@ async function loginLoopback() {
190
191
  return;
191
192
  }
192
193
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
193
- res.end(successHtml(emailFromCode(code), API_BASE));
194
+ res.end(successHtml(emailFromCode(code), WEB_BASE));
194
195
  queueMicrotask(() => resolveCode(code));
195
196
  });
196
197
  const port = await new Promise((resolve2) => {
@@ -199,7 +200,7 @@ async function loginLoopback() {
199
200
  resolve2(typeof addr === "object" && addr ? addr.port : 0);
200
201
  });
201
202
  });
202
- const url = `${API_BASE}/cli-auth?port=${port}`;
203
+ const url = `${WEB_BASE}/cli-auth?port=${port}`;
203
204
  info("Opening the Boole login page in your browser\u2026");
204
205
  log(` ${c.dim("If it does not open, visit:")} ${c.cyan(url)}`);
205
206
  openBrowser(url);
@@ -283,14 +284,27 @@ var BooleApi = class {
283
284
  async request(path, init2 = {}) {
284
285
  await this.ensureFresh();
285
286
  if (!this.creds) throw new AuthError("Not logged in. Run `boole login`.");
286
- const doFetch = () => fetch(`${API_BASE}${path}`, {
287
- ...init2,
288
- headers: {
289
- "Content-Type": "application/json",
290
- ...init2.headers || {},
291
- Authorization: `Bearer ${this.creds.access_token}`
287
+ const TIMEOUT_MS = Number(process.env.BOOLE_TIMEOUT_MS) || 12e3;
288
+ const doFetch = async () => {
289
+ const ac = new AbortController();
290
+ const t = setTimeout(() => ac.abort(), TIMEOUT_MS);
291
+ try {
292
+ return await fetch(`${API_BASE}${path}`, {
293
+ ...init2,
294
+ signal: ac.signal,
295
+ headers: {
296
+ "Content-Type": "application/json",
297
+ ...init2.headers || {},
298
+ Authorization: `Bearer ${this.creds.access_token}`
299
+ }
300
+ });
301
+ } catch (e) {
302
+ if (e?.name === "AbortError") throw new Error(`${path}: timed out after ${TIMEOUT_MS / 1e3}s (network or box waking up)`);
303
+ throw e;
304
+ } finally {
305
+ clearTimeout(t);
292
306
  }
293
- });
307
+ };
294
308
  let res = await doFetch();
295
309
  if (res.status === 401) {
296
310
  this.creds.expires_at = 0;
@@ -368,7 +382,7 @@ function onboardingNotice() {
368
382
  warn("No trading computer yet \u2014 and you can\u2019t deploy your first one from the CLI.");
369
383
  log(" Finish onboarding in the Boole app first (this is required):");
370
384
  log(` 1. Create your account 2. Agree to the terms 3. Set up billing`);
371
- log(` ${c.cyan(API_BASE)}`);
385
+ log(` ${c.cyan(WEB_BASE)}`);
372
386
  log(` Deploy your first trading computer there, then come back and run ${c.cyan("boole connect")}.`);
373
387
  log("");
374
388
  }
@@ -389,7 +403,7 @@ function orient() {
389
403
  log(`${c.bold("Do this next:")} ${c.cyan("boole login")}`);
390
404
  } else if (!sess) {
391
405
  log(`${c.bold("You are:")} logged in as ${c.bold(creds.user.email || creds.user.id)}, ${c.yellow("no box connected")}.`);
392
- log(`${c.bold("Do this next:")} ${c.cyan("boole connect")} ${c.dim(`# no trading computer yet? finish onboarding at ${API_BASE}`)}`);
406
+ log(`${c.bold("Do this next:")} ${c.cyan("boole connect")} ${c.dim(`# no trading computer yet? finish onboarding at ${WEB_BASE}`)}`);
393
407
  } else {
394
408
  log(`${c.bold("You are:")} connected to ${c.bold(sess.agent || sess.ip)} ${c.green("\u2014 ready")}.`);
395
409
  log(c.bold("Do this next:"));
@@ -445,7 +459,8 @@ function pickAgentId(droplets) {
445
459
  if (ready.length === 1) return { id: ready[0].id, name: ready[0].name };
446
460
  return null;
447
461
  }
448
- async function summary() {
462
+ async function summary(opts = {}) {
463
+ const snapshot = opts.snapshot !== false;
449
464
  const creds = loadCredentials();
450
465
  if (!creds) {
451
466
  warn("Not logged in. Run `boole login`.");
@@ -483,7 +498,7 @@ async function summary() {
483
498
  log(c.bold(`Trading computers (${droplets.length})`));
484
499
  printAgents(droplets);
485
500
  const pick = pickAgentId(droplets);
486
- if (pick) {
501
+ if (pick && snapshot) {
487
502
  log("");
488
503
  log(c.bold(`Snapshot \u2014 ${pick.name}`));
489
504
  try {
@@ -493,6 +508,8 @@ async function summary() {
493
508
  } catch {
494
509
  warn("trading computer unreachable (tunnel may be waking up \u2014 retry in a moment)");
495
510
  }
511
+ } else if (pick) {
512
+ log(c.dim(` Run ${c.cyan("boole status")} for balances + live snapshot.`));
496
513
  }
497
514
  operatingBrief();
498
515
  }
@@ -711,7 +728,7 @@ function init(opts = {}) {
711
728
  }
712
729
 
713
730
  // src/index.ts
714
- var VERSION = "0.2.1";
731
+ var VERSION = "0.2.3";
715
732
  function parse(argv) {
716
733
  const _ = [];
717
734
  const flags = {};
@@ -756,7 +773,7 @@ ${c.bold("Operate the box")}
756
773
  ${c.bold("Other")}
757
774
  help, --help \xB7 version, --version
758
775
 
759
- Env: ${c.dim("BOOLE_API_BASE")} (default https://trade.boole.markets), ${c.dim("BOOLE_HOME")}
776
+ Env: ${c.dim("BOOLE_API_BASE")} (REST API) \xB7 ${c.dim("BOOLE_WEB_BASE")} (login page) \xB7 ${c.dim("BOOLE_HOME")} \xB7 ${c.dim("BOOLE_TIMEOUT_MS")}
760
777
  `;
761
778
  async function main() {
762
779
  const { _, flags } = parse(process.argv.slice(2));
@@ -776,7 +793,7 @@ async function main() {
776
793
  switch (cmd) {
777
794
  case "login":
778
795
  await login({ paste: !!flags.paste });
779
- await summary();
796
+ await summary({ snapshot: false });
780
797
  break;
781
798
  case "logout":
782
799
  await logout();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boole-digital/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Boole — install, sign in, and operate your trading computer from the terminal (Claude Code, Codex, Gemini).",
5
5
  "type": "module",
6
6
  "bin": { "boole": "dist/index.js" },