@aisa-one/cli 0.6.5 → 0.6.7

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/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.7] — 2026-10-12
11
+
12
+ ### Fixed
13
+
14
+ - Display the subscription plan name in `aisa balance`: Builder Plan for
15
+ `builder` and legacy `hive_growth_30d`, Team Plan for `team`, and
16
+ Subscription Plan when the plan code is missing or unknown.
17
+
18
+ ## [0.6.6] — 2026-09-30
19
+
20
+ ### Fixed
21
+
22
+ - Open the browser on Windows. `start` is built into cmd.exe, so running it
23
+ directly failed with ENOENT and the error was swallowed: `aisa login`,
24
+ `aisa connect` and `aisa topup` never opened a page, and sign-in waited
25
+ for an approval that could not arrive. The browser now opens through
26
+ cmd.exe, with `&` and other special characters escaped so the whole URL
27
+ gets through.
28
+
10
29
  ## [0.6.5] — 2026-09-30
11
30
 
12
31
  ### Added
@@ -503,7 +522,10 @@ supports today; nothing here depends on a backend change.
503
522
  - Config commands (`aisa config get|set|list|reset`) and auth
504
523
  (`aisa login|logout|whoami`).
505
524
 
506
- [Unreleased]: https://github.com/AIsa-team/cli/compare/v0.6.4...HEAD
525
+ [Unreleased]: https://github.com/AIsa-team/cli/compare/v0.6.7...HEAD
526
+ [0.6.7]: https://github.com/AIsa-team/cli/compare/v0.6.6...v0.6.7
527
+ [0.6.6]: https://github.com/AIsa-team/cli/compare/v0.6.5...v0.6.6
528
+ [0.6.5]: https://github.com/AIsa-team/cli/compare/v0.6.4...v0.6.5
507
529
  [0.6.4]: https://github.com/AIsa-team/cli/compare/v0.6.3...v0.6.4
508
530
  [0.6.3]: https://github.com/AIsa-team/cli/compare/v0.6.2...v0.6.3
509
531
  [0.6.2]: https://github.com/AIsa-team/cli/compare/v0.6.1...v0.6.2
@@ -1,4 +1,6 @@
1
1
  export declare function formatMicrosUSD(micros: number | string | bigint): string;
2
+ /** Display name for the balance's plan credit, matching the console's plan catalog. */
3
+ export declare function planName(planCode: string | undefined): string;
2
4
  export declare function balanceAction(options?: {
3
5
  json?: boolean;
4
6
  }): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { run } from "../utils/exec.js";
1
+ import { openBrowser } from "../utils/browser.js";
2
2
  import chalk from "chalk";
3
3
  import { requireAccessToken } from "../config.js";
4
4
  import { apiRequest } from "../api.js";
@@ -17,6 +17,18 @@ export function formatMicrosUSD(micros) {
17
17
  }
18
18
  return `${negative ? "-" : ""}$${dollars.toString()}.${cents.toString().padStart(2, "0")}`;
19
19
  }
20
+ /** Display name for the balance's plan credit, matching the console's plan catalog. */
21
+ export function planName(planCode) {
22
+ switch (planCode) {
23
+ case "builder":
24
+ case "hive_growth_30d":
25
+ return "Builder Plan";
26
+ case "team":
27
+ return "Team Plan";
28
+ default:
29
+ return "Subscription Plan";
30
+ }
31
+ }
20
32
  export async function balanceAction(options = {}) {
21
33
  const key = await requireAccessToken();
22
34
  const res = await apiRequest(key, "credits/balance");
@@ -30,7 +42,7 @@ export async function balanceAction(options = {}) {
30
42
  const balance = res.data;
31
43
  console.log(` Balance: ${formatMicrosUSD(balance.account_balance_micros_usd)} ${balance.currency}`);
32
44
  console.log(` Available with key: ${formatMicrosUSD(balance.available_balance_micros_usd)} ${balance.currency}`);
33
- console.log(` GTM balance: ${formatMicrosUSD(balance.go_to_market_balance_micros_usd)} ${balance.currency}`);
45
+ console.log(` ${`${planName(balance.gtm?.plan_code)}:`.padEnd(21)}${formatMicrosUSD(balance.go_to_market_balance_micros_usd)} ${balance.currency}`);
34
46
  if (balance.api_key.unlimited) {
35
47
  console.log(" API key limit: Unlimited");
36
48
  }
@@ -92,8 +104,7 @@ export function topupAction(amount, options = {}) {
92
104
  console.log(` ${chalk.cyan(url)}`);
93
105
  if (options.open === false)
94
106
  return;
95
- const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
96
- void run(cmd, [url], { timeout: 30_000 }).catch(() => { });
107
+ openBrowser(url);
97
108
  hint("Credit lands in your account as soon as the payment completes");
98
109
  }
99
110
  /** Gateway caps GET /v1/usage at 31 days; buckets are fixed at one day. */
@@ -14,7 +14,7 @@ import { INSTALLERS, installAgent, isInstalled, supported } from "./install.js";
14
14
  import { writeCodexLLM, writeClaudeCodeLLM, writeOpencodeLLM, writeCodexAisaProfile, writeOpencodeAisaBackup, defaultModelsFor, patchCodexMCPAuth, DEFAULT_MODELS, } from "./llm-config.js";
15
15
  import { writeClaudeAisaSettings, installWrappers } from "./wrappers.js";
16
16
  import { signInAndStoreTokens } from "./oauth-login.js";
17
- import { canOpenBrowser } from "../utils/browser.js";
17
+ import { canOpenBrowser, openBrowser } from "../utils/browser.js";
18
18
  import { vscodeDetected, vscodeUserDir, writeVSCodeLLM, writeVSCodeMCP, installVSCodeExtension, launchVSCode, VSCODE_MODELS } from "./vscode.js";
19
19
  import { formatMicrosUSD } from "./account.js";
20
20
  import { apiRequest } from "../api.js";
@@ -1812,10 +1812,6 @@ function launchCursor(dir) {
1812
1812
  function withBrowserEarly() {
1813
1813
  return canOpenBrowser();
1814
1814
  }
1815
- function openBrowser(url) {
1816
- const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1817
- void run(cmd, [url], { timeout: 30_000 }).catch(() => { });
1818
- }
1819
1815
  /**
1820
1816
  * Where a live run leaves its address, so a second `aisa connect` can offer
1821
1817
  * the first one's page instead of starting a rival server. Ephemeral by
@@ -1,5 +1,4 @@
1
1
  import chalk from "chalk";
2
- import { run } from "../utils/exec.js";
3
2
  import { createHash, randomBytes } from "node:crypto";
4
3
  import { createServer } from "node:http";
5
4
  import { createInterface } from "node:readline/promises";
@@ -7,7 +6,7 @@ import { error, hint, info, success } from "../utils/display.js";
7
6
  import { replaceTokens, tokenExpiresAt } from "../config.js";
8
7
  import { maskKey } from "../config.js";
9
8
  import { httpFetch } from "../utils/http.js";
10
- import { canOpenBrowser } from "../utils/browser.js";
9
+ import { canOpenBrowser, openBrowser } from "../utils/browser.js";
11
10
  import { SIGNIN, t } from "./flow.js";
12
11
  import { renderSignInPage } from "./signin-page.js";
13
12
  import { handOverSignInPage, SIGNIN_PAGE_TTL_MS } from "./serve-signin.js";
@@ -220,10 +219,6 @@ async function waitForPaste(expectedState, lang) {
220
219
  /* c8 ignore next */
221
220
  throw new Error(t(SIGNIN.badPaste, lang));
222
221
  }
223
- function openBrowser(url) {
224
- const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
225
- void run(cmd, [url], { timeout: 30_000 }).catch(() => { });
226
- }
227
222
  export async function signInAndStoreTokens(options = {}) {
228
223
  const lang = options.lang ?? "en";
229
224
  // Unset means "work it out": a server has no browser to open and waiting
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "0.6.5";
1
+ export declare const VERSION = "0.6.7";
2
2
  /** Default for chat when no model is configured or supplied explicitly. */
3
3
  export declare const DEFAULT_CHAT_MODEL = "deepseek-v4.1-flash";
4
4
  /** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
package/dist/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION = "0.6.5";
1
+ export const VERSION = "0.6.7";
2
2
  /** Default for chat when no model is configured or supplied explicitly. */
3
3
  export const DEFAULT_CHAT_MODEL = "deepseek-v4.1-flash";
4
4
  /** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
package/dist/types.d.ts CHANGED
@@ -30,6 +30,10 @@ export interface BalanceResponse {
30
30
  account_balance_micros_usd: number;
31
31
  available_balance_micros_usd: number;
32
32
  go_to_market_balance_micros_usd: number;
33
+ gtm?: {
34
+ /** Plan of the active paid period ("builder", "team"); absent without one or on older gateways. */
35
+ plan_code?: string;
36
+ };
33
37
  api_key: {
34
38
  unlimited: boolean;
35
39
  remaining_micros_usd: number;
@@ -17,3 +17,29 @@
17
17
  * for a click nobody will ever make.
18
18
  */
19
19
  export declare function canOpenBrowser(): boolean;
20
+ /**
21
+ * The command that hands a URL to the default browser on this platform.
22
+ *
23
+ * Windows is the one that needs care. Its opener, `start`, is not a program
24
+ * but a command built into cmd.exe, so running it directly fails with
25
+ * ENOENT, and the failure used to be swallowed: the browser never opened,
26
+ * and `aisa login` sat waiting for an approval that could not arrive.
27
+ * Going through cmd.exe fixes that, with two details:
28
+ *
29
+ * · `start` reads its first quoted argument as a window title, so an empty
30
+ * title goes first; otherwise a quoted URL would become the title.
31
+ * · cmd.exe reads `&` in a query string as "run the next command", which
32
+ * would cut the URL at its second parameter. Its special characters are
33
+ * escaped with `^` so the whole URL reaches the browser.
34
+ */
35
+ export declare function browserCommand(url: string, platform?: NodeJS.Platform): {
36
+ file: string;
37
+ args: string[];
38
+ };
39
+ /**
40
+ * Open a URL in the default browser, without waiting and without failing.
41
+ *
42
+ * Every caller prints the URL as well, so a browser that does not open
43
+ * costs the user a click, not the command.
44
+ */
45
+ export declare function openBrowser(url: string): void;
@@ -1,3 +1,4 @@
1
+ import { run } from "./exec.js";
1
2
  /**
2
3
  * Can this machine put a page in front of the person using it?
3
4
  *
@@ -29,3 +30,36 @@ export function canOpenBrowser() {
29
30
  return true;
30
31
  return Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
31
32
  }
33
+ /**
34
+ * The command that hands a URL to the default browser on this platform.
35
+ *
36
+ * Windows is the one that needs care. Its opener, `start`, is not a program
37
+ * but a command built into cmd.exe, so running it directly fails with
38
+ * ENOENT, and the failure used to be swallowed: the browser never opened,
39
+ * and `aisa login` sat waiting for an approval that could not arrive.
40
+ * Going through cmd.exe fixes that, with two details:
41
+ *
42
+ * · `start` reads its first quoted argument as a window title, so an empty
43
+ * title goes first; otherwise a quoted URL would become the title.
44
+ * · cmd.exe reads `&` in a query string as "run the next command", which
45
+ * would cut the URL at its second parameter. Its special characters are
46
+ * escaped with `^` so the whole URL reaches the browser.
47
+ */
48
+ export function browserCommand(url, platform = process.platform) {
49
+ if (platform === "darwin")
50
+ return { file: "open", args: [url] };
51
+ if (platform === "win32") {
52
+ return { file: "cmd", args: ["/c", "start", "", url.replace(/[\^&|<>()]/g, "^$&")] };
53
+ }
54
+ return { file: "xdg-open", args: [url] };
55
+ }
56
+ /**
57
+ * Open a URL in the default browser, without waiting and without failing.
58
+ *
59
+ * Every caller prints the URL as well, so a browser that does not open
60
+ * costs the user a click, not the command.
61
+ */
62
+ export function openBrowser(url) {
63
+ const { file, args } = browserCommand(url);
64
+ void run(file, args, { timeout: 30_000 }).catch(() => { });
65
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aisa-one/cli",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "CLI for the AIsa unified AI infrastructure platform - one API key for 80+ LLMs and 900+ endpoints across finance, search, social, and video APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",