@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.
- package/README.md +66 -0
- package/dist/base.js +8 -1
- package/dist/commands/compare.d.ts +12 -0
- package/dist/commands/compare.js +104 -0
- package/dist/commands/integrate.d.ts +1 -0
- package/dist/commands/integrate.js +76 -28
- package/dist/commands/login.js +40 -59
- package/dist/commands/opt/preset.js +8 -5
- package/dist/commands/opt/show.js +20 -6
- package/dist/commands/providers/add.d.ts +3 -1
- package/dist/commands/providers/add.js +102 -20
- package/dist/commands/providers/rotate.js +39 -4
- package/dist/commands/setup.d.ts +19 -0
- package/dist/commands/setup.js +277 -0
- package/dist/commands/usage.js +32 -8
- package/dist/hooks/init/home.d.ts +3 -0
- package/dist/hooks/init/home.js +107 -0
- package/dist/lib/api.d.ts +1 -0
- package/dist/lib/api.js +60 -0
- package/dist/lib/auth.d.ts +9 -0
- package/dist/lib/auth.js +100 -0
- package/dist/lib/friendly.d.ts +8 -0
- package/dist/lib/friendly.js +86 -0
- package/dist/lib/home.d.ts +16 -0
- package/dist/lib/home.js +97 -0
- package/dist/lib/integrations.d.ts +1 -0
- package/dist/lib/integrations.js +198 -61
- package/dist/lib/output.d.ts +3 -0
- package/dist/lib/output.js +43 -0
- package/dist/lib/presets.d.ts +9 -0
- package/dist/lib/presets.js +40 -0
- package/dist/lib/providers.d.ts +13 -0
- package/dist/lib/providers.js +39 -0
- package/dist/lib/tty.d.ts +1 -0
- package/dist/lib/tty.js +11 -0
- package/dist/lib/ui.d.ts +60 -0
- package/dist/lib/ui.js +122 -0
- package/dist/lib/util.d.ts +1 -2
- package/dist/lib/util.js +11 -79
- package/oclif.manifest.json +215 -16
- 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
|
-
|
|
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,
|
|
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
|
|
16
|
-
'<%= config.bin %> integrate claude-code --write --
|
|
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
|
|
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)(
|
|
38
|
-
if (!integ)
|
|
39
|
-
return this.error(`Unknown target "${
|
|
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)
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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 ? '
|
|
128
|
-
this.log(`${r.target.padEnd(
|
|
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
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -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
|
|
7
|
-
const
|
|
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
|
|
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
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
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
|
|
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: '
|
|
10
|
+
description: 'Mode to apply',
|
|
10
11
|
required: true,
|
|
11
|
-
options:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
14
|
-
|
|
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
|
|
18
|
-
this.log(`
|
|
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('
|
|
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
|
-
|
|
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
|
};
|