@bytevion/cli 0.1.0 → 0.2.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/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/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 +201 -0
- package/dist/hooks/init/home.d.ts +3 -0
- package/dist/hooks/init/home.js +95 -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/integrations.d.ts +1 -0
- package/dist/lib/integrations.js +198 -61
- 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 +110 -0
- package/dist/lib/util.d.ts +1 -2
- package/dist/lib/util.js +11 -79
- package/oclif.manifest.json +305 -108
- package/package.json +76 -59
|
@@ -1,8 +1,42 @@
|
|
|
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 base_1 = require("../../base");
|
|
5
|
-
const
|
|
38
|
+
const tty_1 = require("../../lib/tty");
|
|
39
|
+
const ui = __importStar(require("../../lib/ui"));
|
|
6
40
|
class ProvidersRotate extends base_1.BaseCommand {
|
|
7
41
|
static description = 'Replace the upstream API key on a provider connection (keeps imported models).';
|
|
8
42
|
static args = {
|
|
@@ -15,10 +49,11 @@ class ProvidersRotate extends base_1.BaseCommand {
|
|
|
15
49
|
const { args, flags } = await this.parse(ProvidersRotate);
|
|
16
50
|
this.requireToken(flags);
|
|
17
51
|
let apiKey = flags['api-key'];
|
|
52
|
+
if (!apiKey && (0, tty_1.interactive)() && !this.jsonEnabled()) {
|
|
53
|
+
apiKey = await ui.password({ message: 'New upstream provider API key', validate: (v) => (v.trim() ? undefined : 'Required') });
|
|
54
|
+
}
|
|
18
55
|
if (!apiKey)
|
|
19
|
-
|
|
20
|
-
if (!apiKey)
|
|
21
|
-
return this.error('A provider API key is required.', { exit: 2 });
|
|
56
|
+
return this.error('Missing --api-key.', { exit: 2 });
|
|
22
57
|
const res = await this.api(flags).providersRotate(args.id, apiKey);
|
|
23
58
|
if (!this.jsonEnabled())
|
|
24
59
|
this.log(`Rotated provider key on connection ${args.id} (now ****${res.secret_last4 ?? '????'}).`);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../base';
|
|
2
|
+
export default class Setup extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static aliases: string[];
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
provider: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
'provider-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
'provider-base-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
mode: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
preset: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
'key-name': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
'skip-provider': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
connect: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<unknown>;
|
|
17
|
+
private connectProvider;
|
|
18
|
+
private runNonInteractive;
|
|
19
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
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 auth_1 = require("../lib/auth");
|
|
39
|
+
const credentials_1 = require("../lib/credentials");
|
|
40
|
+
const providers_1 = require("../lib/providers");
|
|
41
|
+
const tty_1 = require("../lib/tty");
|
|
42
|
+
const ui = __importStar(require("../lib/ui"));
|
|
43
|
+
class Setup extends base_1.BaseCommand {
|
|
44
|
+
static description = 'Guided setup: sign in, connect a provider, create a Byte key, and wire a tool.';
|
|
45
|
+
static aliases = ['init', 'onboard'];
|
|
46
|
+
static examples = ['<%= config.bin %> setup', '<%= config.bin %> setup --provider deepseek --provider-key sk-... --connect opencode --json'];
|
|
47
|
+
static flags = {
|
|
48
|
+
provider: core_1.Flags.string({ description: 'Provider preset id (openai, deepseek, anthropic, …)' }),
|
|
49
|
+
'provider-key': core_1.Flags.string({ description: 'Upstream provider API key', env: 'BYTE_PROVIDER_KEY' }),
|
|
50
|
+
'provider-base-url': core_1.Flags.string({ description: 'Custom provider base URL (for --provider custom)' }),
|
|
51
|
+
mode: core_1.Flags.string({ description: 'Gateway mode override (byte_compatible/byte_messages/byte_generative)' }),
|
|
52
|
+
preset: core_1.Flags.string({
|
|
53
|
+
description: 'Optimization preset',
|
|
54
|
+
options: ['balanced', 'max_savings', 'lowest_latency', 'reliability_first'],
|
|
55
|
+
default: 'balanced',
|
|
56
|
+
}),
|
|
57
|
+
'key-name': core_1.Flags.string({ description: 'Name for the Byte key', default: 'cli' }),
|
|
58
|
+
'skip-provider': core_1.Flags.boolean({ description: 'Skip connecting a provider' }),
|
|
59
|
+
connect: core_1.Flags.string({ description: 'Tool to wire after setup (e.g. opencode, codex)' }),
|
|
60
|
+
};
|
|
61
|
+
async run() {
|
|
62
|
+
const { flags } = await this.parse(Setup);
|
|
63
|
+
const profile = this.profileFrom(flags);
|
|
64
|
+
const base = this.baseUrlFrom(flags);
|
|
65
|
+
if (this.jsonEnabled() || !(0, tty_1.interactive)()) {
|
|
66
|
+
return this.runNonInteractive(flags, profile, base);
|
|
67
|
+
}
|
|
68
|
+
await ui.intro(ui.banner());
|
|
69
|
+
// 1) Sign in
|
|
70
|
+
let token = (0, credentials_1.getToken)(profile);
|
|
71
|
+
const api = this.api(flags);
|
|
72
|
+
if (token) {
|
|
73
|
+
try {
|
|
74
|
+
const me = await api.me();
|
|
75
|
+
await ui.log.info(`Signed in as ${me.user?.email ?? 'you'}`);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
token = undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!token) {
|
|
82
|
+
await (0, auth_1.deviceLogin)({ baseUrl: base, profile });
|
|
83
|
+
}
|
|
84
|
+
// 2) Connect a provider
|
|
85
|
+
let chosenAlias;
|
|
86
|
+
if (!flags['skip-provider']) {
|
|
87
|
+
const existing = await api.providersList().catch(() => ({ connections: [] }));
|
|
88
|
+
const conns = existing.connections ?? (Array.isArray(existing) ? existing : []);
|
|
89
|
+
let addNew = true;
|
|
90
|
+
if (conns.length) {
|
|
91
|
+
addNew = (await ui.select({
|
|
92
|
+
message: 'Provider',
|
|
93
|
+
options: [
|
|
94
|
+
{ value: 'existing', label: `Use existing connection (${conns.length})` },
|
|
95
|
+
{ value: 'new', label: 'Connect a new provider' },
|
|
96
|
+
],
|
|
97
|
+
})) === 'new';
|
|
98
|
+
}
|
|
99
|
+
if (addNew) {
|
|
100
|
+
chosenAlias = await this.connectProvider(api, flags);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 3) Create a Byte key
|
|
104
|
+
let byteKey = (0, credentials_1.getByteKey)(profile);
|
|
105
|
+
if (!byteKey) {
|
|
106
|
+
const name = await ui.text({ message: 'Name this Byte key', defaultValue: flags['key-name'] || 'cli' });
|
|
107
|
+
const res = await api.keysCreate({ name: name || 'cli', preset: flags.preset });
|
|
108
|
+
const created = String(res.key);
|
|
109
|
+
(0, credentials_1.setByteKey)(profile, created);
|
|
110
|
+
await ui.revealSecret('Your Byte API key', created);
|
|
111
|
+
}
|
|
112
|
+
// 4) Optimization preset
|
|
113
|
+
await api.optPatch({ default_mode: flags.preset }).catch(() => undefined);
|
|
114
|
+
await ui.log.success(`Optimizations: ${flags.preset} preset applied`);
|
|
115
|
+
// 5) Connect a tool
|
|
116
|
+
const connect = await ui.select({
|
|
117
|
+
message: 'Connect a coding tool now?',
|
|
118
|
+
options: [
|
|
119
|
+
{ value: 'skip', label: 'Skip for now' },
|
|
120
|
+
{ value: 'opencode', label: 'opencode' },
|
|
121
|
+
{ value: 'claude-code', label: 'Claude Code' },
|
|
122
|
+
{ value: 'codex', label: 'Codex CLI' },
|
|
123
|
+
{ value: 'cursor', label: 'Cursor' },
|
|
124
|
+
{ value: 'cline', label: 'Cline' },
|
|
125
|
+
{ value: 'aider', label: 'Aider' },
|
|
126
|
+
],
|
|
127
|
+
});
|
|
128
|
+
if (connect !== 'skip') {
|
|
129
|
+
const argv = [connect, '--write', '--yes', ...(chosenAlias ? ['--model', chosenAlias] : [])];
|
|
130
|
+
await this.config.runCommand('integrate', argv);
|
|
131
|
+
}
|
|
132
|
+
await ui.outro(`${ui.theme.ok('Setup complete.')} Next: ${ui.theme.accent('byte run "hello from byte"')} · ${ui.theme.accent('byte usage')}`);
|
|
133
|
+
return { status: 'setup_complete', profile, model: chosenAlias };
|
|
134
|
+
}
|
|
135
|
+
async connectProvider(api, flags) {
|
|
136
|
+
const providerId = await ui.select({
|
|
137
|
+
message: 'Which provider?',
|
|
138
|
+
options: providers_1.PROVIDER_PRESETS.map((p) => ({ value: p.id, label: p.label, hint: p.advanced ? 'advanced' : undefined })),
|
|
139
|
+
});
|
|
140
|
+
const preset = (0, providers_1.findPreset)(providerId);
|
|
141
|
+
let baseUrl = preset.base_url;
|
|
142
|
+
if (preset.custom || !baseUrl) {
|
|
143
|
+
baseUrl = await ui.text({
|
|
144
|
+
message: 'Provider base URL',
|
|
145
|
+
placeholder: 'https://api.example.com/v1',
|
|
146
|
+
validate: (v) => (v.startsWith('http') ? undefined : 'Must be a URL'),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (preset.advanced && preset.note)
|
|
150
|
+
await ui.log.warn(preset.note);
|
|
151
|
+
const key = await ui.password({ message: `${preset.label} API key`, validate: (v) => (v.trim() ? undefined : 'Required') });
|
|
152
|
+
const spin = await ui.spinner();
|
|
153
|
+
spin.start(`Connecting ${preset.label}…`);
|
|
154
|
+
try {
|
|
155
|
+
const res = await api.providersAdd({ api_key: key, gateway_mode: flags.mode || preset.gateway_mode, base_url: baseUrl, auto_fetch: true });
|
|
156
|
+
const models = res.fetch_result?.models ?? res.models ?? [];
|
|
157
|
+
spin.stop(`Connected ${preset.label} — ${models.length} model(s) imported.`);
|
|
158
|
+
if (models.length) {
|
|
159
|
+
return ui.select({
|
|
160
|
+
message: 'Default model',
|
|
161
|
+
options: models.slice(0, 50).map((m) => ({ value: m.byte_alias, label: m.byte_alias, hint: m.model_id })),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
spin.stop('Provider connection failed.');
|
|
167
|
+
await ui.log.error(err?.message ?? String(err));
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
async runNonInteractive(flags, profile, base) {
|
|
172
|
+
this.requireToken(flags);
|
|
173
|
+
const api = this.api(flags);
|
|
174
|
+
let imported = 0;
|
|
175
|
+
let chosenAlias;
|
|
176
|
+
const key = flags['provider-key'];
|
|
177
|
+
if (key && !flags['skip-provider']) {
|
|
178
|
+
const preset = flags.provider ? (0, providers_1.findPreset)(flags.provider) : undefined;
|
|
179
|
+
const baseUrl = flags['provider-base-url'] || preset?.base_url;
|
|
180
|
+
const mode = flags.mode || preset?.gateway_mode || 'byte_compatible';
|
|
181
|
+
if (!baseUrl) {
|
|
182
|
+
return this.error('Provide --provider <preset> or --provider-base-url for the upstream provider.', { exit: 2 });
|
|
183
|
+
}
|
|
184
|
+
const res = await api.providersAdd({ api_key: key, gateway_mode: mode, base_url: baseUrl, auto_fetch: true });
|
|
185
|
+
imported = res.fetch_result?.imported ?? res.imported ?? 0;
|
|
186
|
+
chosenAlias = res.fetch_result?.models?.[0]?.byte_alias;
|
|
187
|
+
}
|
|
188
|
+
await api.optPatch({ default_mode: flags.preset }).catch(() => undefined);
|
|
189
|
+
const keyRes = await api.keysCreate({ name: flags['key-name'] || 'cli', preset: flags.preset });
|
|
190
|
+
(0, credentials_1.setByteKey)(profile, keyRes.key);
|
|
191
|
+
if (flags.connect) {
|
|
192
|
+
await this.config.runCommand('integrate', [flags.connect, '--write', '--yes', ...(chosenAlias ? ['--model', chosenAlias] : [])]);
|
|
193
|
+
}
|
|
194
|
+
if (!this.jsonEnabled()) {
|
|
195
|
+
this.log(`Byte key: ${keyRes.key}`);
|
|
196
|
+
this.log(`Provider models imported: ${imported}`);
|
|
197
|
+
}
|
|
198
|
+
return { byte_key: keyRes.key, provider_models_imported: imported, preset: flags.preset, model: chosenAlias };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.default = Setup;
|
|
@@ -0,0 +1,95 @@
|
|
|
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 config_1 = require("../../lib/config");
|
|
37
|
+
const credentials_1 = require("../../lib/credentials");
|
|
38
|
+
const tty_1 = require("../../lib/tty");
|
|
39
|
+
const ui = __importStar(require("../../lib/ui"));
|
|
40
|
+
// oclif runs init hooks before it would print help. Bare `byte` (no command) in a real
|
|
41
|
+
// terminal opens an interactive home menu; anything else (a command, a pipe, CI, --help)
|
|
42
|
+
// returns and lets oclif behave normally.
|
|
43
|
+
const hook = async function (opts) {
|
|
44
|
+
if (opts.id !== undefined)
|
|
45
|
+
return;
|
|
46
|
+
const argv = opts.argv ?? [];
|
|
47
|
+
if (argv.length > 0)
|
|
48
|
+
return;
|
|
49
|
+
if (!(0, tty_1.interactive)())
|
|
50
|
+
return;
|
|
51
|
+
const profile = (0, config_1.profileName)();
|
|
52
|
+
const prof = (0, config_1.getProfile)(profile);
|
|
53
|
+
const signedIn = Boolean((0, credentials_1.getToken)(profile));
|
|
54
|
+
const status = signedIn ? ui.theme.muted(`signed in · ${prof.email ?? prof.org_name ?? profile}`) : ui.theme.muted('not signed in');
|
|
55
|
+
await ui.intro(`${ui.banner()} ${status}`);
|
|
56
|
+
const choice = await ui.select({
|
|
57
|
+
message: 'What would you like to do?',
|
|
58
|
+
initialValue: signedIn ? 'setup' : 'login',
|
|
59
|
+
options: [
|
|
60
|
+
{ value: 'setup', label: 'Set up Byte', hint: 'guided' },
|
|
61
|
+
{ value: 'providers:add', label: 'Connect a provider' },
|
|
62
|
+
{ value: 'keys:create', label: 'Create a Byte key' },
|
|
63
|
+
{ value: 'integrate', label: 'Connect a tool' },
|
|
64
|
+
{ value: 'run', label: 'Run a test prompt' },
|
|
65
|
+
{ value: 'compare', label: 'Compare direct vs Byte', hint: 'prove the win' },
|
|
66
|
+
{ value: 'usage', label: 'View usage' },
|
|
67
|
+
{ value: signedIn ? 'logout' : 'login', label: signedIn ? 'Sign out' : 'Sign in' },
|
|
68
|
+
{ value: 'exit', label: 'Exit' },
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
if (choice === 'exit') {
|
|
72
|
+
await ui.outro('Bye.');
|
|
73
|
+
await this.exit(0);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let cmdId = choice;
|
|
77
|
+
let cmdArgv = [];
|
|
78
|
+
if (choice === 'run') {
|
|
79
|
+
const prompt = await ui.text({ message: 'Prompt', placeholder: 'hello from byte', defaultValue: 'hello from byte' });
|
|
80
|
+
cmdId = 'run';
|
|
81
|
+
cmdArgv = [prompt || 'hello from byte'];
|
|
82
|
+
}
|
|
83
|
+
else if (choice === 'compare') {
|
|
84
|
+
const prompt = await ui.text({ message: 'Prompt to compare', placeholder: 'Summarize the latest changes', defaultValue: 'Summarize the latest changes' });
|
|
85
|
+
cmdId = 'compare';
|
|
86
|
+
cmdArgv = [prompt || 'Summarize the latest changes'];
|
|
87
|
+
}
|
|
88
|
+
else if (choice === 'keys:create') {
|
|
89
|
+
const name = await ui.text({ message: 'Key name', defaultValue: 'cli' });
|
|
90
|
+
cmdArgv = [name || 'cli'];
|
|
91
|
+
}
|
|
92
|
+
await this.config.runCommand(cmdId, cmdArgv);
|
|
93
|
+
await this.exit(0);
|
|
94
|
+
};
|
|
95
|
+
exports.default = hook;
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -36,5 +36,6 @@ export declare class ByteApi {
|
|
|
36
36
|
chat(byteKey: string, body: Record<string, unknown>): Promise<any>;
|
|
37
37
|
models(byteKey: string): Promise<any>;
|
|
38
38
|
probeMessages(byteKey: string): Promise<any>;
|
|
39
|
+
compareStream(body: Record<string, unknown>): AsyncGenerator<any>;
|
|
39
40
|
}
|
|
40
41
|
export {};
|
package/dist/lib/api.js
CHANGED
|
@@ -143,5 +143,65 @@ class ByteApi {
|
|
|
143
143
|
body: { model: 'byte-default', max_tokens: 1, messages: [{ role: 'user', content: 'ping' }] },
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
|
+
// --- compare (direct vs Byte) — Server-Sent Events ---
|
|
147
|
+
async *compareStream(body) {
|
|
148
|
+
let res;
|
|
149
|
+
try {
|
|
150
|
+
res = await fetch(`${this.baseUrl}/api/v1/compare/chat`, {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
headers: {
|
|
153
|
+
...(this.token ? { Authorization: `Bearer ${this.token}` } : {}),
|
|
154
|
+
'Content-Type': 'application/json',
|
|
155
|
+
Accept: 'text/event-stream',
|
|
156
|
+
},
|
|
157
|
+
body: JSON.stringify(body),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
const message = err instanceof Error ? err.message : 'network error';
|
|
162
|
+
throw new errors_1.ByteError(`Cannot reach ${this.baseUrl} (${message})`, 'BYTE_API_OFFLINE', 5, 0);
|
|
163
|
+
}
|
|
164
|
+
if (!res.ok) {
|
|
165
|
+
const text = await res.text().catch(() => '');
|
|
166
|
+
let detail = res.statusText;
|
|
167
|
+
try {
|
|
168
|
+
detail = JSON.parse(text).detail ?? detail;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
/* keep statusText */
|
|
172
|
+
}
|
|
173
|
+
const code = typeof detail === 'string' ? detail : 'BYTE_HTTP_ERROR';
|
|
174
|
+
throw new errors_1.ByteError(typeof detail === 'string' ? detail : JSON.stringify(detail), code, (0, errors_1.exitForStatus)(res.status), res.status);
|
|
175
|
+
}
|
|
176
|
+
const reader = res.body?.getReader();
|
|
177
|
+
if (!reader)
|
|
178
|
+
return;
|
|
179
|
+
const decoder = new TextDecoder();
|
|
180
|
+
let buffer = '';
|
|
181
|
+
for (;;) {
|
|
182
|
+
const { value, done } = await reader.read();
|
|
183
|
+
if (done)
|
|
184
|
+
break;
|
|
185
|
+
buffer += decoder.decode(value, { stream: true });
|
|
186
|
+
const parts = buffer.split('\n\n');
|
|
187
|
+
buffer = parts.pop() ?? '';
|
|
188
|
+
for (const part of parts) {
|
|
189
|
+
for (const line of part.split('\n')) {
|
|
190
|
+
const trimmed = line.trim();
|
|
191
|
+
if (!trimmed.startsWith('data:'))
|
|
192
|
+
continue;
|
|
193
|
+
const raw = trimmed.slice(5).trim();
|
|
194
|
+
if (!raw || raw === '[DONE]')
|
|
195
|
+
continue;
|
|
196
|
+
try {
|
|
197
|
+
yield JSON.parse(raw);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
/* ignore non-JSON keepalives */
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
146
206
|
}
|
|
147
207
|
exports.ByteApi = ByteApi;
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
exports.deviceLogin = deviceLogin;
|
|
37
|
+
const node_os_1 = require("node:os");
|
|
38
|
+
const api_1 = require("./api");
|
|
39
|
+
const config_1 = require("./config");
|
|
40
|
+
const credentials_1 = require("./credentials");
|
|
41
|
+
const errors_1 = require("./errors");
|
|
42
|
+
const ui = __importStar(require("./ui"));
|
|
43
|
+
const util_1 = require("./util");
|
|
44
|
+
// Device-code login loop shared by `byte login` and the setup wizard. Prints the
|
|
45
|
+
// user code, opens the browser, and polls with backoff until approved/denied/expired.
|
|
46
|
+
async function deviceLogin(opts) {
|
|
47
|
+
const api = new api_1.ByteApi(opts.baseUrl);
|
|
48
|
+
const start = await api.deviceStart(`byte-cli@${(0, node_os_1.hostname)()}`);
|
|
49
|
+
const verifyUrl = start.verification_uri_complete || start.verification_uri;
|
|
50
|
+
await ui.note(`${ui.theme.bold(start.user_code)}\n\n${verifyUrl}`, 'Approve this device in your browser');
|
|
51
|
+
if (!opts.noBrowser) {
|
|
52
|
+
try {
|
|
53
|
+
await (0, util_1.openBrowser)(verifyUrl);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// user can open the URL manually
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const spin = await ui.spinner();
|
|
60
|
+
spin.start('Waiting for approval…');
|
|
61
|
+
let interval = (Number(start.interval) || 5) * 1000;
|
|
62
|
+
const deadline = Date.now() + (Number(start.expires_in) || 600) * 1000;
|
|
63
|
+
while (Date.now() < deadline) {
|
|
64
|
+
await (0, util_1.sleep)(interval);
|
|
65
|
+
try {
|
|
66
|
+
const tok = await api.deviceToken(start.device_code);
|
|
67
|
+
(0, credentials_1.setToken)(opts.profile, tok.access_token);
|
|
68
|
+
(0, config_1.setProfile)(opts.profile, {
|
|
69
|
+
base_url: opts.baseUrl,
|
|
70
|
+
dashboard_url: (0, config_1.getProfile)(opts.profile).dashboard_url || config_1.DEFAULT_DASHBOARD_URL,
|
|
71
|
+
org_id: tok.org?.id,
|
|
72
|
+
org_name: tok.org?.name,
|
|
73
|
+
email: tok.user?.email,
|
|
74
|
+
});
|
|
75
|
+
spin.stop('Signed in.');
|
|
76
|
+
return { email: tok.user?.email, org: tok.org?.name };
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const code = err instanceof errors_1.ByteError ? err.code : '';
|
|
80
|
+
if (code === 'authorization_pending')
|
|
81
|
+
continue;
|
|
82
|
+
if (code === 'slow_down') {
|
|
83
|
+
interval += 5000;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (code === 'access_denied') {
|
|
87
|
+
spin.stop('Authorization denied.');
|
|
88
|
+
throw new errors_1.ByteError('Authorization was denied in the dashboard.', 'BYTE_AUTH_DENIED', 3);
|
|
89
|
+
}
|
|
90
|
+
if (code === 'expired_token') {
|
|
91
|
+
spin.stop('Code expired.');
|
|
92
|
+
throw new errors_1.ByteError('The verification code expired. Run `byte login` again.', 'BYTE_AUTH_EXPIRED', 3);
|
|
93
|
+
}
|
|
94
|
+
spin.stop('Login failed.');
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
spin.stop('Timed out.');
|
|
99
|
+
throw new errors_1.ByteError('Login timed out. Run `byte login` again.', 'BYTE_AUTH_TIMEOUT', 3);
|
|
100
|
+
}
|