@bytevion/cli 0.1.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 (75) hide show
  1. package/bin/run.js +7 -0
  2. package/dist/base.d.ts +20 -0
  3. package/dist/base.js +49 -0
  4. package/dist/commands/batch/list.d.ts +5 -0
  5. package/dist/commands/batch/list.js +22 -0
  6. package/dist/commands/batch/poll.d.ts +13 -0
  7. package/dist/commands/batch/poll.js +42 -0
  8. package/dist/commands/batch/submit.d.ts +13 -0
  9. package/dist/commands/batch/submit.js +74 -0
  10. package/dist/commands/doctor.d.ts +5 -0
  11. package/dist/commands/doctor.js +65 -0
  12. package/dist/commands/env.d.ts +10 -0
  13. package/dist/commands/env.js +35 -0
  14. package/dist/commands/init.d.ts +12 -0
  15. package/dist/commands/init.js +58 -0
  16. package/dist/commands/integrate.d.ts +20 -0
  17. package/dist/commands/integrate.js +133 -0
  18. package/dist/commands/keys/create.d.ts +11 -0
  19. package/dist/commands/keys/create.js +33 -0
  20. package/dist/commands/keys/list.d.ts +5 -0
  21. package/dist/commands/keys/list.js +21 -0
  22. package/dist/commands/keys/revoke.d.ts +11 -0
  23. package/dist/commands/keys/revoke.js +19 -0
  24. package/dist/commands/keys/rotate.d.ts +11 -0
  25. package/dist/commands/keys/rotate.js +24 -0
  26. package/dist/commands/login.d.ts +9 -0
  27. package/dist/commands/login.js +76 -0
  28. package/dist/commands/logout.d.ts +5 -0
  29. package/dist/commands/logout.js +24 -0
  30. package/dist/commands/opt/preset.d.ts +8 -0
  31. package/dist/commands/opt/preset.js +23 -0
  32. package/dist/commands/opt/set.d.ts +10 -0
  33. package/dist/commands/opt/set.js +22 -0
  34. package/dist/commands/opt/show.d.ts +5 -0
  35. package/dist/commands/opt/show.js +24 -0
  36. package/dist/commands/providers/add.d.ts +12 -0
  37. package/dist/commands/providers/add.js +40 -0
  38. package/dist/commands/providers/list.d.ts +5 -0
  39. package/dist/commands/providers/list.js +22 -0
  40. package/dist/commands/providers/rotate.d.ts +14 -0
  41. package/dist/commands/providers/rotate.js +28 -0
  42. package/dist/commands/providers/test.d.ts +11 -0
  43. package/dist/commands/providers/test.js +22 -0
  44. package/dist/commands/run.d.ts +13 -0
  45. package/dist/commands/run.js +32 -0
  46. package/dist/commands/sessions/index.d.ts +5 -0
  47. package/dist/commands/sessions/index.js +21 -0
  48. package/dist/commands/sessions/revoke.d.ts +8 -0
  49. package/dist/commands/sessions/revoke.js +19 -0
  50. package/dist/commands/stats.d.ts +5 -0
  51. package/dist/commands/stats.js +27 -0
  52. package/dist/commands/usage.d.ts +8 -0
  53. package/dist/commands/usage.js +32 -0
  54. package/dist/commands/whoami.d.ts +5 -0
  55. package/dist/commands/whoami.js +19 -0
  56. package/dist/lib/api.d.ts +40 -0
  57. package/dist/lib/api.js +147 -0
  58. package/dist/lib/config.d.ts +20 -0
  59. package/dist/lib/config.js +52 -0
  60. package/dist/lib/credentials.d.ts +5 -0
  61. package/dist/lib/credentials.js +50 -0
  62. package/dist/lib/errors.d.ts +7 -0
  63. package/dist/lib/errors.js +30 -0
  64. package/dist/lib/integrations.d.ts +23 -0
  65. package/dist/lib/integrations.js +145 -0
  66. package/dist/lib/output.d.ts +4 -0
  67. package/dist/lib/output.js +37 -0
  68. package/dist/lib/paths.d.ts +3 -0
  69. package/dist/lib/paths.js +19 -0
  70. package/dist/lib/shell.d.ts +4 -0
  71. package/dist/lib/shell.js +25 -0
  72. package/dist/lib/util.d.ts +4 -0
  73. package/dist/lib/util.js +101 -0
  74. package/oclif.manifest.json +1516 -0
  75. package/package.json +59 -0
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../base");
5
+ const output_1 = require("../lib/output");
6
+ class Usage extends base_1.BaseCommand {
7
+ static description = 'Show usage and savings over time for the current org.';
8
+ static flags = {
9
+ granularity: core_1.Flags.string({ description: 'Bucket size', options: ['day', 'hour'], default: 'day' }),
10
+ };
11
+ async run() {
12
+ const { flags } = await this.parse(Usage);
13
+ this.requireToken(flags);
14
+ const res = await this.api(flags).usage(flags.granularity);
15
+ if (this.jsonEnabled())
16
+ return res;
17
+ const points = res.series ?? res.points ?? (Array.isArray(res) ? res : []);
18
+ if (!points.length) {
19
+ this.log('No usage recorded yet.');
20
+ return res;
21
+ }
22
+ this.log((0, output_1.renderTable)(['Bucket', 'Requests', 'Tokens', 'Cost', 'Savings'], points.map((p) => [
23
+ p.bucket ?? p.date ?? p.t ?? '-',
24
+ p.requests ?? p.total_requests ?? '-',
25
+ p.tokens ?? p.total_tokens ?? '-',
26
+ (0, output_1.fmtUsd)(p.cost_usd ?? p.cost_byte_usd),
27
+ (0, output_1.fmtUsd)(p.savings_usd),
28
+ ])));
29
+ return res;
30
+ }
31
+ }
32
+ exports.default = Usage;
@@ -0,0 +1,5 @@
1
+ import { BaseCommand } from '../base';
2
+ export default class Whoami extends BaseCommand {
3
+ static description: string;
4
+ run(): Promise<unknown>;
5
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../base");
4
+ class Whoami extends base_1.BaseCommand {
5
+ static description = 'Show the signed-in identity for the current profile.';
6
+ async run() {
7
+ const { flags } = await this.parse(Whoami);
8
+ this.requireToken(flags);
9
+ const me = await this.api(flags).me();
10
+ if (!this.jsonEnabled()) {
11
+ this.log(`Email: ${me.user?.email ?? '-'}`);
12
+ this.log(`Org: ${me.org?.name ?? '-'} (id ${me.org?.id ?? '-'})`);
13
+ this.log(`Profile: ${this.profileFrom(flags)}`);
14
+ this.log(`API: ${this.baseUrlFrom(flags)}`);
15
+ }
16
+ return me;
17
+ }
18
+ }
19
+ exports.default = Whoami;
@@ -0,0 +1,40 @@
1
+ interface RequestOptions {
2
+ body?: unknown;
3
+ auth?: string;
4
+ }
5
+ export declare class ByteApi {
6
+ private readonly baseUrl;
7
+ private readonly token?;
8
+ constructor(baseUrl: string, token?: string);
9
+ request<T = any>(method: string, path: string, opts?: RequestOptions): Promise<T>;
10
+ deviceStart(clientName: string): Promise<any>;
11
+ deviceToken(deviceCode: string): Promise<any>;
12
+ me(): Promise<any>;
13
+ cliLogout(): Promise<any>;
14
+ sessions(): Promise<any>;
15
+ revokeSession(id: string): Promise<any>;
16
+ createCiToken(name: string): Promise<any>;
17
+ keysList(): Promise<any>;
18
+ keysCreate(body: Record<string, unknown>): Promise<any>;
19
+ keysRevoke(id: number): Promise<any>;
20
+ keysRotate(id: number): Promise<any>;
21
+ providersList(): Promise<any>;
22
+ providersAdd(body: Record<string, unknown>): Promise<any>;
23
+ providersRotate(id: number, apiKey: string): Promise<any>;
24
+ providersTest(id: number): Promise<any>;
25
+ optShow(): Promise<any>;
26
+ optPatch(body: Record<string, unknown>): Promise<any>;
27
+ usage(granularity: string): Promise<any>;
28
+ dashboard(): Promise<any>;
29
+ cacheStats(): Promise<any>;
30
+ costs(): Promise<any>;
31
+ health(): Promise<any>;
32
+ batchList(): Promise<any>;
33
+ batchSubmit(body: Record<string, unknown>): Promise<any>;
34
+ batchGet(id: string): Promise<any>;
35
+ batchRun(id: string): Promise<any>;
36
+ chat(byteKey: string, body: Record<string, unknown>): Promise<any>;
37
+ models(byteKey: string): Promise<any>;
38
+ probeMessages(byteKey: string): Promise<any>;
39
+ }
40
+ export {};
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ByteApi = void 0;
4
+ const errors_1 = require("./errors");
5
+ class ByteApi {
6
+ baseUrl;
7
+ token;
8
+ constructor(baseUrl, token) {
9
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
10
+ this.token = token;
11
+ }
12
+ async request(method, path, opts = {}) {
13
+ const headers = { Accept: 'application/json' };
14
+ const auth = opts.auth ?? this.token;
15
+ if (auth)
16
+ headers.Authorization = `Bearer ${auth}`;
17
+ if (opts.body !== undefined)
18
+ headers['Content-Type'] = 'application/json';
19
+ let res;
20
+ try {
21
+ res = await fetch(`${this.baseUrl}${path}`, {
22
+ method,
23
+ headers,
24
+ body: opts.body === undefined ? undefined : JSON.stringify(opts.body),
25
+ });
26
+ }
27
+ catch (err) {
28
+ const message = err instanceof Error ? err.message : 'network error';
29
+ throw new errors_1.ByteError(`Cannot reach ${this.baseUrl} (${message})`, 'BYTE_API_OFFLINE', 5, 0);
30
+ }
31
+ const text = await res.text();
32
+ let data;
33
+ if (text) {
34
+ try {
35
+ data = JSON.parse(text);
36
+ }
37
+ catch {
38
+ data = text;
39
+ }
40
+ }
41
+ if (!res.ok) {
42
+ const detail = (data && typeof data === 'object' && (data.detail ?? data.error)) || res.statusText;
43
+ const code = typeof detail === 'string' ? detail : 'BYTE_HTTP_ERROR';
44
+ const message = typeof detail === 'string' ? detail : JSON.stringify(detail);
45
+ throw new errors_1.ByteError(message, code, (0, errors_1.exitForStatus)(res.status), res.status);
46
+ }
47
+ return data;
48
+ }
49
+ // --- device auth ---
50
+ deviceStart(clientName) {
51
+ return this.request('POST', '/api/v1/auth/device/start', { body: { client_name: clientName } });
52
+ }
53
+ deviceToken(deviceCode) {
54
+ return this.request('POST', '/api/v1/auth/device/token', { body: { device_code: deviceCode } });
55
+ }
56
+ me() {
57
+ return this.request('GET', '/api/v1/auth/me');
58
+ }
59
+ cliLogout() {
60
+ return this.request('POST', '/api/v1/auth/cli/logout', { body: {} });
61
+ }
62
+ sessions() {
63
+ return this.request('GET', '/api/v1/cli/sessions');
64
+ }
65
+ revokeSession(id) {
66
+ return this.request('DELETE', `/api/v1/cli/sessions/${encodeURIComponent(id)}`);
67
+ }
68
+ createCiToken(name) {
69
+ return this.request('POST', '/api/v1/cli/tokens', { body: { name, scope: 'ci' } });
70
+ }
71
+ // --- Byte keys ---
72
+ keysList() {
73
+ return this.request('GET', '/api/v1/keys');
74
+ }
75
+ keysCreate(body) {
76
+ return this.request('POST', '/api/v1/keys', { body });
77
+ }
78
+ keysRevoke(id) {
79
+ return this.request('DELETE', `/api/v1/keys/${id}`);
80
+ }
81
+ keysRotate(id) {
82
+ return this.request('POST', `/api/v1/keys/${id}/rotate`, { body: {} });
83
+ }
84
+ // --- providers (BYOK) ---
85
+ providersList() {
86
+ return this.request('GET', '/api/v1/model-connections');
87
+ }
88
+ providersAdd(body) {
89
+ return this.request('POST', '/api/v1/model-connections', { body });
90
+ }
91
+ providersRotate(id, apiKey) {
92
+ return this.request('PATCH', `/api/v1/model-connections/${id}`, { body: { api_key: apiKey } });
93
+ }
94
+ providersTest(id) {
95
+ return this.request('POST', `/api/v1/model-connections/${id}/fetch-models`, { body: {} });
96
+ }
97
+ // --- optimizations ---
98
+ optShow() {
99
+ return this.request('GET', '/api/v1/optimizations');
100
+ }
101
+ optPatch(body) {
102
+ return this.request('PATCH', '/api/v1/optimizations', { body });
103
+ }
104
+ // --- observability ---
105
+ usage(granularity) {
106
+ return this.request('GET', `/api/v1/usage/timeseries?granularity=${encodeURIComponent(granularity)}`);
107
+ }
108
+ dashboard() {
109
+ return this.request('GET', '/api/v1/dashboard/summary');
110
+ }
111
+ cacheStats() {
112
+ return this.request('GET', '/api/v1/cache/stats');
113
+ }
114
+ costs() {
115
+ return this.request('GET', '/api/v1/costs/breakdown');
116
+ }
117
+ health() {
118
+ return this.request('GET', '/api/v1/health');
119
+ }
120
+ // --- batch jobs ---
121
+ batchList() {
122
+ return this.request('GET', '/api/v1/batch/jobs');
123
+ }
124
+ batchSubmit(body) {
125
+ return this.request('POST', '/api/v1/batch/jobs', { body });
126
+ }
127
+ batchGet(id) {
128
+ return this.request('GET', `/api/v1/batch/jobs/${encodeURIComponent(id)}`);
129
+ }
130
+ batchRun(id) {
131
+ return this.request('POST', `/api/v1/batch/jobs/${encodeURIComponent(id)}/run`, { body: {} });
132
+ }
133
+ // --- gateway (authenticated with a byte_sk_live_ key, not the control token) ---
134
+ chat(byteKey, body) {
135
+ return this.request('POST', '/v1/chat/completions', { body, auth: byteKey });
136
+ }
137
+ models(byteKey) {
138
+ return this.request('GET', '/v1/models', { auth: byteKey });
139
+ }
140
+ probeMessages(byteKey) {
141
+ return this.request('POST', '/v1/messages', {
142
+ auth: byteKey,
143
+ body: { model: 'byte-default', max_tokens: 1, messages: [{ role: 'user', content: 'ping' }] },
144
+ });
145
+ }
146
+ }
147
+ exports.ByteApi = ByteApi;
@@ -0,0 +1,20 @@
1
+ export declare const DEFAULT_BASE_URL = "https://admin.bytevion.com";
2
+ export declare const DEFAULT_DASHBOARD_URL = "https://admin.bytevion.com";
3
+ export interface Profile {
4
+ base_url: string;
5
+ dashboard_url: string;
6
+ org_id?: number;
7
+ org_name?: string;
8
+ email?: string;
9
+ byte_key_prefix?: string;
10
+ }
11
+ export interface ByteConfig {
12
+ version: number;
13
+ current_profile: string;
14
+ profiles: Record<string, Profile>;
15
+ }
16
+ export declare function loadConfig(): ByteConfig;
17
+ export declare function saveConfig(cfg: ByteConfig): void;
18
+ export declare function profileName(override?: string): string;
19
+ export declare function getProfile(name?: string): Profile;
20
+ export declare function setProfile(name: string, patch: Partial<Profile>): void;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_DASHBOARD_URL = exports.DEFAULT_BASE_URL = void 0;
4
+ exports.loadConfig = loadConfig;
5
+ exports.saveConfig = saveConfig;
6
+ exports.profileName = profileName;
7
+ exports.getProfile = getProfile;
8
+ exports.setProfile = setProfile;
9
+ const node_fs_1 = require("node:fs");
10
+ const paths_1 = require("./paths");
11
+ // Production serves the dashboard, control plane (/api/v1) and gateway (/v1)
12
+ // from a single host. api.bytevion.com is not provisioned, so default to the
13
+ // live host; override per-profile with --base-url or BYTE_BASE_URL.
14
+ exports.DEFAULT_BASE_URL = 'https://admin.bytevion.com';
15
+ exports.DEFAULT_DASHBOARD_URL = 'https://admin.bytevion.com';
16
+ function blankProfile() {
17
+ return { base_url: exports.DEFAULT_BASE_URL, dashboard_url: exports.DEFAULT_DASHBOARD_URL };
18
+ }
19
+ function blankConfig() {
20
+ return { version: 1, current_profile: 'default', profiles: { default: blankProfile() } };
21
+ }
22
+ function loadConfig() {
23
+ try {
24
+ const data = JSON.parse((0, node_fs_1.readFileSync)((0, paths_1.configPath)(), 'utf8'));
25
+ if (!data || typeof data !== 'object' || !data.profiles)
26
+ return blankConfig();
27
+ return data;
28
+ }
29
+ catch {
30
+ return blankConfig();
31
+ }
32
+ }
33
+ function saveConfig(cfg) {
34
+ const path = (0, paths_1.configPath)();
35
+ const tmp = `${path}.tmp`;
36
+ (0, node_fs_1.writeFileSync)(tmp, `${JSON.stringify(cfg, null, 2)}\n`, { mode: 0o600 });
37
+ (0, node_fs_1.renameSync)(tmp, path);
38
+ }
39
+ function profileName(override) {
40
+ return override || process.env.BYTE_PROFILE || loadConfig().current_profile || 'default';
41
+ }
42
+ function getProfile(name) {
43
+ const cfg = loadConfig();
44
+ const key = name || cfg.current_profile || 'default';
45
+ return cfg.profiles[key] || blankProfile();
46
+ }
47
+ function setProfile(name, patch) {
48
+ const cfg = loadConfig();
49
+ cfg.profiles[name] = { ...(cfg.profiles[name] || blankProfile()), ...patch };
50
+ cfg.current_profile = name;
51
+ saveConfig(cfg);
52
+ }
@@ -0,0 +1,5 @@
1
+ export declare function getToken(profile: string): string | undefined;
2
+ export declare function setToken(profile: string, token: string): void;
3
+ export declare function getByteKey(profile: string): string | undefined;
4
+ export declare function setByteKey(profile: string, key: string): void;
5
+ export declare function clearCredentials(profile: string): void;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getToken = getToken;
4
+ exports.setToken = setToken;
5
+ exports.getByteKey = getByteKey;
6
+ exports.setByteKey = setByteKey;
7
+ exports.clearCredentials = clearCredentials;
8
+ const node_fs_1 = require("node:fs");
9
+ const paths_1 = require("./paths");
10
+ function load() {
11
+ try {
12
+ return JSON.parse((0, node_fs_1.readFileSync)((0, paths_1.credentialsPath)(), 'utf8'));
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ }
18
+ function persist(store) {
19
+ const path = (0, paths_1.credentialsPath)();
20
+ const tmp = `${path}.tmp`;
21
+ (0, node_fs_1.writeFileSync)(tmp, JSON.stringify(store), { mode: 0o600 });
22
+ (0, node_fs_1.renameSync)(tmp, path);
23
+ try {
24
+ (0, node_fs_1.chmodSync)(path, 0o600);
25
+ }
26
+ catch {
27
+ // best effort on platforms without POSIX modes
28
+ }
29
+ }
30
+ function getToken(profile) {
31
+ return process.env.BYTE_TOKEN || load()[profile]?.token;
32
+ }
33
+ function setToken(profile, token) {
34
+ const store = load();
35
+ store[profile] = { ...(store[profile] || {}), token };
36
+ persist(store);
37
+ }
38
+ function getByteKey(profile) {
39
+ return process.env.BYTE_API_KEY || load()[profile]?.byte_key;
40
+ }
41
+ function setByteKey(profile, key) {
42
+ const store = load();
43
+ store[profile] = { ...(store[profile] || {}), byte_key: key };
44
+ persist(store);
45
+ }
46
+ function clearCredentials(profile) {
47
+ const store = load();
48
+ delete store[profile];
49
+ persist(store);
50
+ }
@@ -0,0 +1,7 @@
1
+ export declare class ByteError extends Error {
2
+ readonly code: string;
3
+ readonly exit: number;
4
+ readonly status?: number;
5
+ constructor(message: string, code?: string, exit?: number, status?: number);
6
+ }
7
+ export declare function exitForStatus(status: number): number;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ByteError = void 0;
4
+ exports.exitForStatus = exitForStatus;
5
+ // Exit codes (mirrors the dashboard error vocabulary):
6
+ // 0 ok, 2 usage (oclif default), 3 auth, 4 not-configured, 5 offline, 6 upstream
7
+ class ByteError extends Error {
8
+ code;
9
+ exit;
10
+ status;
11
+ constructor(message, code = 'BYTE_ERROR', exit = 1, status) {
12
+ super(message);
13
+ this.name = 'ByteError';
14
+ this.code = code;
15
+ this.exit = exit;
16
+ this.status = status;
17
+ }
18
+ }
19
+ exports.ByteError = ByteError;
20
+ function exitForStatus(status) {
21
+ if (status === 0)
22
+ return 5;
23
+ if (status === 401 || status === 403)
24
+ return 3;
25
+ if (status === 404 || status === 503)
26
+ return 4;
27
+ if (status >= 500)
28
+ return 6;
29
+ return 1;
30
+ }
@@ -0,0 +1,23 @@
1
+ export type Compat = 'openai' | 'anthropic';
2
+ export interface IntegrationContext {
3
+ baseUrl: string;
4
+ byteKey: string;
5
+ }
6
+ export interface SettingsFile {
7
+ path: string;
8
+ apply: (existing: any) => any;
9
+ }
10
+ export interface IntegrationResult {
11
+ env: Array<[string, string]>;
12
+ instructions: string[];
13
+ settingsFile?: SettingsFile;
14
+ }
15
+ export interface Integration {
16
+ key: string;
17
+ aliases: string[];
18
+ title: string;
19
+ compat: Compat;
20
+ build: (ctx: IntegrationContext) => IntegrationResult;
21
+ }
22
+ export declare function listIntegrations(): Integration[];
23
+ export declare function findIntegration(name: string): Integration | undefined;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listIntegrations = listIntegrations;
4
+ exports.findIntegration = findIntegration;
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ const INTEGRATIONS = [
8
+ {
9
+ key: 'claude-code',
10
+ aliases: ['claudecode', 'claude'],
11
+ title: 'Claude Code',
12
+ compat: 'anthropic',
13
+ build: ({ baseUrl, byteKey }) => ({
14
+ env: [
15
+ ['ANTHROPIC_BASE_URL', baseUrl],
16
+ ['ANTHROPIC_AUTH_TOKEN', byteKey],
17
+ ],
18
+ instructions: [
19
+ 'Claude Code reads ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN from its environment',
20
+ 'or from ~/.claude/settings.json. Set the env vars below, or use --write to update',
21
+ 'the settings file. Then start Claude Code as usual.',
22
+ ],
23
+ settingsFile: {
24
+ path: (0, node_path_1.join)((0, node_os_1.homedir)(), '.claude', 'settings.json'),
25
+ apply: (existing) => ({
26
+ ...(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
+ },
32
+ }),
33
+ },
34
+ }),
35
+ },
36
+ {
37
+ key: 'codex',
38
+ aliases: ['codex-cli', 'openai-codex'],
39
+ title: 'Codex CLI',
40
+ compat: 'openai',
41
+ build: ({ baseUrl, byteKey }) => ({
42
+ env: [
43
+ ['OPENAI_BASE_URL', `${baseUrl}/v1`],
44
+ ['OPENAI_API_KEY', byteKey],
45
+ ],
46
+ instructions: [
47
+ 'Codex CLI uses OPENAI_BASE_URL + OPENAI_API_KEY. Set the env vars below',
48
+ '(or add a matching model_provider base_url in ~/.codex/config.toml), then run codex.',
49
+ ],
50
+ }),
51
+ },
52
+ {
53
+ key: 'cursor',
54
+ aliases: [],
55
+ title: 'Cursor',
56
+ compat: 'openai',
57
+ build: ({ baseUrl, byteKey }) => ({
58
+ 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
+ ],
65
+ }),
66
+ },
67
+ {
68
+ key: 'cline',
69
+ aliases: [],
70
+ title: 'Cline (VS Code)',
71
+ compat: 'openai',
72
+ build: ({ baseUrl, byteKey }) => ({
73
+ 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
+ ],
80
+ }),
81
+ },
82
+ {
83
+ key: 'aider',
84
+ aliases: [],
85
+ title: 'Aider',
86
+ compat: 'openai',
87
+ build: ({ baseUrl, byteKey }) => ({
88
+ env: [
89
+ ['OPENAI_API_BASE', `${baseUrl}/v1`],
90
+ ['OPENAI_API_KEY', byteKey],
91
+ ],
92
+ instructions: [
93
+ 'Aider honors OPENAI_API_BASE + OPENAI_API_KEY (or ~/.aider.conf.yml: openai-api-base).',
94
+ 'Set the env vars below, then run e.g. `aider --model openai/<alias>`.',
95
+ ],
96
+ }),
97
+ },
98
+ {
99
+ key: 'openai',
100
+ aliases: ['openai-sdk'],
101
+ title: 'OpenAI SDK',
102
+ compat: 'openai',
103
+ build: ({ baseUrl, byteKey }) => ({
104
+ env: [
105
+ ['OPENAI_BASE_URL', `${baseUrl}/v1`],
106
+ ['OPENAI_API_KEY', byteKey],
107
+ ],
108
+ instructions: [
109
+ 'Python:',
110
+ ` from openai import OpenAI`,
111
+ ` client = OpenAI(base_url="${baseUrl}/v1", api_key="${byteKey}")`,
112
+ 'JavaScript:',
113
+ ` import OpenAI from "openai"`,
114
+ ` const client = new OpenAI({ baseURL: "${baseUrl}/v1", apiKey: "${byteKey}" })`,
115
+ ],
116
+ }),
117
+ },
118
+ {
119
+ key: 'anthropic',
120
+ aliases: ['anthropic-sdk'],
121
+ title: 'Anthropic SDK',
122
+ compat: 'anthropic',
123
+ build: ({ baseUrl, byteKey }) => ({
124
+ env: [
125
+ ['ANTHROPIC_BASE_URL', baseUrl],
126
+ ['ANTHROPIC_AUTH_TOKEN', byteKey],
127
+ ],
128
+ instructions: [
129
+ 'Python:',
130
+ ` from anthropic import Anthropic`,
131
+ ` client = Anthropic(base_url="${baseUrl}", auth_token="${byteKey}")`,
132
+ 'JavaScript:',
133
+ ` import Anthropic from "@anthropic-ai/sdk"`,
134
+ ` const client = new Anthropic({ baseURL: "${baseUrl}", authToken: "${byteKey}" })`,
135
+ ],
136
+ }),
137
+ },
138
+ ];
139
+ function listIntegrations() {
140
+ return INTEGRATIONS;
141
+ }
142
+ function findIntegration(name) {
143
+ const needle = name.toLowerCase();
144
+ return INTEGRATIONS.find((i) => i.key === needle || i.aliases.includes(needle));
145
+ }
@@ -0,0 +1,4 @@
1
+ export declare function renderTable(head: string[], rows: Array<Array<string | number | null | undefined>>): string;
2
+ export declare function maskKey(value: string | undefined): string;
3
+ export declare function fmtUsd(value: unknown): string;
4
+ export declare function pct(value: unknown): string;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderTable = renderTable;
7
+ exports.maskKey = maskKey;
8
+ exports.fmtUsd = fmtUsd;
9
+ exports.pct = pct;
10
+ const cli_table3_1 = __importDefault(require("cli-table3"));
11
+ function renderTable(head, rows) {
12
+ const table = new cli_table3_1.default({ head });
13
+ for (const row of rows) {
14
+ table.push(row.map((cell) => (cell === null || cell === undefined ? '' : String(cell))));
15
+ }
16
+ return table.toString();
17
+ }
18
+ function maskKey(value) {
19
+ if (!value)
20
+ return '';
21
+ if (value.length <= 12)
22
+ return value;
23
+ return `${value.slice(0, 16)}...${value.slice(-4)}`;
24
+ }
25
+ function fmtUsd(value) {
26
+ const n = typeof value === 'number' ? value : Number(value);
27
+ if (!Number.isFinite(n))
28
+ return '-';
29
+ return `$${n.toFixed(n >= 1 ? 2 : 4)}`;
30
+ }
31
+ function pct(value) {
32
+ const n = typeof value === 'number' ? value : Number(value);
33
+ if (!Number.isFinite(n))
34
+ return '-';
35
+ const scaled = n <= 1 ? n * 100 : n;
36
+ return `${scaled.toFixed(1)}%`;
37
+ }
@@ -0,0 +1,3 @@
1
+ export declare function byteDir(): string;
2
+ export declare function configPath(): string;
3
+ export declare function credentialsPath(): string;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.byteDir = byteDir;
4
+ exports.configPath = configPath;
5
+ exports.credentialsPath = credentialsPath;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_os_1 = require("node:os");
8
+ const node_path_1 = require("node:path");
9
+ function byteDir() {
10
+ const dir = process.env.BYTE_HOME || (0, node_path_1.join)((0, node_os_1.homedir)(), '.byte');
11
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
12
+ return dir;
13
+ }
14
+ function configPath() {
15
+ return (0, node_path_1.join)(byteDir(), 'config.json');
16
+ }
17
+ function credentialsPath() {
18
+ return (0, node_path_1.join)(byteDir(), 'credentials.json');
19
+ }
@@ -0,0 +1,4 @@
1
+ export type Shell = 'bash' | 'zsh' | 'fish' | 'powershell' | 'cmd';
2
+ export declare function detectShell(override?: string): Shell;
3
+ export declare function formatEnv(shell: Shell, key: string, value: string): string;
4
+ export declare function formatEnvBlock(shell: Shell, vars: Array<[string, string]>): string;