@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/dist/lib/integrations.js
CHANGED
|
@@ -4,31 +4,31 @@ exports.listIntegrations = listIntegrations;
|
|
|
4
4
|
exports.findIntegration = findIntegration;
|
|
5
5
|
const node_os_1 = require("node:os");
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
|
+
const openaiEnv = (ctx) => [
|
|
8
|
+
['OPENAI_BASE_URL', `${ctx.baseUrl}/v1`],
|
|
9
|
+
['OPENAI_API_KEY', ctx.byteKey],
|
|
10
|
+
];
|
|
11
|
+
const anthropicEnv = (ctx) => [
|
|
12
|
+
['ANTHROPIC_BASE_URL', ctx.baseUrl],
|
|
13
|
+
['ANTHROPIC_AUTH_TOKEN', ctx.byteKey],
|
|
14
|
+
];
|
|
7
15
|
const INTEGRATIONS = [
|
|
8
16
|
{
|
|
9
17
|
key: 'claude-code',
|
|
10
18
|
aliases: ['claudecode', 'claude'],
|
|
11
19
|
title: 'Claude Code',
|
|
12
20
|
compat: 'anthropic',
|
|
13
|
-
build: (
|
|
14
|
-
env:
|
|
15
|
-
['ANTHROPIC_BASE_URL', baseUrl],
|
|
16
|
-
['ANTHROPIC_AUTH_TOKEN', byteKey],
|
|
17
|
-
],
|
|
21
|
+
build: (ctx) => ({
|
|
22
|
+
env: anthropicEnv(ctx),
|
|
18
23
|
instructions: [
|
|
19
|
-
'Claude Code reads ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN
|
|
20
|
-
'
|
|
21
|
-
'the settings file. Then start Claude Code as usual.',
|
|
24
|
+
'Claude Code reads ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN (env or ~/.claude/settings.json).',
|
|
25
|
+
'Set the env vars below (or use --write), then start Claude Code.',
|
|
22
26
|
],
|
|
23
27
|
settingsFile: {
|
|
24
28
|
path: (0, node_path_1.join)((0, node_os_1.homedir)(), '.claude', 'settings.json'),
|
|
25
29
|
apply: (existing) => ({
|
|
26
30
|
...(existing && typeof existing === 'object' ? existing : {}),
|
|
27
|
-
env: {
|
|
28
|
-
...(existing?.env && typeof existing.env === 'object' ? existing.env : {}),
|
|
29
|
-
ANTHROPIC_BASE_URL: baseUrl,
|
|
30
|
-
ANTHROPIC_AUTH_TOKEN: byteKey,
|
|
31
|
-
},
|
|
31
|
+
env: { ...(existing?.env ?? {}), ANTHROPIC_BASE_URL: ctx.baseUrl, ANTHROPIC_AUTH_TOKEN: ctx.byteKey },
|
|
32
32
|
}),
|
|
33
33
|
},
|
|
34
34
|
}),
|
|
@@ -38,15 +38,38 @@ const INTEGRATIONS = [
|
|
|
38
38
|
aliases: ['codex-cli', 'openai-codex'],
|
|
39
39
|
title: 'Codex CLI',
|
|
40
40
|
compat: 'openai',
|
|
41
|
-
build: (
|
|
42
|
-
env:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
build: (ctx) => ({
|
|
42
|
+
env: openaiEnv(ctx),
|
|
43
|
+
instructions: ['Codex CLI uses OPENAI_BASE_URL + OPENAI_API_KEY (or ~/.codex/config.toml). Set the env vars below, then run codex.'],
|
|
44
|
+
}),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'opencode',
|
|
48
|
+
aliases: ['oc'],
|
|
49
|
+
title: 'opencode',
|
|
50
|
+
compat: 'openai',
|
|
51
|
+
build: (ctx) => ({
|
|
52
|
+
env: [['BYTE_API_KEY', ctx.byteKey]],
|
|
46
53
|
instructions: [
|
|
47
|
-
|
|
48
|
-
'
|
|
54
|
+
`Wires the "byte" provider in ~/.config/opencode/opencode.json (model: byte/${ctx.modelAlias}).`,
|
|
55
|
+
'Export BYTE_API_KEY (above) so opencode can read {env:BYTE_API_KEY}.',
|
|
49
56
|
],
|
|
57
|
+
settingsFile: {
|
|
58
|
+
path: (0, node_path_1.join)((0, node_os_1.homedir)(), '.config', 'opencode', 'opencode.json'),
|
|
59
|
+
apply: (existing) => {
|
|
60
|
+
const cfg = existing && typeof existing === 'object' ? existing : {};
|
|
61
|
+
const provider = { ...(cfg.provider ?? {}) };
|
|
62
|
+
const byte = provider.byte ?? {};
|
|
63
|
+
provider.byte = {
|
|
64
|
+
npm: '@ai-sdk/openai-compatible',
|
|
65
|
+
name: 'Byte',
|
|
66
|
+
...byte,
|
|
67
|
+
options: { ...(byte.options ?? {}), baseURL: `${ctx.baseUrl}/v1`, apiKey: '{env:BYTE_API_KEY}' },
|
|
68
|
+
models: { ...(byte.models ?? {}), [ctx.modelAlias]: { name: ctx.modelAlias } },
|
|
69
|
+
};
|
|
70
|
+
return { $schema: cfg.$schema ?? 'https://opencode.ai/config.json', ...cfg, provider, model: `byte/${ctx.modelAlias}` };
|
|
71
|
+
},
|
|
72
|
+
},
|
|
50
73
|
}),
|
|
51
74
|
},
|
|
52
75
|
{
|
|
@@ -54,14 +77,9 @@ const INTEGRATIONS = [
|
|
|
54
77
|
aliases: [],
|
|
55
78
|
title: 'Cursor',
|
|
56
79
|
compat: 'openai',
|
|
57
|
-
build: (
|
|
80
|
+
build: (ctx) => ({
|
|
58
81
|
env: [],
|
|
59
|
-
instructions: [
|
|
60
|
-
'In Cursor: Settings -> Models -> enable "Override OpenAI Base URL", then set',
|
|
61
|
-
` Base URL: ${baseUrl}/v1`,
|
|
62
|
-
` API Key: ${byteKey}`,
|
|
63
|
-
'Pick a model from the list (populated from Byte once a provider is connected).',
|
|
64
|
-
],
|
|
82
|
+
instructions: ['Cursor → Settings → Models → "Override OpenAI Base URL":', ` Base URL: ${ctx.baseUrl}/v1`, ` API Key: ${ctx.byteKey}`, ` Model: ${ctx.modelAlias}`],
|
|
65
83
|
}),
|
|
66
84
|
},
|
|
67
85
|
{
|
|
@@ -69,14 +87,9 @@ const INTEGRATIONS = [
|
|
|
69
87
|
aliases: [],
|
|
70
88
|
title: 'Cline (VS Code)',
|
|
71
89
|
compat: 'openai',
|
|
72
|
-
build: (
|
|
90
|
+
build: (ctx) => ({
|
|
73
91
|
env: [],
|
|
74
|
-
instructions: [
|
|
75
|
-
'In Cline: set API Provider = "OpenAI Compatible", then',
|
|
76
|
-
` Base URL: ${baseUrl}/v1`,
|
|
77
|
-
` API Key: ${byteKey}`,
|
|
78
|
-
' Model: an enabled alias (see `byte providers test <id>`).',
|
|
79
|
-
],
|
|
92
|
+
instructions: ['Cline → API Provider "OpenAI Compatible":', ` Base URL: ${ctx.baseUrl}/v1`, ` API Key: ${ctx.byteKey}`, ` Model: ${ctx.modelAlias}`],
|
|
80
93
|
}),
|
|
81
94
|
},
|
|
82
95
|
{
|
|
@@ -84,15 +97,149 @@ const INTEGRATIONS = [
|
|
|
84
97
|
aliases: [],
|
|
85
98
|
title: 'Aider',
|
|
86
99
|
compat: 'openai',
|
|
87
|
-
build: (
|
|
88
|
-
env: [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
build: (ctx) => ({
|
|
101
|
+
env: [['OPENAI_API_BASE', `${ctx.baseUrl}/v1`], ['OPENAI_API_KEY', ctx.byteKey]],
|
|
102
|
+
instructions: ['Aider honors OPENAI_API_BASE + OPENAI_API_KEY (or ~/.aider.conf.yml openai-api-base).', `Run e.g. aider --model openai/${ctx.modelAlias}`],
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
key: 'continue',
|
|
107
|
+
aliases: ['continue-dev'],
|
|
108
|
+
title: 'Continue.dev',
|
|
109
|
+
compat: 'openai',
|
|
110
|
+
build: (ctx) => ({
|
|
111
|
+
env: [],
|
|
112
|
+
instructions: ['Continue → ~/.continue/config.yaml add a model:', ` - provider: openai`, ` apiBase: ${ctx.baseUrl}/v1`, ` apiKey: ${ctx.byteKey}`, ` model: ${ctx.modelAlias}`],
|
|
113
|
+
}),
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
key: 'roo',
|
|
117
|
+
aliases: ['roo-code'],
|
|
118
|
+
title: 'Roo Code',
|
|
119
|
+
compat: 'openai',
|
|
120
|
+
build: (ctx) => ({
|
|
121
|
+
env: [],
|
|
122
|
+
instructions: ['Roo Code → OpenAI Compatible provider:', ` Base URL: ${ctx.baseUrl}/v1`, ` API Key: ${ctx.byteKey}`, ` Model: ${ctx.modelAlias}`],
|
|
123
|
+
}),
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: 'windsurf',
|
|
127
|
+
aliases: [],
|
|
128
|
+
title: 'Windsurf',
|
|
129
|
+
compat: 'openai',
|
|
130
|
+
build: (ctx) => ({
|
|
131
|
+
env: openaiEnv(ctx),
|
|
132
|
+
instructions: ['Windsurf → custom/OpenAI-compatible model settings:', ` Base URL: ${ctx.baseUrl}/v1`, ` API Key: ${ctx.byteKey}`],
|
|
133
|
+
}),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
key: 'zed',
|
|
137
|
+
aliases: [],
|
|
138
|
+
title: 'Zed',
|
|
139
|
+
compat: 'openai',
|
|
140
|
+
build: (ctx) => ({
|
|
141
|
+
env: [],
|
|
142
|
+
instructions: ['Zed → settings.json, add a custom LLM provider with:', ` "api_url": "${ctx.baseUrl}/v1"`, ` API key set via Zed’s key prompt; model ${ctx.modelAlias}`],
|
|
143
|
+
}),
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
key: 'goose',
|
|
147
|
+
aliases: [],
|
|
148
|
+
title: 'Goose (Block)',
|
|
149
|
+
compat: 'openai',
|
|
150
|
+
build: (ctx) => ({
|
|
151
|
+
env: openaiEnv(ctx),
|
|
152
|
+
instructions: ['Goose → configure an OpenAI-compatible provider (BYOM) using the env vars below.'],
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
key: 'kilo',
|
|
157
|
+
aliases: ['kilo-code'],
|
|
158
|
+
title: 'Kilo Code',
|
|
159
|
+
compat: 'openai',
|
|
160
|
+
build: (ctx) => ({
|
|
161
|
+
env: [],
|
|
162
|
+
instructions: ['Kilo Code → OpenAI Compatible provider:', ` Base URL: ${ctx.baseUrl}/v1`, ` API Key: ${ctx.byteKey}`, ` Model: ${ctx.modelAlias}`],
|
|
163
|
+
}),
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
key: 'open-interpreter',
|
|
167
|
+
aliases: ['oi', 'interpreter'],
|
|
168
|
+
title: 'Open Interpreter',
|
|
169
|
+
compat: 'openai',
|
|
170
|
+
build: (ctx) => ({
|
|
171
|
+
env: openaiEnv(ctx),
|
|
172
|
+
instructions: [`Run: interpreter --api_base ${ctx.baseUrl}/v1 --api_key ${ctx.byteKey} --model ${ctx.modelAlias}`],
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
key: 'tabby',
|
|
177
|
+
aliases: [],
|
|
178
|
+
title: 'Tabby',
|
|
179
|
+
compat: 'openai',
|
|
180
|
+
build: (ctx) => ({
|
|
181
|
+
env: [],
|
|
182
|
+
instructions: ['Tabby → HTTP model connector (OpenAI-compatible):', ` kind: openai/chat, model: ${ctx.modelAlias}`, ` api_endpoint: ${ctx.baseUrl}/v1, api_key: ${ctx.byteKey}`],
|
|
183
|
+
}),
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
key: 'cody',
|
|
187
|
+
aliases: [],
|
|
188
|
+
title: 'Cody (Sourcegraph)',
|
|
189
|
+
compat: 'openai',
|
|
190
|
+
build: (ctx) => ({
|
|
191
|
+
env: [],
|
|
192
|
+
instructions: ['Cody (enterprise) → model config, openaicompatible endpoint:', ` url: ${ctx.baseUrl}/v1, accessToken: ${ctx.byteKey}`],
|
|
193
|
+
}),
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
key: 'copilot',
|
|
197
|
+
aliases: ['github-copilot'],
|
|
198
|
+
title: 'GitHub Copilot (BYOK)',
|
|
199
|
+
compat: 'openai',
|
|
200
|
+
build: (ctx) => ({
|
|
201
|
+
env: [['COPILOT_PROVIDER_BASE_URL', `${ctx.baseUrl}/v1`], ['COPILOT_PROVIDER_API_KEY', ctx.byteKey], ['COPILOT_MODEL', ctx.modelAlias]],
|
|
202
|
+
instructions: ['GitHub Copilot BYOK reads COPILOT_PROVIDER_BASE_URL + COPILOT_PROVIDER_API_KEY + COPILOT_MODEL.'],
|
|
203
|
+
}),
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
key: 'copilot-cli',
|
|
207
|
+
aliases: [],
|
|
208
|
+
title: 'GitHub Copilot CLI (BYOK)',
|
|
209
|
+
compat: 'openai',
|
|
210
|
+
build: (ctx) => ({
|
|
211
|
+
env: [['COPILOT_PROVIDER_BASE_URL', `${ctx.baseUrl}/v1`], ['COPILOT_PROVIDER_API_KEY', ctx.byteKey], ['COPILOT_MODEL', ctx.modelAlias]],
|
|
212
|
+
instructions: ['Copilot CLI BYOK reads COPILOT_PROVIDER_BASE_URL + COPILOT_PROVIDER_API_KEY + COPILOT_MODEL.'],
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: 'qwen-code',
|
|
217
|
+
aliases: ['qwen'],
|
|
218
|
+
title: 'Qwen Code',
|
|
219
|
+
compat: 'openai',
|
|
220
|
+
build: (ctx) => ({
|
|
221
|
+
env: openaiEnv(ctx),
|
|
222
|
+
instructions: ['Qwen Code → set the OpenAI-compatible env vars below (DashScope compatible-mode style).'],
|
|
223
|
+
}),
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
key: 'kimi-cli',
|
|
227
|
+
aliases: ['kimi'],
|
|
228
|
+
title: 'Kimi CLI (Moonshot)',
|
|
229
|
+
compat: 'anthropic',
|
|
230
|
+
build: (ctx) => ({
|
|
231
|
+
env: anthropicEnv(ctx),
|
|
232
|
+
instructions: ['Kimi CLI honors ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN.'],
|
|
233
|
+
}),
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
key: 'gemini-cli',
|
|
237
|
+
aliases: [],
|
|
238
|
+
title: 'Gemini CLI',
|
|
239
|
+
compat: 'openai',
|
|
240
|
+
build: (ctx) => ({
|
|
241
|
+
env: openaiEnv(ctx),
|
|
242
|
+
instructions: ['Gemini CLI custom-endpoint support is limited; the OpenAI-compatible env below works where supported.'],
|
|
96
243
|
}),
|
|
97
244
|
},
|
|
98
245
|
{
|
|
@@ -100,18 +247,13 @@ const INTEGRATIONS = [
|
|
|
100
247
|
aliases: ['openai-sdk'],
|
|
101
248
|
title: 'OpenAI SDK',
|
|
102
249
|
compat: 'openai',
|
|
103
|
-
build: (
|
|
104
|
-
env:
|
|
105
|
-
['OPENAI_BASE_URL', `${baseUrl}/v1`],
|
|
106
|
-
['OPENAI_API_KEY', byteKey],
|
|
107
|
-
],
|
|
250
|
+
build: (ctx) => ({
|
|
251
|
+
env: openaiEnv(ctx),
|
|
108
252
|
instructions: [
|
|
109
253
|
'Python:',
|
|
110
|
-
`
|
|
111
|
-
` client = OpenAI(base_url="${baseUrl}/v1", api_key="${byteKey}")`,
|
|
254
|
+
` client = OpenAI(base_url="${ctx.baseUrl}/v1", api_key="${ctx.byteKey}")`,
|
|
112
255
|
'JavaScript:',
|
|
113
|
-
`
|
|
114
|
-
` const client = new OpenAI({ baseURL: "${baseUrl}/v1", apiKey: "${byteKey}" })`,
|
|
256
|
+
` new OpenAI({ baseURL: "${ctx.baseUrl}/v1", apiKey: "${ctx.byteKey}" })`,
|
|
115
257
|
],
|
|
116
258
|
}),
|
|
117
259
|
},
|
|
@@ -120,18 +262,13 @@ const INTEGRATIONS = [
|
|
|
120
262
|
aliases: ['anthropic-sdk'],
|
|
121
263
|
title: 'Anthropic SDK',
|
|
122
264
|
compat: 'anthropic',
|
|
123
|
-
build: (
|
|
124
|
-
env:
|
|
125
|
-
['ANTHROPIC_BASE_URL', baseUrl],
|
|
126
|
-
['ANTHROPIC_AUTH_TOKEN', byteKey],
|
|
127
|
-
],
|
|
265
|
+
build: (ctx) => ({
|
|
266
|
+
env: anthropicEnv(ctx),
|
|
128
267
|
instructions: [
|
|
129
268
|
'Python:',
|
|
130
|
-
`
|
|
131
|
-
` client = Anthropic(base_url="${baseUrl}", auth_token="${byteKey}")`,
|
|
269
|
+
` client = Anthropic(base_url="${ctx.baseUrl}", auth_token="${ctx.byteKey}")`,
|
|
132
270
|
'JavaScript:',
|
|
133
|
-
`
|
|
134
|
-
` const client = new Anthropic({ baseURL: "${baseUrl}", authToken: "${byteKey}" })`,
|
|
271
|
+
` new Anthropic({ baseURL: "${ctx.baseUrl}", authToken: "${ctx.byteKey}" })`,
|
|
135
272
|
],
|
|
136
273
|
}),
|
|
137
274
|
},
|
package/dist/lib/output.d.ts
CHANGED
|
@@ -2,3 +2,6 @@ export declare function renderTable(head: string[], rows: Array<Array<string | n
|
|
|
2
2
|
export declare function maskKey(value: string | undefined): string;
|
|
3
3
|
export declare function fmtUsd(value: unknown): string;
|
|
4
4
|
export declare function pct(value: unknown): string;
|
|
5
|
+
export declare function fmtNum(value: unknown): string;
|
|
6
|
+
export declare function fmtBucket(value: unknown): string;
|
|
7
|
+
export declare function sparkline(values: number[], plain?: boolean): string;
|
package/dist/lib/output.js
CHANGED
|
@@ -7,6 +7,9 @@ exports.renderTable = renderTable;
|
|
|
7
7
|
exports.maskKey = maskKey;
|
|
8
8
|
exports.fmtUsd = fmtUsd;
|
|
9
9
|
exports.pct = pct;
|
|
10
|
+
exports.fmtNum = fmtNum;
|
|
11
|
+
exports.fmtBucket = fmtBucket;
|
|
12
|
+
exports.sparkline = sparkline;
|
|
10
13
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
11
14
|
function renderTable(head, rows) {
|
|
12
15
|
const table = new cli_table3_1.default({ head });
|
|
@@ -35,3 +38,43 @@ function pct(value) {
|
|
|
35
38
|
const scaled = n <= 1 ? n * 100 : n;
|
|
36
39
|
return `${scaled.toFixed(1)}%`;
|
|
37
40
|
}
|
|
41
|
+
// 1234 -> "1.2K", 1_500_000 -> "1.5M". Keeps small counts exact.
|
|
42
|
+
function fmtNum(value) {
|
|
43
|
+
const n = typeof value === 'number' ? value : Number(value);
|
|
44
|
+
if (!Number.isFinite(n))
|
|
45
|
+
return '-';
|
|
46
|
+
const abs = Math.abs(n);
|
|
47
|
+
if (abs >= 1_000_000)
|
|
48
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
49
|
+
if (abs >= 1_000)
|
|
50
|
+
return `${(n / 1_000).toFixed(1)}K`;
|
|
51
|
+
return String(Math.round(n));
|
|
52
|
+
}
|
|
53
|
+
const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
54
|
+
// "2026-05-30" -> "May 30"; "2026-05-30T14:00:00Z" -> "May 30 14:00".
|
|
55
|
+
function fmtBucket(value) {
|
|
56
|
+
if (typeof value !== 'string' || !value)
|
|
57
|
+
return '-';
|
|
58
|
+
const m = value.match(/^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):)?/);
|
|
59
|
+
if (!m)
|
|
60
|
+
return value;
|
|
61
|
+
const mon = MONTHS[Number(m[2]) - 1] ?? m[2];
|
|
62
|
+
const day = String(Number(m[3]));
|
|
63
|
+
return m[4] ? `${mon} ${day} ${m[4]}:00` : `${mon} ${day}`;
|
|
64
|
+
}
|
|
65
|
+
// Unicode block sparkline with an ASCII fallback for legacy terminals (NO_COLOR/conhost).
|
|
66
|
+
function sparkline(values, plain = false) {
|
|
67
|
+
const nums = values.map((v) => (Number.isFinite(v) ? v : 0));
|
|
68
|
+
if (!nums.length)
|
|
69
|
+
return '';
|
|
70
|
+
const ramp = plain ? '.:-=+*#'.split('') : '▁▂▃▄▅▆▇█'.split('');
|
|
71
|
+
const max = Math.max(...nums);
|
|
72
|
+
const min = Math.min(...nums);
|
|
73
|
+
const span = max - min || 1;
|
|
74
|
+
return nums
|
|
75
|
+
.map((v) => {
|
|
76
|
+
const idx = Math.round(((v - min) / span) * (ramp.length - 1));
|
|
77
|
+
return ramp[Math.max(0, Math.min(ramp.length - 1, idx))];
|
|
78
|
+
})
|
|
79
|
+
.join('');
|
|
80
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface PresetCard {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
hint: string;
|
|
5
|
+
blurb: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const PRESET_CARDS: PresetCard[];
|
|
8
|
+
export declare const PRESET_VALUES: string[];
|
|
9
|
+
export declare function presetCard(value: string): PresetCard | undefined;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PRESET_VALUES = exports.PRESET_CARDS = void 0;
|
|
4
|
+
exports.presetCard = presetCard;
|
|
5
|
+
exports.PRESET_CARDS = [
|
|
6
|
+
{
|
|
7
|
+
value: 'maximum',
|
|
8
|
+
label: 'Maximum — everything on (recommended)',
|
|
9
|
+
hint: 'best savings + quality',
|
|
10
|
+
blurb: 'Every production-safe optimization runs on every request: full caching, compression, routing, and quality guards.',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
value: 'max_savings',
|
|
14
|
+
label: 'Maximum savings',
|
|
15
|
+
hint: 'cheapest',
|
|
16
|
+
blurb: 'Leans hardest on caching, compression, and cheaper routing to cut spend the most.',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: 'balanced',
|
|
20
|
+
label: 'Balanced',
|
|
21
|
+
hint: 'savings + speed',
|
|
22
|
+
blurb: 'A middle ground: strong savings without the deepest latency-adding passes.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
value: 'lowest_latency',
|
|
26
|
+
label: 'Lowest latency',
|
|
27
|
+
hint: 'fastest',
|
|
28
|
+
blurb: 'Skips the heavier passes so responses come back as fast as possible.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'reliability_first',
|
|
32
|
+
label: 'Reliability first',
|
|
33
|
+
hint: 'most robust',
|
|
34
|
+
blurb: 'Prioritizes verification, repair, and fallbacks over maximum savings.',
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
exports.PRESET_VALUES = exports.PRESET_CARDS.map((c) => c.value);
|
|
38
|
+
function presetCard(value) {
|
|
39
|
+
return exports.PRESET_CARDS.find((c) => c.value === value);
|
|
40
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ProviderPreset {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
base_url: string;
|
|
5
|
+
gateway_mode: string;
|
|
6
|
+
keyHint: string;
|
|
7
|
+
advanced?: boolean;
|
|
8
|
+
custom?: boolean;
|
|
9
|
+
note?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const PROVIDER_PRESETS: ProviderPreset[];
|
|
12
|
+
export declare function findPreset(id: string): ProviderPreset | undefined;
|
|
13
|
+
export declare function presetIds(): string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROVIDER_PRESETS = void 0;
|
|
4
|
+
exports.findPreset = findPreset;
|
|
5
|
+
exports.presetIds = presetIds;
|
|
6
|
+
exports.PROVIDER_PRESETS = [
|
|
7
|
+
{ id: 'openai', label: 'OpenAI', base_url: 'https://api.openai.com/v1', gateway_mode: 'byte_compatible', keyHint: 'sk-…' },
|
|
8
|
+
{ id: 'anthropic', label: 'Anthropic (Claude)', base_url: 'https://api.anthropic.com/v1', gateway_mode: 'byte_messages', keyHint: 'sk-ant-…' },
|
|
9
|
+
{ id: 'deepseek', label: 'DeepSeek', base_url: 'https://api.deepseek.com', gateway_mode: 'byte_compatible', keyHint: 'sk-…' },
|
|
10
|
+
{ id: 'gemini', label: 'Google Gemini', base_url: 'https://generativelanguage.googleapis.com/v1beta', gateway_mode: 'byte_generative', keyHint: 'AIza…' },
|
|
11
|
+
{ id: 'xai', label: 'xAI (Grok)', base_url: 'https://api.x.ai/v1', gateway_mode: 'byte_compatible', keyHint: 'xai-…' },
|
|
12
|
+
{ id: 'groq', label: 'Groq', base_url: 'https://api.groq.com/openai/v1', gateway_mode: 'byte_compatible', keyHint: 'gsk_…' },
|
|
13
|
+
{ id: 'mistral', label: 'Mistral', base_url: 'https://api.mistral.ai/v1', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
14
|
+
{ id: 'openrouter', label: 'OpenRouter', base_url: 'https://openrouter.ai/api/v1', gateway_mode: 'byte_compatible', keyHint: 'sk-or-…' },
|
|
15
|
+
{ id: 'together', label: 'Together AI', base_url: 'https://api.together.xyz/v1', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
16
|
+
{ id: 'fireworks', label: 'Fireworks AI', base_url: 'https://api.fireworks.ai/inference/v1', gateway_mode: 'byte_compatible', keyHint: 'fw_…' },
|
|
17
|
+
{ id: 'perplexity', label: 'Perplexity', base_url: 'https://api.perplexity.ai', gateway_mode: 'byte_compatible', keyHint: 'pplx-…' },
|
|
18
|
+
{ id: 'cerebras', label: 'Cerebras', base_url: 'https://api.cerebras.ai/v1', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
19
|
+
{ id: 'sambanova', label: 'SambaNova', base_url: 'https://api.sambanova.ai/v1', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
20
|
+
{ id: 'deepinfra', label: 'DeepInfra', base_url: 'https://api.deepinfra.com/v1/openai', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
21
|
+
{ id: 'moonshot', label: 'Moonshot (Kimi)', base_url: 'https://api.moonshot.ai/v1', gateway_mode: 'byte_compatible', keyHint: 'sk-…' },
|
|
22
|
+
{ id: 'zhipu', label: 'Zhipu (GLM)', base_url: 'https://open.bigmodel.cn/api/paas/v4', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
23
|
+
{ id: 'qwen', label: 'Alibaba Qwen (DashScope)', base_url: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1', gateway_mode: 'byte_compatible', keyHint: 'sk-…' },
|
|
24
|
+
{ id: 'nebius', label: 'Nebius AI Studio', base_url: 'https://api.studio.nebius.com/v1', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
25
|
+
{ id: 'hyperbolic', label: 'Hyperbolic', base_url: 'https://api.hyperbolic.xyz/v1', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
26
|
+
{ id: 'novita', label: 'Novita AI', base_url: 'https://api.novita.ai/openai', gateway_mode: 'byte_compatible', keyHint: '…' },
|
|
27
|
+
// Advanced: not a simple base_url + bearer key; surfaced with a clear note, not one-click.
|
|
28
|
+
{ id: 'azure', label: 'Azure OpenAI', base_url: '', gateway_mode: 'byte_compatible', keyHint: 'your key', advanced: true, note: 'Provide your deployment URL; Azure uses an api-key header.' },
|
|
29
|
+
{ id: 'bedrock', label: 'AWS Bedrock', base_url: '', gateway_mode: 'byte_compatible', keyHint: 'AWS creds', advanced: true, note: 'Requires AWS SigV4 signing — not yet one-click.' },
|
|
30
|
+
{ id: 'vertex', label: 'Google Vertex AI', base_url: '', gateway_mode: 'byte_generative', keyHint: 'service account', advanced: true, note: 'Requires an OAuth2 service account — not yet one-click.' },
|
|
31
|
+
{ id: 'cohere', label: 'Cohere', base_url: 'https://api.cohere.com/v2', gateway_mode: 'byte_compatible', keyHint: '…', advanced: true, note: 'Cohere v2 API shape may need a bridge.' },
|
|
32
|
+
{ id: 'custom', label: 'Custom (OpenAI-compatible)', base_url: '', gateway_mode: 'byte_compatible', keyHint: '…', custom: true },
|
|
33
|
+
];
|
|
34
|
+
function findPreset(id) {
|
|
35
|
+
return exports.PROVIDER_PRESETS.find((p) => p.id === id.toLowerCase());
|
|
36
|
+
}
|
|
37
|
+
function presetIds() {
|
|
38
|
+
return exports.PROVIDER_PRESETS.map((p) => p.id);
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function interactive(): boolean;
|
package/dist/lib/tty.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.interactive = interactive;
|
|
4
|
+
// Interactive only when both ends are a real terminal, not in CI, and not opted out.
|
|
5
|
+
// Machines (pipes, CI, --json) must never get a prompt or a menu — they fall back to
|
|
6
|
+
// flags or oclif's normal help/error path.
|
|
7
|
+
function interactive() {
|
|
8
|
+
return (Boolean(process.stdin.isTTY && process.stdout.isTTY) &&
|
|
9
|
+
!process.env.CI &&
|
|
10
|
+
process.env.BYTE_NO_MENU !== '1');
|
|
11
|
+
}
|
package/dist/lib/ui.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export declare const theme: {
|
|
2
|
+
accent: (s: string) => string;
|
|
3
|
+
ok: (s: string) => string;
|
|
4
|
+
warn: (s: string) => string;
|
|
5
|
+
bad: (s: string) => string;
|
|
6
|
+
muted: (s: string) => string;
|
|
7
|
+
bold: (s: string) => string;
|
|
8
|
+
};
|
|
9
|
+
export declare function banner(): string;
|
|
10
|
+
export declare function intro(message: string): Promise<void>;
|
|
11
|
+
export declare function outro(message: string): Promise<void>;
|
|
12
|
+
export declare function note(message: string, title?: string): Promise<void>;
|
|
13
|
+
export declare const log: {
|
|
14
|
+
info(message: string): Promise<void>;
|
|
15
|
+
success(message: string): Promise<void>;
|
|
16
|
+
warn(message: string): Promise<void>;
|
|
17
|
+
error(message: string): Promise<void>;
|
|
18
|
+
step(message: string): Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export declare function text(opts: {
|
|
21
|
+
message: string;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
defaultValue?: string;
|
|
24
|
+
initialValue?: string;
|
|
25
|
+
validate?: (value: string) => string | undefined;
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
export declare function password(opts: {
|
|
28
|
+
message: string;
|
|
29
|
+
mask?: string;
|
|
30
|
+
validate?: (value: string) => string | undefined;
|
|
31
|
+
}): Promise<string>;
|
|
32
|
+
export interface SelectOption<T extends string> {
|
|
33
|
+
value: T;
|
|
34
|
+
label: string;
|
|
35
|
+
hint?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function select<T extends string>(opts: {
|
|
38
|
+
message: string;
|
|
39
|
+
options: Array<SelectOption<T>>;
|
|
40
|
+
initialValue?: T;
|
|
41
|
+
maxItems?: number;
|
|
42
|
+
}): Promise<T>;
|
|
43
|
+
export declare function multiselect<T extends string>(opts: {
|
|
44
|
+
message: string;
|
|
45
|
+
options: Array<SelectOption<T>>;
|
|
46
|
+
initialValues?: T[];
|
|
47
|
+
required?: boolean;
|
|
48
|
+
}): Promise<T[]>;
|
|
49
|
+
export declare function confirm(opts: {
|
|
50
|
+
message: string;
|
|
51
|
+
initialValue?: boolean;
|
|
52
|
+
}): Promise<boolean>;
|
|
53
|
+
export interface Spinner {
|
|
54
|
+
start(message?: string): void;
|
|
55
|
+
stop(message?: string, code?: number): void;
|
|
56
|
+
message(message?: string): void;
|
|
57
|
+
}
|
|
58
|
+
export declare function spinner(): Promise<Spinner>;
|
|
59
|
+
export declare function revealSecret(label: string, value: string): Promise<void>;
|
|
60
|
+
export declare function cancelAndExit(message?: string): Promise<never>;
|