@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
package/bin/run.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+
3
+ // CommonJS entry. @oclif/core ships as ESM, so load it via dynamic import.
4
+ ;(async () => {
5
+ const { execute } = await import('@oclif/core')
6
+ await execute({ dir: __dirname })
7
+ })()
package/dist/base.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { Command } from '@oclif/core';
2
+ import { ByteApi } from './lib/api';
3
+ export declare abstract class BaseCommand extends Command {
4
+ static enableJsonFlag: boolean;
5
+ static baseFlags: {
6
+ profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ 'base-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ protected profileFrom(flags: Record<string, any>): string;
10
+ protected baseUrlFrom(flags: Record<string, any>): string;
11
+ protected api(flags: Record<string, any>, opts?: {
12
+ auth?: boolean;
13
+ }): ByteApi;
14
+ protected requireToken(flags: Record<string, any>): string;
15
+ protected requireByteKey(flags: Record<string, any>): string;
16
+ protected optionalByteKey(flags: Record<string, any>): string | undefined;
17
+ protected catch(err: Error & {
18
+ exitCode?: number;
19
+ }): Promise<unknown>;
20
+ }
package/dist/base.js ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseCommand = void 0;
4
+ const core_1 = require("@oclif/core");
5
+ const api_1 = require("./lib/api");
6
+ const config_1 = require("./lib/config");
7
+ const credentials_1 = require("./lib/credentials");
8
+ const errors_1 = require("./lib/errors");
9
+ class BaseCommand extends core_1.Command {
10
+ static enableJsonFlag = true;
11
+ static baseFlags = {
12
+ profile: core_1.Flags.string({ description: 'Configuration profile to use', env: 'BYTE_PROFILE' }),
13
+ 'base-url': core_1.Flags.string({ description: 'Override the API base URL', env: 'BYTE_BASE_URL' }),
14
+ };
15
+ profileFrom(flags) {
16
+ return (0, config_1.profileName)(flags.profile);
17
+ }
18
+ baseUrlFrom(flags) {
19
+ return flags['base-url'] || (0, config_1.getProfile)(this.profileFrom(flags)).base_url || config_1.DEFAULT_BASE_URL;
20
+ }
21
+ api(flags, opts = {}) {
22
+ const token = opts.auth === false ? undefined : (0, credentials_1.getToken)(this.profileFrom(flags));
23
+ return new api_1.ByteApi(this.baseUrlFrom(flags), token);
24
+ }
25
+ requireToken(flags) {
26
+ const stored = (0, credentials_1.getToken)(this.profileFrom(flags));
27
+ if (!stored) {
28
+ throw new errors_1.ByteError('Not signed in. Run `byte login` first.', 'BYTE_AUTH_REQUIRED', 3);
29
+ }
30
+ return stored;
31
+ }
32
+ requireByteKey(flags) {
33
+ const key = (0, credentials_1.getByteKey)(this.profileFrom(flags));
34
+ if (!key) {
35
+ throw new errors_1.ByteError('No Byte API key for this profile. Run `byte init` or `byte keys create`.', 'BYTE_KEY_REQUIRED', 4);
36
+ }
37
+ return key;
38
+ }
39
+ optionalByteKey(flags) {
40
+ return (0, credentials_1.getByteKey)(this.profileFrom(flags));
41
+ }
42
+ async catch(err) {
43
+ if (err instanceof errors_1.ByteError) {
44
+ return this.error(err.message, { code: err.code, exit: err.exit });
45
+ }
46
+ return super.catch(err);
47
+ }
48
+ }
49
+ exports.BaseCommand = BaseCommand;
@@ -0,0 +1,5 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class BatchList extends BaseCommand {
3
+ static description: string;
4
+ run(): Promise<unknown>;
5
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../../base");
4
+ const output_1 = require("../../lib/output");
5
+ class BatchList extends base_1.BaseCommand {
6
+ static description = 'List recent batch jobs for the current org.';
7
+ async run() {
8
+ const { flags } = await this.parse(BatchList);
9
+ this.requireToken(flags);
10
+ const res = await this.api(flags).batchList();
11
+ const jobs = res.jobs ?? res ?? [];
12
+ if (this.jsonEnabled())
13
+ return jobs;
14
+ if (!jobs.length) {
15
+ this.log('No batch jobs yet. Submit one with `byte batch submit <file>`.');
16
+ return jobs;
17
+ }
18
+ this.log((0, output_1.renderTable)(['Job ID', 'Status', 'Model', 'Created'], jobs.map((j) => [j.id, j.status, j.model, j.created_at ?? '-'])));
19
+ return jobs;
20
+ }
21
+ }
22
+ exports.default = BatchList;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class BatchPoll extends BaseCommand {
3
+ static description: string;
4
+ static args: {
5
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ run: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ watch: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ interval: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,42 @@
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 util_1 = require("../../lib/util");
6
+ const PENDING = new Set(['queued', 'running', 'processing', 'pending']);
7
+ class BatchPoll extends base_1.BaseCommand {
8
+ static description = 'Show a batch job, optionally starting it and/or watching until it finishes.';
9
+ static args = {
10
+ id: core_1.Args.string({ description: 'Job id (see `byte batch list`)', required: true }),
11
+ };
12
+ static flags = {
13
+ run: core_1.Flags.boolean({ description: 'Start the job before polling' }),
14
+ watch: core_1.Flags.boolean({ description: 'Poll until the job leaves a pending state' }),
15
+ interval: core_1.Flags.integer({ description: 'Seconds between polls when watching', default: 3 }),
16
+ };
17
+ async run() {
18
+ const { args, flags } = await this.parse(BatchPoll);
19
+ this.requireToken(flags);
20
+ const api = this.api(flags);
21
+ let job = flags.run ? (await api.batchRun(args.id)).job : (await api.batchGet(args.id)).job;
22
+ while (flags.watch && job && PENDING.has(String(job.status))) {
23
+ // eslint-disable-next-line no-await-in-loop
24
+ await (0, util_1.sleep)(Math.max(1, flags.interval) * 1000);
25
+ // eslint-disable-next-line no-await-in-loop
26
+ job = (await api.batchGet(args.id)).job;
27
+ if (!this.jsonEnabled())
28
+ this.log(` status: ${job?.status}`);
29
+ }
30
+ if (this.jsonEnabled())
31
+ return job;
32
+ this.log(`Job ${args.id}: ${job?.status}`);
33
+ if (job?.error_code)
34
+ this.log(`Error: ${job.error_code}`);
35
+ if (job?.result_content) {
36
+ this.log('');
37
+ this.log(job.result_content);
38
+ }
39
+ return job;
40
+ }
41
+ }
42
+ exports.default = BatchPoll;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class BatchSubmit extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ file: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ model: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ 'auto-start': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const node_fs_1 = require("node:fs");
5
+ const base_1 = require("../../base");
6
+ const output_1 = require("../../lib/output");
7
+ function normalizeSpec(item) {
8
+ if (Array.isArray(item))
9
+ return { messages: item };
10
+ if (item && Array.isArray(item.messages))
11
+ return { model: item.model, messages: item.messages };
12
+ throw new Error('Each job must be a messages array or an object with a "messages" array.');
13
+ }
14
+ function parseSpecs(raw) {
15
+ const trimmed = raw.trim();
16
+ try {
17
+ const data = JSON.parse(trimmed);
18
+ if (Array.isArray(data) && data.length > 0 && data[0]?.role)
19
+ return [{ messages: data }];
20
+ if (Array.isArray(data))
21
+ return data.map(normalizeSpec);
22
+ return [normalizeSpec(data)];
23
+ }
24
+ catch {
25
+ // fall through to JSONL parsing
26
+ }
27
+ const specs = [];
28
+ for (const line of trimmed.split(/\r?\n/)) {
29
+ const l = line.trim();
30
+ if (l)
31
+ specs.push(normalizeSpec(JSON.parse(l)));
32
+ }
33
+ return specs;
34
+ }
35
+ class BatchSubmit extends base_1.BaseCommand {
36
+ static description = 'Submit offline batch job(s) from a JSON/JSONL file (one conversation per job).';
37
+ static examples = ['<%= config.bin %> batch submit jobs.jsonl --auto-start'];
38
+ static args = {
39
+ file: core_1.Args.string({ description: 'Path to a .json or .jsonl file of jobs', required: true }),
40
+ };
41
+ static flags = {
42
+ model: core_1.Flags.string({ description: 'Default model/alias for jobs that omit one' }),
43
+ 'auto-start': core_1.Flags.boolean({ description: 'Run jobs immediately after submitting' }),
44
+ };
45
+ async run() {
46
+ const { args, flags } = await this.parse(BatchSubmit);
47
+ this.requireToken(flags);
48
+ let specs;
49
+ try {
50
+ specs = parseSpecs((0, node_fs_1.readFileSync)(args.file, 'utf8'));
51
+ }
52
+ catch (err) {
53
+ return this.error(`Invalid batch file: ${err?.message ?? err}`, { exit: 2 });
54
+ }
55
+ if (!specs.length)
56
+ return this.error('No job specs found in file.', { exit: 2 });
57
+ const api = this.api(flags);
58
+ const created = [];
59
+ for (const spec of specs) {
60
+ const body = { messages: spec.messages, auto_start: Boolean(flags['auto-start']) };
61
+ if (spec.model || flags.model)
62
+ body.model = spec.model || flags.model;
63
+ // sequential on purpose: keeps ordering stable and surfaces the first failure clearly
64
+ // eslint-disable-next-line no-await-in-loop
65
+ const res = await api.batchSubmit(body);
66
+ created.push(res.job ?? res);
67
+ }
68
+ if (this.jsonEnabled())
69
+ return created;
70
+ this.log((0, output_1.renderTable)(['Job ID', 'Status', 'Model'], created.map((j) => [j.id, j.status, j.model])));
71
+ return created;
72
+ }
73
+ }
74
+ exports.default = BatchSubmit;
@@ -0,0 +1,5 @@
1
+ import { BaseCommand } from '../base';
2
+ export default class Doctor extends BaseCommand {
3
+ static description: string;
4
+ run(): Promise<unknown>;
5
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../base");
4
+ const credentials_1 = require("../lib/credentials");
5
+ class Doctor extends base_1.BaseCommand {
6
+ static description = 'Check connectivity, auth, provider, and gateway health in one shot.';
7
+ async run() {
8
+ const { flags } = await this.parse(Doctor);
9
+ const profile = this.profileFrom(flags);
10
+ const api = this.api(flags);
11
+ const checks = [];
12
+ const base = this.baseUrlFrom(flags);
13
+ checks.push({ name: 'API base URL', ok: true, detail: base });
14
+ try {
15
+ const h = await api.health();
16
+ checks.push({ name: 'API reachable', ok: true, detail: String(h.status ?? 'ok') });
17
+ }
18
+ catch (err) {
19
+ checks.push({ name: 'API reachable', ok: false, detail: err?.message ?? 'unreachable' });
20
+ }
21
+ const token = (0, credentials_1.getToken)(profile);
22
+ if (token) {
23
+ try {
24
+ const me = await api.me();
25
+ checks.push({ name: 'Authenticated', ok: true, detail: `${me.user?.email} / ${me.org?.name}` });
26
+ }
27
+ catch (err) {
28
+ checks.push({ name: 'Authenticated', ok: false, detail: err?.message ?? 'invalid token' });
29
+ }
30
+ try {
31
+ const p = await api.providersList();
32
+ const n = (p.connections ?? p ?? []).length;
33
+ checks.push({ name: 'Provider configured', ok: n > 0, detail: `${n} connection(s)` });
34
+ }
35
+ catch (err) {
36
+ checks.push({ name: 'Provider configured', ok: false, detail: err?.message ?? 'error' });
37
+ }
38
+ }
39
+ else {
40
+ checks.push({ name: 'Authenticated', ok: false, detail: 'no token — run `byte login`' });
41
+ }
42
+ const key = (0, credentials_1.getByteKey)(profile);
43
+ if (key) {
44
+ try {
45
+ await api.models(key);
46
+ checks.push({ name: 'Gateway key valid', ok: true, detail: 'byte key accepted' });
47
+ }
48
+ catch (err) {
49
+ checks.push({ name: 'Gateway key valid', ok: err?.status !== 401, detail: err?.message ?? 'error' });
50
+ }
51
+ }
52
+ else {
53
+ checks.push({ name: 'Gateway key', ok: false, detail: 'no Byte key — run `byte keys create`' });
54
+ }
55
+ const healthy = checks.every((c) => c.ok);
56
+ if (!this.jsonEnabled()) {
57
+ for (const c of checks)
58
+ this.log(`${c.ok ? 'OK ' : 'FAIL'} ${c.name}: ${c.detail}`);
59
+ }
60
+ if (!healthy)
61
+ process.exitCode = 4;
62
+ return { healthy, checks };
63
+ }
64
+ }
65
+ exports.default = Doctor;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../base';
2
+ export default class Env extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ shell: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ sdk: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,35 @@
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 shell_1 = require("../lib/shell");
6
+ class Env extends base_1.BaseCommand {
7
+ static description = 'Print shell environment exports that point an SDK or tool at Byte.';
8
+ static examples = [
9
+ 'eval "$(<%= config.bin %> env)"',
10
+ '<%= config.bin %> env --sdk anthropic --shell powershell',
11
+ ];
12
+ static flags = {
13
+ shell: core_1.Flags.string({ description: 'Shell syntax', options: ['bash', 'zsh', 'fish', 'powershell', 'cmd'] }),
14
+ sdk: core_1.Flags.string({ description: 'Target SDK', options: ['openai', 'anthropic'], default: 'openai' }),
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(Env);
18
+ const key = this.requireByteKey(flags);
19
+ const base = this.baseUrlFrom(flags);
20
+ const shell = (0, shell_1.detectShell)(flags.shell);
21
+ const vars = flags.sdk === 'anthropic'
22
+ ? [
23
+ ['ANTHROPIC_BASE_URL', base],
24
+ ['ANTHROPIC_AUTH_TOKEN', key],
25
+ ]
26
+ : [
27
+ ['OPENAI_BASE_URL', `${base}/v1`],
28
+ ['OPENAI_API_KEY', key],
29
+ ];
30
+ if (!this.jsonEnabled())
31
+ this.log((0, shell_1.formatEnvBlock)(shell, vars));
32
+ return { shell, sdk: flags.sdk, vars: Object.fromEntries(vars) };
33
+ }
34
+ }
35
+ exports.default = Env;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../base';
2
+ export default class Init extends BaseCommand {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static flags: {
6
+ 'provider-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ preset: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ 'key-name': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ 'skip-provider': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,58 @@
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 credentials_1 = require("../lib/credentials");
6
+ const util_1 = require("../lib/util");
7
+ class Init extends base_1.BaseCommand {
8
+ static description = 'Guided setup: add a provider key, choose a preset, and create your Byte API key.';
9
+ static aliases = ['onboard'];
10
+ static flags = {
11
+ 'provider-key': core_1.Flags.string({ description: 'Upstream provider API key (BYOK)', env: 'BYTE_PROVIDER_KEY' }),
12
+ preset: core_1.Flags.string({
13
+ description: 'Optimization preset',
14
+ options: ['balanced', 'max_savings', 'lowest_latency', 'reliability_first'],
15
+ default: 'balanced',
16
+ }),
17
+ 'key-name': core_1.Flags.string({ description: 'Name for the Byte API key', default: 'cli' }),
18
+ 'skip-provider': core_1.Flags.boolean({ description: 'Skip adding a provider key' }),
19
+ };
20
+ async run() {
21
+ const { flags } = await this.parse(Init);
22
+ this.requireToken(flags);
23
+ const profile = this.profileFrom(flags);
24
+ const api = this.api(flags);
25
+ const json = this.jsonEnabled();
26
+ let providerKey = flags['provider-key'];
27
+ if (!providerKey && !flags['skip-provider'] && !json && process.stdin.isTTY) {
28
+ providerKey = await (0, util_1.promptHidden)('Upstream provider API key (leave blank to skip): ');
29
+ }
30
+ let imported = 0;
31
+ if (providerKey) {
32
+ const conn = await api.providersAdd({ api_key: providerKey, gateway_mode: 'byte_auto', auto_fetch: true });
33
+ imported = conn.fetch_result?.imported ?? conn.imported ?? 0;
34
+ if (!json)
35
+ this.log(`Provider connected — ${imported} model(s) imported.`);
36
+ }
37
+ else if (!json) {
38
+ this.log('No provider key added (add one later with `byte providers add`).');
39
+ }
40
+ await api.optPatch({ default_mode: flags.preset });
41
+ if (!json)
42
+ this.log(`Optimization preset set to "${flags.preset}".`);
43
+ const keyRes = await api.keysCreate({ name: flags['key-name'], preset: flags.preset });
44
+ (0, credentials_1.setByteKey)(profile, keyRes.key);
45
+ if (!json) {
46
+ this.log('');
47
+ this.log('Byte API key created and saved to this profile:');
48
+ this.log(` ${keyRes.key}`);
49
+ this.log('');
50
+ this.log('Next:');
51
+ this.log(' byte integrate codex # or claude-code, cursor, cline, aider, openai, anthropic');
52
+ this.log(' byte run "hello from byte"');
53
+ this.log(' byte usage');
54
+ }
55
+ return { provider_models_imported: imported, preset: flags.preset, byte_key: keyRes.key };
56
+ }
57
+ }
58
+ exports.default = Init;
@@ -0,0 +1,20 @@
1
+ import { BaseCommand } from '../base';
2
+ export default class Integrate extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ target: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ list: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ shell: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ write: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ key: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ preset: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ };
16
+ run(): Promise<unknown>;
17
+ private writeSettings;
18
+ private messagesEndpointExists;
19
+ private showList;
20
+ }
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const base_1 = require("../base");
7
+ const api_1 = require("../lib/api");
8
+ const errors_1 = require("../lib/errors");
9
+ const integrations_1 = require("../lib/integrations");
10
+ const shell_1 = require("../lib/shell");
11
+ class Integrate extends base_1.BaseCommand {
12
+ static description = 'Wire a coding harness or SDK to Byte (Claude Code, Codex, Cursor, Cline, Aider, OpenAI/Anthropic SDK).';
13
+ static examples = [
14
+ '<%= config.bin %> integrate --list',
15
+ '<%= config.bin %> integrate codex',
16
+ '<%= config.bin %> integrate claude-code --write --preset lowest_latency',
17
+ ];
18
+ static args = {
19
+ target: core_1.Args.string({ description: 'Target to wire (run --list to see all)', required: false }),
20
+ };
21
+ static flags = {
22
+ list: core_1.Flags.boolean({ description: 'List supported targets and live readiness' }),
23
+ shell: core_1.Flags.string({ description: 'Shell syntax for env output', options: ['bash', 'zsh', 'fish', 'powershell', 'cmd'] }),
24
+ write: core_1.Flags.boolean({ description: 'Write tool config files (a timestamped .bak is kept)' }),
25
+ yes: core_1.Flags.boolean({ char: 'y', description: 'Skip confirmation prompts' }),
26
+ key: core_1.Flags.string({ description: 'Byte API key to use (defaults to the saved profile key)' }),
27
+ preset: core_1.Flags.string({
28
+ description: 'Apply this optimization preset to the org before wiring',
29
+ options: ['balanced', 'max_savings', 'lowest_latency', 'reliability_first'],
30
+ }),
31
+ };
32
+ async run() {
33
+ const { args, flags } = await this.parse(Integrate);
34
+ if (flags.list || !args.target) {
35
+ return this.showList(flags);
36
+ }
37
+ const integ = (0, integrations_1.findIntegration)(args.target);
38
+ if (!integ) {
39
+ return this.error(`Unknown target "${args.target}". Run \`byte integrate --list\`.`, { exit: 2 });
40
+ }
41
+ const byteKey = flags.key || this.requireByteKey(flags);
42
+ const base = this.baseUrlFrom(flags);
43
+ const shell = (0, shell_1.detectShell)(flags.shell);
44
+ if (flags.preset) {
45
+ this.requireToken(flags);
46
+ await this.api(flags).optPatch({ default_mode: flags.preset });
47
+ }
48
+ if (integ.compat === 'anthropic') {
49
+ const exists = await this.messagesEndpointExists(base, byteKey);
50
+ if (!exists) {
51
+ this.warn(`${integ.title} needs Byte's Anthropic endpoint (/v1/messages), which did not respond. ` +
52
+ 'The values below are correct once it is enabled on your gateway.');
53
+ }
54
+ }
55
+ const result = integ.build({ baseUrl: base, byteKey });
56
+ if (!this.jsonEnabled()) {
57
+ this.log(`Integrating ${integ.title} (${integ.compat}-compatible):`);
58
+ this.log('');
59
+ for (const line of result.instructions)
60
+ this.log(` ${line}`);
61
+ if (result.env.length) {
62
+ this.log('');
63
+ this.log(' Environment:');
64
+ for (const line of (0, shell_1.formatEnvBlock)(shell, result.env).split('\n'))
65
+ this.log(` ${line}`);
66
+ }
67
+ if (result.settingsFile) {
68
+ if (flags.write) {
69
+ this.writeSettings(result.settingsFile);
70
+ }
71
+ else {
72
+ this.log('');
73
+ this.log(` Tip: re-run with --write to update ${result.settingsFile.path} automatically.`);
74
+ }
75
+ }
76
+ }
77
+ else if (flags.write && result.settingsFile) {
78
+ this.writeSettings(result.settingsFile);
79
+ }
80
+ return { target: integ.key, compat: integ.compat, env: Object.fromEntries(result.env) };
81
+ }
82
+ writeSettings(file) {
83
+ let existing = {};
84
+ if ((0, node_fs_1.existsSync)(file.path)) {
85
+ try {
86
+ existing = JSON.parse((0, node_fs_1.readFileSync)(file.path, 'utf8'));
87
+ }
88
+ catch {
89
+ existing = {};
90
+ }
91
+ const backup = `${file.path}.byte-bak-${Date.now()}`;
92
+ (0, node_fs_1.copyFileSync)(file.path, backup);
93
+ this.log(` Backed up existing config to ${backup}`);
94
+ }
95
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(file.path), { recursive: true });
96
+ (0, node_fs_1.writeFileSync)(file.path, `${JSON.stringify(file.apply(existing), null, 2)}\n`);
97
+ this.log(` Updated ${file.path}`);
98
+ }
99
+ async messagesEndpointExists(base, byteKey) {
100
+ try {
101
+ await new api_1.ByteApi(base).probeMessages(byteKey);
102
+ return true;
103
+ }
104
+ catch (err) {
105
+ // 404 means the endpoint is not deployed; any other status means it exists.
106
+ if (err instanceof errors_1.ByteError)
107
+ return err.status !== 404;
108
+ return false;
109
+ }
110
+ }
111
+ async showList(flags) {
112
+ const targets = (0, integrations_1.listIntegrations)();
113
+ const key = flags.key || this.optionalByteKey(flags);
114
+ let messagesReady;
115
+ if (key) {
116
+ messagesReady = await this.messagesEndpointExists(this.baseUrlFrom(flags), key);
117
+ }
118
+ const rows = targets.map((t) => ({
119
+ target: t.key,
120
+ title: t.title,
121
+ compat: t.compat,
122
+ ready: t.compat === 'openai' ? true : messagesReady,
123
+ }));
124
+ if (this.jsonEnabled())
125
+ return rows;
126
+ for (const r of rows) {
127
+ const status = r.ready === undefined ? 'unknown (sign in / create a key to probe)' : r.ready ? 'ready' : 'needs /v1/messages';
128
+ this.log(`${r.target.padEnd(14)} ${r.title.padEnd(16)} ${r.compat.padEnd(10)} ${status}`);
129
+ }
130
+ return rows;
131
+ }
132
+ }
133
+ exports.default = Integrate;
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class KeysCreate extends BaseCommand {
3
+ static description: string;
4
+ static args: {
5
+ name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ preset: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ class KeysCreate extends base_1.BaseCommand {
6
+ static description = 'Create a new Byte API key. The secret is shown only once.';
7
+ static args = {
8
+ name: core_1.Args.string({ description: 'A label for the key (e.g. prod-chat)', required: true }),
9
+ };
10
+ static flags = {
11
+ preset: core_1.Flags.string({
12
+ description: 'Bind a default optimization preset to this key',
13
+ options: ['balanced', 'max_savings', 'lowest_latency', 'reliability_first', 'manual'],
14
+ }),
15
+ };
16
+ async run() {
17
+ const { args, flags } = await this.parse(KeysCreate);
18
+ this.requireToken(flags);
19
+ const body = { name: args.name };
20
+ if (flags.preset)
21
+ body.preset = flags.preset;
22
+ const res = await this.api(flags).keysCreate(body);
23
+ if (!this.jsonEnabled()) {
24
+ this.log(`Created key "${res.record?.name}" (id ${res.record?.id}).`);
25
+ this.log('');
26
+ this.log(` ${res.key}`);
27
+ this.log('');
28
+ this.log('Copy it now — it will not be shown again.');
29
+ }
30
+ return res;
31
+ }
32
+ }
33
+ exports.default = KeysCreate;
@@ -0,0 +1,5 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class KeysList extends BaseCommand {
3
+ static description: string;
4
+ run(): Promise<unknown>;
5
+ }