@bytevion/cli 0.1.0 → 0.3.0

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 (41) hide show
  1. package/README.md +66 -0
  2. package/dist/base.js +8 -1
  3. package/dist/commands/compare.d.ts +12 -0
  4. package/dist/commands/compare.js +104 -0
  5. package/dist/commands/integrate.d.ts +1 -0
  6. package/dist/commands/integrate.js +76 -28
  7. package/dist/commands/login.js +40 -59
  8. package/dist/commands/opt/preset.js +8 -5
  9. package/dist/commands/opt/show.js +20 -6
  10. package/dist/commands/providers/add.d.ts +3 -1
  11. package/dist/commands/providers/add.js +102 -20
  12. package/dist/commands/providers/rotate.js +39 -4
  13. package/dist/commands/setup.d.ts +19 -0
  14. package/dist/commands/setup.js +277 -0
  15. package/dist/commands/usage.js +32 -8
  16. package/dist/hooks/init/home.d.ts +3 -0
  17. package/dist/hooks/init/home.js +107 -0
  18. package/dist/lib/api.d.ts +1 -0
  19. package/dist/lib/api.js +60 -0
  20. package/dist/lib/auth.d.ts +9 -0
  21. package/dist/lib/auth.js +100 -0
  22. package/dist/lib/friendly.d.ts +8 -0
  23. package/dist/lib/friendly.js +86 -0
  24. package/dist/lib/home.d.ts +16 -0
  25. package/dist/lib/home.js +97 -0
  26. package/dist/lib/integrations.d.ts +1 -0
  27. package/dist/lib/integrations.js +198 -61
  28. package/dist/lib/output.d.ts +3 -0
  29. package/dist/lib/output.js +43 -0
  30. package/dist/lib/presets.d.ts +9 -0
  31. package/dist/lib/presets.js +40 -0
  32. package/dist/lib/providers.d.ts +13 -0
  33. package/dist/lib/providers.js +39 -0
  34. package/dist/lib/tty.d.ts +1 -0
  35. package/dist/lib/tty.js +11 -0
  36. package/dist/lib/ui.d.ts +60 -0
  37. package/dist/lib/ui.js +122 -0
  38. package/dist/lib/util.d.ts +1 -2
  39. package/dist/lib/util.js +11 -79
  40. package/oclif.manifest.json +215 -16
  41. package/package.json +76 -59
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @bytevion/cli — Byte from your terminal
2
+
3
+ Control the Byte LLM-optimization gateway from the command line: connect a provider, mint a
4
+ Byte key, wire your coding tool, and watch the savings — without leaving the terminal.
5
+
6
+ ```bash
7
+ npm i -g @bytevion/cli # Node >= 20.12
8
+ byte # interactive home menu
9
+ byte setup # guided setup (sign in → provider → key → tool)
10
+ ```
11
+
12
+ ## Quickstart
13
+
14
+ ```bash
15
+ byte login # approve the device in your browser
16
+ byte providers add --provider deepseek --api-key sk-... # or run `byte setup`
17
+ byte keys create my-key --preset lowest_latency
18
+ byte integrate opencode --write
19
+ byte run "hello from byte"
20
+ byte usage
21
+ ```
22
+
23
+ ## Commands
24
+
25
+ | Command | What it does |
26
+ |---|---|
27
+ | `byte` | Interactive home menu (run with no arguments in a terminal) |
28
+ | `byte setup` (alias `init`) | Guided wizard: sign in → connect provider → create key → wire a tool |
29
+ | `byte login` / `logout` / `whoami` | Device-code sign in / out / identity |
30
+ | `byte providers add\|list\|rotate\|test` | Manage upstream provider keys (BYOK) |
31
+ | `byte keys create\|list\|rotate\|revoke` | Manage Byte API keys (optional per-key `--preset`) |
32
+ | `byte opt show\|set\|preset` | Inspect / tune optimizations |
33
+ | `byte integrate <tool>` | Wire a coding harness or SDK (`--list` to see all, `--write` to apply) |
34
+ | `byte run "<prompt>"` | One-off prompt through the gateway |
35
+ | `byte compare "<prompt>"` | Run direct vs Byte and compare cost, latency, quality |
36
+ | `byte usage` / `byte stats` | Usage and savings |
37
+ | `byte env` | Print shell exports for an SDK/tool |
38
+ | `byte doctor` | Connectivity / auth / provider / gateway health |
39
+ | `byte batch submit\|list\|poll` | Offline, cost-optimized batch jobs |
40
+ | `byte sessions` | List / revoke terminal sessions |
41
+
42
+ ## Providers (presets)
43
+
44
+ `byte providers add --provider <id> --api-key <key>` — base URL and gateway mode are inferred:
45
+
46
+ `openai`, `anthropic`, `deepseek`, `gemini`, `xai`, `groq`, `mistral`, `openrouter`, `together`,
47
+ `fireworks`, `perplexity`, `cerebras`, `sambanova`, `deepinfra`, `moonshot`, `zhipu`, `qwen`,
48
+ `nebius`, `hyperbolic`, `novita`, plus `custom` (`--provider-base-url`). Azure / Bedrock / Vertex /
49
+ Cohere are advanced (need a deployment URL / SigV4 / OAuth2) — use `--provider-base-url` / the dashboard.
50
+
51
+ ## Tools you can wire (`byte integrate`)
52
+
53
+ Claude Code, Codex CLI, opencode, Cursor, Cline, Aider, Continue, Roo Code, Windsurf, Zed, Goose,
54
+ Kilo Code, Open Interpreter, Tabby, Cody, GitHub Copilot (BYOK) + Copilot CLI, Qwen Code, Kimi CLI,
55
+ Gemini CLI, and the OpenAI / Anthropic SDKs.
56
+
57
+ ## Environment
58
+
59
+ `BYTE_TOKEN` (control-plane token, for CI) · `BYTE_API_KEY` (gateway key) · `BYTE_PROFILE` ·
60
+ `BYTE_BASE_URL` · `BYTE_HOME` · `BYTE_NO_MENU=1` (disable the home menu) · `NO_COLOR` · `CI`.
61
+
62
+ Every command accepts `--json` for machine output and `--profile <name>` for multiple workspaces.
63
+
64
+ ## Exit codes
65
+
66
+ `0` ok · `2` usage · `3` auth · `4` not configured · `5` offline · `6` upstream.
package/dist/base.js CHANGED
@@ -6,6 +6,7 @@ const api_1 = require("./lib/api");
6
6
  const config_1 = require("./lib/config");
7
7
  const credentials_1 = require("./lib/credentials");
8
8
  const errors_1 = require("./lib/errors");
9
+ const friendly_1 = require("./lib/friendly");
9
10
  class BaseCommand extends core_1.Command {
10
11
  static enableJsonFlag = true;
11
12
  static baseFlags = {
@@ -41,7 +42,13 @@ class BaseCommand extends core_1.Command {
41
42
  }
42
43
  async catch(err) {
43
44
  if (err instanceof errors_1.ByteError) {
44
- return this.error(err.message, { code: err.code, exit: err.exit });
45
+ // --json callers want the machine-readable oclif error; humans get a panel that
46
+ // says what broke, why, and the exact next command — then we exit with the code.
47
+ if (this.jsonEnabled()) {
48
+ return this.error(err.message, { code: err.code, exit: err.exit });
49
+ }
50
+ this.logToStderr((0, friendly_1.renderErrorPanel)((0, friendly_1.friendlyError)(err)));
51
+ return this.exit(err.exit);
45
52
  }
46
53
  return super.catch(err);
47
54
  }
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../base';
2
+ export default class Compare extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ prompt: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ model: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const core_1 = require("@oclif/core");
37
+ const base_1 = require("../base");
38
+ const tty_1 = require("../lib/tty");
39
+ const ui = __importStar(require("../lib/ui"));
40
+ const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : Number(v) || 0);
41
+ const usd = (v) => `$${num(v).toFixed(6)}`;
42
+ const tokensOf = (m) => num(m?.tokens_in) + num(m?.tokens_out);
43
+ const pad = (s, n) => s.padEnd(n);
44
+ class Compare extends base_1.BaseCommand {
45
+ static description = 'Prove the win: run a prompt direct vs through Byte and compare cost, latency, and quality.';
46
+ static examples = [
47
+ '<%= config.bin %> compare "Summarize the latest release notes"',
48
+ '<%= config.bin %> compare "Refactor this function" --model byte-2-deepseek-chat',
49
+ ];
50
+ static args = {
51
+ prompt: core_1.Args.string({ description: 'Prompt to run on both lanes', required: true }),
52
+ };
53
+ static flags = {
54
+ model: core_1.Flags.string({ description: 'Model id (byte alias) or "auto"', default: 'auto' }),
55
+ };
56
+ async run() {
57
+ const { args, flags } = await this.parse(Compare);
58
+ this.requireToken(flags);
59
+ const api = this.api(flags);
60
+ const body = { messages: [{ role: 'user', content: args.prompt }], model: flags.model };
61
+ const panels = {};
62
+ const spin = !this.jsonEnabled() && (0, tty_1.interactive)() ? await ui.spinner() : null;
63
+ spin?.start('Running the prompt direct and through Byte…');
64
+ try {
65
+ for await (const event of api.compareStream(body)) {
66
+ const panel = String(event?.panel || '');
67
+ if (event?.metrics && (panel === 'direct' || panel === 'byte'))
68
+ panels[panel] = event.metrics;
69
+ }
70
+ }
71
+ finally {
72
+ spin?.stop('Comparison complete');
73
+ }
74
+ const direct = panels.direct || {};
75
+ const byte = panels.byte || {};
76
+ const summary = byte.compare_summary || {};
77
+ if (this.jsonEnabled())
78
+ return { direct, byte, summary };
79
+ if (!panels.direct && !panels.byte) {
80
+ this.log('No comparison result was produced. Make sure a provider and model alias are configured (`byte setup`).');
81
+ return { direct, byte, summary };
82
+ }
83
+ const savings = num(summary.savings_usd ?? byte.savings_usd);
84
+ const savingsPct = num(byte.savings_pct);
85
+ const latencySaved = num(summary.latency_saved_ms ?? byte.latency_saved_ms);
86
+ const dominance = String(byte.dominance_status || summary.dominance_status || 'n/a');
87
+ const quality = String(byte.quality_guard_state || 'not_measured');
88
+ this.log('');
89
+ this.log(` ${pad('', 16)}${pad('Direct', 18)}Byte`);
90
+ this.log(` ${pad('Cost', 16)}${pad(usd(direct.cost_usd), 18)}${usd(byte.cost_usd)}`);
91
+ this.log(` ${pad('Latency (ms)', 16)}${pad(String(num(direct.latency_ms)), 18)}${num(byte.latency_ms)}`);
92
+ this.log(` ${pad('Tokens', 16)}${pad(String(tokensOf(direct)), 18)}${tokensOf(byte)}`);
93
+ this.log('');
94
+ const sign = latencySaved >= 0 ? '−' : '+';
95
+ this.log(` Savings ${usd(savings)} (${savingsPct.toFixed(1)}%)`);
96
+ this.log(` Latency ${sign}${Math.abs(latencySaved)} ms`);
97
+ this.log(` Quality ${quality}`);
98
+ const verdict = dominance === 'dominant' ? ui.theme.ok('Byte wins (dominant)') : ui.theme.warn(dominance);
99
+ this.log(` Verdict ${verdict}`);
100
+ this.log('');
101
+ return { direct, byte, summary };
102
+ }
103
+ }
104
+ exports.default = Compare;
@@ -11,6 +11,7 @@ export default class Integrate extends BaseCommand {
11
11
  write: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
12
  yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
13
  key: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ model: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
15
  preset: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
16
  };
16
17
  run(): Promise<unknown>;
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  const core_1 = require("@oclif/core");
4
37
  const node_fs_1 = require("node:fs");
@@ -8,12 +41,15 @@ const api_1 = require("../lib/api");
8
41
  const errors_1 = require("../lib/errors");
9
42
  const integrations_1 = require("../lib/integrations");
10
43
  const shell_1 = require("../lib/shell");
44
+ const tty_1 = require("../lib/tty");
45
+ const ui = __importStar(require("../lib/ui"));
46
+ const util_1 = require("../lib/util");
11
47
  class Integrate extends base_1.BaseCommand {
12
- static description = 'Wire a coding harness or SDK to Byte (Claude Code, Codex, Cursor, Cline, Aider, OpenAI/Anthropic SDK).';
48
+ static description = 'Wire a coding harness or SDK to Byte (Claude Code, Codex, opencode, Cursor, Cline, Aider, ).';
13
49
  static examples = [
14
50
  '<%= config.bin %> integrate --list',
15
- '<%= config.bin %> integrate codex',
16
- '<%= config.bin %> integrate claude-code --write --preset lowest_latency',
51
+ '<%= config.bin %> integrate opencode --write',
52
+ '<%= config.bin %> integrate claude-code --write --model byte-2-deepseek-chat',
17
53
  ];
18
54
  static args = {
19
55
  target: core_1.Args.string({ description: 'Target to wire (run --list to see all)', required: false }),
@@ -24,6 +60,7 @@ class Integrate extends base_1.BaseCommand {
24
60
  write: core_1.Flags.boolean({ description: 'Write tool config files (a timestamped .bak is kept)' }),
25
61
  yes: core_1.Flags.boolean({ char: 'y', description: 'Skip confirmation prompts' }),
26
62
  key: core_1.Flags.string({ description: 'Byte API key to use (defaults to the saved profile key)' }),
63
+ model: core_1.Flags.string({ description: 'Model id (byte alias) to wire (default byte-default)' }),
27
64
  preset: core_1.Flags.string({
28
65
  description: 'Apply this optimization preset to the org before wiring',
29
66
  options: ['balanced', 'max_savings', 'lowest_latency', 'reliability_first'],
@@ -31,16 +68,27 @@ class Integrate extends base_1.BaseCommand {
31
68
  };
32
69
  async run() {
33
70
  const { args, flags } = await this.parse(Integrate);
34
- if (flags.list || !args.target) {
71
+ if (flags.list)
35
72
  return this.showList(flags);
73
+ let target = args.target;
74
+ if (!target) {
75
+ if ((0, tty_1.interactive)() && !this.jsonEnabled()) {
76
+ target = await ui.select({
77
+ message: 'Connect which tool?',
78
+ options: (0, integrations_1.listIntegrations)().map((i) => ({ value: i.key, label: i.title, hint: i.compat })),
79
+ });
80
+ }
81
+ else {
82
+ return this.showList(flags);
83
+ }
36
84
  }
37
- const integ = (0, integrations_1.findIntegration)(args.target);
38
- if (!integ) {
39
- return this.error(`Unknown target "${args.target}". Run \`byte integrate --list\`.`, { exit: 2 });
40
- }
85
+ const integ = (0, integrations_1.findIntegration)(target);
86
+ if (!integ)
87
+ return this.error(`Unknown target "${target}". Run \`byte integrate --list\`.`, { exit: 2 });
41
88
  const byteKey = flags.key || this.requireByteKey(flags);
42
89
  const base = this.baseUrlFrom(flags);
43
90
  const shell = (0, shell_1.detectShell)(flags.shell);
91
+ const modelAlias = flags.model || 'byte-default';
44
92
  if (flags.preset) {
45
93
  this.requireToken(flags);
46
94
  await this.api(flags).optPatch({ default_mode: flags.preset });
@@ -48,11 +96,10 @@ class Integrate extends base_1.BaseCommand {
48
96
  if (integ.compat === 'anthropic') {
49
97
  const exists = await this.messagesEndpointExists(base, byteKey);
50
98
  if (!exists) {
51
- this.warn(`${integ.title} needs Byte's Anthropic endpoint (/v1/messages), which did not respond. ` +
52
- 'The values below are correct once it is enabled on your gateway.');
99
+ this.warn(`${integ.title} needs Byte's Anthropic endpoint (/v1/messages). The values below are correct once it is enabled.`);
53
100
  }
54
101
  }
55
- const result = integ.build({ baseUrl: base, byteKey });
102
+ const result = integ.build({ baseUrl: base, byteKey, modelAlias });
56
103
  if (!this.jsonEnabled()) {
57
104
  this.log(`Integrating ${integ.title} (${integ.compat}-compatible):`);
58
105
  this.log('');
@@ -65,9 +112,8 @@ class Integrate extends base_1.BaseCommand {
65
112
  this.log(` ${line}`);
66
113
  }
67
114
  if (result.settingsFile) {
68
- if (flags.write) {
115
+ if (flags.write)
69
116
  this.writeSettings(result.settingsFile);
70
- }
71
117
  else {
72
118
  this.log('');
73
119
  this.log(` Tip: re-run with --write to update ${result.settingsFile.path} automatically.`);
@@ -77,7 +123,7 @@ class Integrate extends base_1.BaseCommand {
77
123
  else if (flags.write && result.settingsFile) {
78
124
  this.writeSettings(result.settingsFile);
79
125
  }
80
- return { target: integ.key, compat: integ.compat, env: Object.fromEntries(result.env) };
126
+ return { target: integ.key, compat: integ.compat, model: modelAlias, env: Object.fromEntries(result.env) };
81
127
  }
82
128
  writeSettings(file) {
83
129
  let existing = {};
@@ -97,24 +143,26 @@ class Integrate extends base_1.BaseCommand {
97
143
  this.log(` Updated ${file.path}`);
98
144
  }
99
145
  async messagesEndpointExists(base, byteKey) {
100
- try {
101
- await new api_1.ByteApi(base).probeMessages(byteKey);
102
- return true;
103
- }
104
- catch (err) {
105
- // 404 means the endpoint is not deployed; any other status means it exists.
106
- if (err instanceof errors_1.ByteError)
107
- return err.status !== 404;
108
- return false;
109
- }
146
+ const probe = (async () => {
147
+ try {
148
+ await new api_1.ByteApi(base).probeMessages(byteKey);
149
+ return true;
150
+ }
151
+ catch (err) {
152
+ if (err instanceof errors_1.ByteError)
153
+ return err.status !== 404;
154
+ return false;
155
+ }
156
+ })();
157
+ // Never block the UX on a slow gateway; assume reachable on timeout.
158
+ return (0, util_1.withTimeout)(probe, 4000, true);
110
159
  }
111
160
  async showList(flags) {
112
161
  const targets = (0, integrations_1.listIntegrations)();
113
162
  const key = flags.key || this.optionalByteKey(flags);
114
163
  let messagesReady;
115
- if (key) {
164
+ if (key)
116
165
  messagesReady = await this.messagesEndpointExists(this.baseUrlFrom(flags), key);
117
- }
118
166
  const rows = targets.map((t) => ({
119
167
  target: t.key,
120
168
  title: t.title,
@@ -124,8 +172,8 @@ class Integrate extends base_1.BaseCommand {
124
172
  if (this.jsonEnabled())
125
173
  return rows;
126
174
  for (const r of rows) {
127
- const status = r.ready === undefined ? 'unknown (sign in / create a key to probe)' : r.ready ? 'ready' : 'needs /v1/messages';
128
- this.log(`${r.target.padEnd(14)} ${r.title.padEnd(16)} ${r.compat.padEnd(10)} ${status}`);
175
+ const status = r.ready === undefined ? 'sign in to probe' : r.ready ? 'ready' : 'needs /v1/messages';
176
+ this.log(`${r.target.padEnd(16)} ${r.title.padEnd(22)} ${r.compat.padEnd(10)} ${status}`);
129
177
  }
130
178
  return rows;
131
179
  }
@@ -1,76 +1,57 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  const core_1 = require("@oclif/core");
4
- const node_os_1 = require("node:os");
5
37
  const base_1 = require("../base");
6
- const api_1 = require("../lib/api");
7
- const config_1 = require("../lib/config");
8
- const credentials_1 = require("../lib/credentials");
9
- const errors_1 = require("../lib/errors");
10
- const util_1 = require("../lib/util");
38
+ const auth_1 = require("../lib/auth");
39
+ const ui = __importStar(require("../lib/ui"));
11
40
  class Login extends base_1.BaseCommand {
12
41
  static description = 'Sign in from this terminal by approving a device code in the dashboard.';
13
42
  static examples = ['<%= config.bin %> login', '<%= config.bin %> login --no-browser'];
14
43
  static flags = {
15
- 'no-browser': core_1.Flags.boolean({ description: 'Do not try to open the browser automatically' }),
44
+ 'no-browser': core_1.Flags.boolean({ description: 'Do not open the browser automatically' }),
16
45
  };
17
46
  async run() {
18
47
  const { flags } = await this.parse(Login);
19
48
  const profile = this.profileFrom(flags);
20
49
  const base = this.baseUrlFrom(flags);
21
- const api = new api_1.ByteApi(base);
22
- const start = await api.deviceStart(`byte-cli@${(0, node_os_1.hostname)()}`);
23
- const verifyUrl = start.verification_uri_complete || start.verification_uri;
24
- this.log('');
25
- this.log(' Approve this terminal in your browser:');
26
- this.log(` ${verifyUrl}`);
27
- this.log('');
28
- this.log(` Verification code: ${start.user_code}`);
29
- this.log('');
30
- if (!flags['no-browser']) {
31
- try {
32
- await (0, util_1.openBrowser)(verifyUrl);
33
- }
34
- catch {
35
- // user can open manually
36
- }
37
- }
38
- let interval = (Number(start.interval) || 5) * 1000;
39
- const deadline = Date.now() + (Number(start.expires_in) || 600) * 1000;
40
- while (Date.now() < deadline) {
41
- await (0, util_1.sleep)(interval);
42
- try {
43
- const tok = await api.deviceToken(start.device_code);
44
- (0, credentials_1.setToken)(profile, tok.access_token);
45
- (0, config_1.setProfile)(profile, {
46
- base_url: base,
47
- dashboard_url: (0, config_1.getProfile)(profile).dashboard_url || config_1.DEFAULT_DASHBOARD_URL,
48
- org_id: tok.org?.id,
49
- org_name: tok.org?.name,
50
- email: tok.user?.email,
51
- });
52
- if (!this.jsonEnabled()) {
53
- this.log(`Signed in as ${tok.user?.email} (org: ${tok.org?.name}).`);
54
- this.log('Next: run `byte init` to add a provider key and create your Byte API key.');
55
- }
56
- return { status: 'signed_in', email: tok.user?.email, org: tok.org?.name, profile };
57
- }
58
- catch (err) {
59
- const code = err instanceof errors_1.ByteError ? err.code : '';
60
- if (code === 'authorization_pending')
61
- continue;
62
- if (code === 'slow_down') {
63
- interval += 5000;
64
- continue;
65
- }
66
- if (code === 'access_denied')
67
- return this.error('Authorization was denied in the dashboard.', { exit: 3 });
68
- if (code === 'expired_token')
69
- return this.error('The code expired. Run `byte login` again.', { exit: 3 });
70
- throw err;
71
- }
50
+ const res = await (0, auth_1.deviceLogin)({ baseUrl: base, profile, noBrowser: flags['no-browser'] });
51
+ if (!this.jsonEnabled()) {
52
+ await ui.log.success(`Signed in as ${res.email} (org: ${res.org}). Next: byte setup`);
72
53
  }
73
- return this.error('Login timed out. Run `byte login` again.', { exit: 3 });
54
+ return { status: 'signed_in', email: res.email, org: res.org, profile };
74
55
  }
75
56
  }
76
57
  exports.default = Login;
@@ -2,21 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_1 = require("../../base");
5
+ const presets_1 = require("../../lib/presets");
5
6
  class OptPreset extends base_1.BaseCommand {
6
- static description = 'Apply an optimization preset for the whole org.';
7
+ static description = 'Apply an optimization mode for the whole org (maximum, balanced, max_savings, lowest_latency, reliability_first).';
7
8
  static args = {
8
9
  preset: core_1.Args.string({
9
- description: 'Preset to apply',
10
+ description: 'Mode to apply',
10
11
  required: true,
11
- options: ['balanced', 'max_savings', 'lowest_latency', 'reliability_first'],
12
+ options: presets_1.PRESET_VALUES,
12
13
  }),
13
14
  };
14
15
  async run() {
15
16
  const { args, flags } = await this.parse(OptPreset);
16
17
  this.requireToken(flags);
17
18
  const res = await this.api(flags).optPatch({ default_mode: args.preset });
18
- if (!this.jsonEnabled())
19
- this.log(`Optimization preset set to "${args.preset}".`);
19
+ if (!this.jsonEnabled()) {
20
+ const card = (0, presets_1.presetCard)(args.preset);
21
+ this.log(`Optimization mode set to "${args.preset}".${card ? ` ${card.blurb}` : ''}`);
22
+ }
20
23
  return res;
21
24
  }
22
25
  }
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const picocolors_1 = __importDefault(require("picocolors"));
3
7
  const base_1 = require("../../base");
8
+ const presets_1 = require("../../lib/presets");
4
9
  class OptShow extends base_1.BaseCommand {
5
- static description = 'Show the current optimization preset and layer states for the org.';
10
+ static description = 'Show the current optimization mode and every layer running on your requests.';
6
11
  async run() {
7
12
  const { flags } = await this.parse(OptShow);
8
13
  this.requireToken(flags);
@@ -10,14 +15,23 @@ class OptShow extends base_1.BaseCommand {
10
15
  if (this.jsonEnabled())
11
16
  return res;
12
17
  const settings = res.settings ?? res;
13
- this.log(`Preset (default_mode): ${settings.default_mode ?? '-'}`);
14
- this.log(`Cache mode: ${settings.cache_mode ?? '-'}`);
18
+ const mode = settings.default_mode ?? '-';
19
+ const card = (0, presets_1.presetCard)(mode);
20
+ this.log('');
21
+ this.log(` ${picocolors_1.default.bold('Optimization mode')} ${picocolors_1.default.cyan(mode)}${card ? picocolors_1.default.dim(` ${card.hint}`) : ''}`);
22
+ this.log(` ${picocolors_1.default.bold('Cache mode')} ${picocolors_1.default.cyan(settings.cache_mode ?? '-')}`);
15
23
  const layers = Array.isArray(res.layers) ? res.layers : [];
16
24
  if (layers.length) {
17
- const enabled = layers.filter((l) => l.enabled).length;
18
- this.log(`Layers enabled: ${enabled}/${layers.length}`);
25
+ const on = layers.filter((l) => l.enabled).length;
26
+ this.log(` ${picocolors_1.default.bold('Active layers')} ${picocolors_1.default.green(String(on))}${picocolors_1.default.dim(`/${layers.length}`)} running on every request`);
27
+ this.log('');
28
+ for (const l of layers) {
29
+ const name = String(l.title ?? l.plain_label ?? l.key ?? 'layer');
30
+ this.log(l.enabled ? ` ${picocolors_1.default.green('●')} ${name}` : ` ${picocolors_1.default.dim('○')} ${picocolors_1.default.dim(name)}`);
31
+ }
19
32
  }
20
- this.log('Run with --json for the full settings object.');
33
+ this.log('');
34
+ this.log(picocolors_1.default.dim(' Run with --json for the full settings object.'));
21
35
  return res;
22
36
  }
23
37
  }
@@ -3,8 +3,10 @@ export default class ProvidersAdd extends BaseCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
+ provider: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
6
7
  'api-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
- mode: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ 'provider-base-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ mode: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
10
  label: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
11
  'no-fetch': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
12
  };