badgr-cli 1.0.1 → 1.0.3

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 CHANGED
@@ -55,7 +55,7 @@ badgr serve meta-llama/Llama-3.1-8B-Instruct --gpu L40S --region EU
55
55
  | Flag | Default | Description |
56
56
  |------|---------|-------------|
57
57
  | `--gpu <type>` | RTX_4090 | GPU: RTX_4090, L40S, A6000, A100, H100 |
58
- | `--region US\|EU\|AU` | US | Region preference |
58
+ | `--region <region>` | | Optional region preference. If omitted, Badgr chooses best available capacity. |
59
59
  | `--count <n>` | 1 | Number of GPUs (1–8) |
60
60
  | `--max-price <$/hr>` | — | Hard spend cap per GPU-hour |
61
61
  | `--dry-run` | — | Preview routing without provisioning |
@@ -73,7 +73,7 @@ badgr run python train.py --gpu A100 --env HF_TOKEN=$HF_TOKEN
73
73
  | `--gpu <type>` | RTX_4090 | GPU type |
74
74
  | `--image <img>` | python:3.11-slim | Docker image |
75
75
  | `--env KEY=VALUE` | — | Environment variable (repeatable) |
76
- | `--region US\|EU\|AU` | US | Region preference |
76
+ | `--region <region>` | | Optional region preference. If omitted, Badgr chooses best available capacity. |
77
77
  | `--max-price <$/hr>` | — | Hard spend cap per GPU-hour |
78
78
  | `--detach` | — | Launch and return immediately |
79
79
 
@@ -83,7 +83,7 @@ badgr run python train.py --gpu A100 --env HF_TOKEN=$HF_TOKEN
83
83
 
84
84
  Badgr automatically searches available GPU capacity across its verified compute network.
85
85
 
86
- It chooses the cheapest eligible route that matches your GPU type, region, price cap, and workload type. If a route is unavailable, Badgr can try another eligible route without requiring you to change providers or rewrite code.
86
+ Badgr automatically searches verified GPU capacity and chooses the best eligible route for your GPU type, workload, price cap, and optional region preference.
87
87
 
88
88
  Preview before provisioning:
89
89
 
@@ -102,7 +102,7 @@ badgr receipts # last 10
102
102
  badgr receipts 50 # last 50
103
103
  ```
104
104
 
105
- Each receipt includes: receipt ID, GPU type, provisioning latency, rate/hr, route used, retry count, and status.
105
+ Each receipt includes: receipt ID, GPU type, provisioning latency, price/hr, retry count, and status.
106
106
 
107
107
  ---
108
108
 
@@ -135,7 +135,7 @@ const client = new OpenAI({
135
135
 
136
136
  ## GPU options
137
137
 
138
- | Flag value | GPU | VRAM | Est. rate/hr |
138
+ | Flag value | GPU | VRAM | Estimated Badgr price/hr |
139
139
  |-----------|-----|------|-------------|
140
140
  | RTX_4090 | NVIDIA RTX 4090 | 24 GB | $0.65–0.89 |
141
141
  | L40S | NVIDIA L40S | 48 GB | $1.10–1.40 |
@@ -143,7 +143,7 @@ const client = new OpenAI({
143
143
  | A100 | NVIDIA A100 | 80 GB | $1.20–1.50 |
144
144
  | H100 | NVIDIA H100 | 80 GB | $2.80–3.10 |
145
145
 
146
- Rates are estimated market rates and may vary by region, availability, workload type, and runtime.
146
+ Prices shown are estimated Badgr rates. Final $/GPU-hour is confirmed before provisioning and may vary by GPU type, availability, region, workload, and runtime.
147
147
 
148
148
  ---
149
149
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "badgr-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Badgr — run or serve GPU workloads from one command",
5
5
  "type": "module",
6
6
  "bin": {
7
- "badgr": "./src/badgr.js"
7
+ "badgr": "src/badgr.js"
8
8
  },
9
9
  "scripts": {
10
10
  "start": "node src/badgr.js",
@@ -21,6 +21,14 @@
21
21
  "engines": {
22
22
  "node": ">=18.0.0"
23
23
  },
24
- "keywords": ["gpu", "cli", "ai", "compute", "modal", "gateway", "openai"],
24
+ "keywords": [
25
+ "gpu",
26
+ "cli",
27
+ "ai",
28
+ "compute",
29
+ "modal",
30
+ "gateway",
31
+ "openai"
32
+ ],
25
33
  "license": "MIT"
26
34
  }
package/src/badgr.js CHANGED
@@ -55,8 +55,8 @@ ${chalk.bold('OPENAI-COMPATIBLE SERVING')}
55
55
  ${chalk.dim(' client = OpenAI(api_key="sk-...", base_url="https://api.badgr.ai/v1")')}
56
56
  ${chalk.dim(' client.chat.completions.create(model="dep_xxx", messages=[...])')}
57
57
 
58
- ${chalk.bold('PROVIDER ROUTING')}
59
- ${chalk.dim('own GPUs Vast.ai / Salad / RunPod overflow → manual enterprise fallback')}
58
+ ${chalk.bold('ROUTING')}
59
+ ${chalk.dim('Badgr automatically selects best available GPU capacity for your request.')}
60
60
  `;
61
61
 
62
62
  async function main() {
@@ -45,7 +45,6 @@ export async function downCommand(config, args, chalk) {
45
45
 
46
46
  console.log(chalk.green(`\n✓ Deployment stopped: ${dep.name}\n`));
47
47
  console.log(` ${chalk.bold('ID:')} ${dep.deployment_id}`);
48
- console.log(` ${chalk.bold('Provider:')} ${dep.provider}`);
49
48
  console.log(` ${chalk.bold('GPU:')} ${dep.gpu_type} × ${dep.gpu_count}`);
50
49
  if (dep.started_at) {
51
50
  const uptime = Math.round((Date.now() / 1000 - dep.started_at) / 60);
@@ -1,20 +1,20 @@
1
1
  import { input } from '@inquirer/prompts';
2
2
 
3
3
  export async function loginCommand(chalk, saveConfigFn) {
4
- console.log(chalk.bold('\n🔑 GPU.AI Login\n'));
4
+ console.log(chalk.bold('\n🔑 Badgr Login\n'));
5
5
 
6
6
  const apiKey = await input({
7
- message: 'Enter your GPU.AI API key:',
7
+ message: 'Enter your Badgr API key:',
8
8
  validate: v => v.trim() ? true : 'API key is required',
9
9
  });
10
10
 
11
11
  const baseUrl = await input({
12
12
  message: 'API base URL:',
13
- default: 'https://api.gpu.ai/v1',
13
+ default: 'https://api.badgr.ai/v1',
14
14
  });
15
15
 
16
16
  const config = saveConfigFn({ apiKey: apiKey.trim(), baseUrl: baseUrl.trim() });
17
- console.log(chalk.green('\n✓ Logged in — config saved to ~/.gpu/config.json\n'));
17
+ console.log(chalk.green('\n✓ Logged in — config saved to ~/.badgr/config.json\n'));
18
18
  console.log(chalk.dim(` Base URL: ${config.baseUrl}\n`));
19
19
  return config;
20
20
  }
@@ -37,7 +37,7 @@ export async function logsCommand(config, args, chalk) {
37
37
  } catch (err) {
38
38
  console.log(chalk.yellow(` Could not fetch logs: ${err.message}`));
39
39
  if (localDep) {
40
- console.log(chalk.dim(`\n Provider: ${localDep.provider} GPU: ${localDep.gpu} Type: ${localDep.type}`));
40
+ console.log(chalk.dim(`\n GPU: ${localDep.gpu} Type: ${localDep.type}`));
41
41
  console.log(chalk.dim(` Endpoint: ${localDep.endpointUrl}`));
42
42
  }
43
43
  }
@@ -15,7 +15,6 @@ function printReceipt(r, chalk) {
15
15
 
16
16
  console.log(` ${chalk.cyan(id)}`);
17
17
  console.log(` ${chalk.bold('action:')} ${action}`);
18
- console.log(` ${chalk.bold('provider:')} ${prov}`);
19
18
  if (lat !== undefined) console.log(` ${chalk.bold('latency:')} ${fmtMs(lat)}`);
20
19
  if (cost) console.log(` ${chalk.bold('cost:')} $${typeof cost === 'number' ? cost.toFixed(4) : cost}/hr`);
21
20
  if (r.retries !== undefined) console.log(` ${chalk.bold('retries:')} ${r.retries}`);
@@ -99,7 +99,7 @@ export async function runCommand(config, args, chalk) {
99
99
  console.log(` ${chalk.bold('GPU:')} ${gpu}`);
100
100
  if (detach) console.log(` ${chalk.dim('(detached — returns immediately)')}`);
101
101
  console.log();
102
- console.log(chalk.dim(' Routing own GPUs Vast/RunPod/Salad overflow...'));
102
+ console.log(chalk.dim(' Finding best available GPU capacity...'));
103
103
 
104
104
  let dep;
105
105
  try {
@@ -134,7 +134,6 @@ export async function runCommand(config, args, chalk) {
134
134
  });
135
135
 
136
136
  console.log(chalk.bold(`\n Job ID: ${chalk.cyan(dep.deployment_id)}`));
137
- console.log(` ${chalk.bold('Provider:')} ${dep.provider}`);
138
137
  console.log(` ${chalk.bold('GPU:')} ${dep.gpu_type} × ${dep.gpu_count}`);
139
138
  if (dep.cost_per_hour > 0) console.log(` ${chalk.bold('Rate:')} $${dep.cost_per_hour.toFixed(2)}/hr`);
140
139
  console.log(` ${chalk.bold('Receipt:')} ${chalk.dim(rcptId)}`);
@@ -68,7 +68,7 @@ export async function serveCommand(config, args, chalk) {
68
68
  console.log(` ${chalk.bold('Model:')} ${model}`);
69
69
  console.log(` ${chalk.bold('GPU:')} ${gpu}`);
70
70
  console.log();
71
- console.log(chalk.dim(' Provisioning vLLM endpoint (own GPUs → overflow providers)...'));
71
+ console.log(chalk.dim(' Finding best available GPU capacity...'));
72
72
 
73
73
  let dep;
74
74
  try {
@@ -144,7 +144,6 @@ export async function serveCommand(config, args, chalk) {
144
144
  console.log(` ${chalk.bold('Deployment:')} ${chalk.cyan(dep.deployment_id)}`);
145
145
  console.log(` ${chalk.bold('Model:')} ${dep.model || model}`);
146
146
  console.log(` ${chalk.bold('GPU:')} ${dep.gpu_type} × ${dep.gpu_count}`);
147
- console.log(` ${chalk.bold('Provider:')} ${dep.provider}`);
148
147
  console.log(` ${chalk.bold('Endpoint:')} ${chalk.cyan(endpointUrl)}`);
149
148
  if (dep.cost_per_hour > 0) console.log(` ${chalk.bold('Rate:')} $${dep.cost_per_hour.toFixed(2)}/hr`);
150
149
  console.log(`\n ${chalk.bold('Receipt:')} ${chalk.dim(rcptId)}`);
@@ -47,15 +47,14 @@ export async function statusCommand(config, args, chalk) {
47
47
  return;
48
48
  }
49
49
 
50
- const cols = { name: 16, type: 9, gpu: 11, provider: 12, status: 14, rate: 9 };
50
+ const cols = { name: 16, type: 9, gpu: 11, status: 14, price: 9 };
51
51
 
52
52
  const header =
53
53
  'Name'.padEnd(cols.name) +
54
54
  'Type'.padEnd(cols.type) +
55
55
  'GPU'.padEnd(cols.gpu) +
56
- 'Provider'.padEnd(cols.provider) +
57
56
  'Status'.padEnd(cols.status) +
58
- 'Rate/hr';
57
+ 'Price/hr';
59
58
  console.log(' ' + chalk.bold(header));
60
59
  console.log(' ' + '─'.repeat(Object.values(cols).reduce((a, b) => a + b, 0) + 8));
61
60
 
@@ -65,18 +64,16 @@ export async function statusCommand(config, args, chalk) {
65
64
  : d.status === 'provisioning'
66
65
  ? chalk.yellow(d.status.padEnd(cols.status))
67
66
  : chalk.dim(d.status.padEnd(cols.status));
68
- const rate = d.cost_per_hour > 0 ? `$${d.cost_per_hour.toFixed(2)}` : 'own-host';
67
+ const price = d.cost_per_hour > 0 ? `$${d.cost_per_hour.toFixed(2)}` : '';
69
68
  const name = (d.name || d.deployment_id || '').slice(0, cols.name - 1);
70
- const provider = (d.provider || '—').padEnd(cols.provider);
71
69
  const gpu = (d.gpu_type || '—').slice(0, cols.gpu - 1).padEnd(cols.gpu);
72
70
  console.log(
73
71
  ' ' +
74
72
  name.padEnd(cols.name) +
75
73
  (d.workload_type || '—').padEnd(cols.type) +
76
74
  gpu +
77
- provider +
78
75
  statusColor +
79
- rate
76
+ price
80
77
  );
81
78
  });
82
79
 
@@ -29,7 +29,7 @@ function printRoutePlan(plan, chalk) {
29
29
  });
30
30
  console.log();
31
31
  console.log(` Estimated range: $${cheapestRate.toFixed(2)}–$${lane2[lane2.length - 1].ratePerHour.toFixed(2)}/hr`);
32
- console.log(chalk.dim(` With 25% overhead (startup risk + badgr margin): ~$${costWithOverhead.toFixed(2)}/hr`));
32
+ console.log(chalk.dim(` Estimated Badgr price: ~$${costWithOverhead.toFixed(2)}/hr`));
33
33
  }
34
34
  console.log();
35
35
  console.log(chalk.dim(' Remove --dry-run to provision.'));
@@ -65,7 +65,7 @@ export async function upCommand(config, args, chalk) {
65
65
  console.log(` ${'─'.repeat(40)}`);
66
66
  specLines(spec).forEach(l => console.log(` ${l}`));
67
67
  console.log();
68
- console.log(chalk.dim(' Routing through GPU.AI gateway (lane 1 → lane 2 → lane 3)...'));
68
+ console.log(chalk.dim(' Finding best available GPU capacity...'));
69
69
 
70
70
  let dep;
71
71
  try {
@@ -119,7 +119,6 @@ export async function upCommand(config, args, chalk) {
119
119
  console.log(` ${chalk.bold('Type:')} ${dep.workload_type}`);
120
120
  if (dep.model) console.log(` ${chalk.bold('Model:')} ${dep.model}`);
121
121
  console.log(` ${chalk.bold('GPU:')} ${dep.gpu_type} × ${dep.gpu_count}`);
122
- console.log(` ${chalk.bold('Provider:')} ${dep.provider}`);
123
122
  console.log(` ${chalk.bold('Endpoint:')} ${chalk.cyan(dep.endpoint_url || config.baseUrl)}`);
124
123
  if (dep.cost_per_hour > 0) console.log(` ${chalk.bold('Rate:')} $${dep.cost_per_hour.toFixed(2)}/hr`);
125
124
  console.log(`\n ${chalk.bold('Receipt ID:')} ${chalk.dim(dep.receipt_id)}`);
@@ -4,7 +4,7 @@ import { join } from 'path';
4
4
  import { rmSync, existsSync } from 'fs';
5
5
  import { loadConfig, saveConfig, requireApiKey, DEFAULTS } from '../src/config.js';
6
6
 
7
- const tmp = join(tmpdir(), `gpu-cli-test-${process.pid}`);
7
+ const tmp = join(tmpdir(), `badgr-cli-test-${process.pid}`);
8
8
  const testConfigFile = join(tmp, 'config.json');
9
9
 
10
10
  afterEach(() => {