badgr-cli 1.0.46 → 1.0.48

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badgr-cli",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "description": "Badgr — run or serve GPU workloads from one command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,9 @@
14
14
  "dependencies": {
15
15
  "@inquirer/prompts": "^8.5.2",
16
16
  "archiver": "^7.0.1",
17
- "chalk": "^5.3.0"
17
+ "chalk": "^5.3.0",
18
+ "js-yaml": "^4.1.0",
19
+ "tar": "^7.4.3"
18
20
  },
19
21
  "devDependencies": {
20
22
  "vitest": "^4.1.8"
package/src/api.js CHANGED
@@ -97,6 +97,36 @@ export async function callApi(path, { method = 'GET', apiKey, baseUrl, body, tim
97
97
  return res.json();
98
98
  }
99
99
 
100
+ // ---- Uploads (POST /v1/uploads — generic blob store) ------------------------
101
+
102
+ /**
103
+ * Upload a blob (project zip, dataset, input archive, ...) to the generic
104
+ * /v1/uploads store. Returns the parsed JSON response ({ upload_id,
105
+ * code_uri, expires_in }) — callers pick whichever field they need.
106
+ *
107
+ * Uses Node's built-in FormData/Blob/fetch (Node >=18) rather than a
108
+ * multipart HTTP library — no extra dependency, and fetch derives the
109
+ * multipart boundary/Content-Type from the FormData body automatically
110
+ * (setting Content-Type manually breaks the boundary).
111
+ */
112
+ export async function uploadBlob(config, { data, filename, contentType }) {
113
+ const form = new FormData();
114
+ const blob = contentType ? new Blob([data], { type: contentType }) : new Blob([data]);
115
+ form.append('file', blob, filename);
116
+
117
+ const baseUrl = config.baseUrl.replace(/\/v1\/?$/, '');
118
+ const res = await fetch(`${baseUrl}/v1/uploads`, {
119
+ method: 'POST',
120
+ body: form,
121
+ headers: { Authorization: `Bearer ${config.apiKey}` },
122
+ });
123
+ if (!res.ok) {
124
+ const text = await res.text().catch(() => '');
125
+ throw new Error(`Upload failed: ${res.status} ${res.statusText}${text ? ` — ${text}` : ''}`);
126
+ }
127
+ return res.json();
128
+ }
129
+
100
130
  // ---- Core: run & serve (POST /v1/run, POST /v1/serve) ----------------------
101
131
 
102
132
  export function runJob(config, body) {
@@ -177,6 +207,15 @@ export function restartDeployment(config, deploymentId) {
177
207
  });
178
208
  }
179
209
 
210
+ export function rerunDeployment(config, deploymentId) {
211
+ return callApi(`/deployments/${deploymentId}/rerun`, {
212
+ method: 'POST',
213
+ apiKey: config.apiKey,
214
+ baseUrl: config.baseUrl,
215
+ timeoutMs: 30_000,
216
+ });
217
+ }
218
+
180
219
  export function heartbeatDeployment(config, deploymentId) {
181
220
  return callApi(`/deployments/${deploymentId}/heartbeat`, {
182
221
  method: 'POST',
package/src/badgr.js CHANGED
@@ -19,9 +19,11 @@ import { transcribeCommand } from './commands/transcribe.js';
19
19
  import { embedCommand } from './commands/embed.js';
20
20
  import { templateCommand } from './commands/template.js';
21
21
  import { workloadCommand } from './commands/workload.js';
22
+ import { batchCommand } from './commands/batch.js';
22
23
  import { workspaceCommand } from './commands/workspace.js';
23
24
  import { detectCommand } from './commands/detect.js';
24
25
  import { restartCommand } from './commands/restart.js';
26
+ import { rerunCommand } from './commands/rerun.js';
25
27
  import { heartbeatCommand } from './commands/heartbeat.js';
26
28
 
27
29
  const HELP = `
@@ -37,6 +39,7 @@ ${chalk.bold('COMMANDS')}
37
39
  ${chalk.cyan('badgr logs <id>')} Stream logs for a running job or endpoint
38
40
  ${chalk.cyan('badgr down <id>')} Stop a deployment and end billing
39
41
  ${chalk.cyan('badgr restart <id>')} Relaunch an endpoint with the same config and API key
42
+ ${chalk.cyan('badgr rerun <id>')} Replay a past job or endpoint with its exact original spec
40
43
  ${chalk.cyan('badgr heartbeat <id>')} Reset an endpoint's idle-timeout clock
41
44
  ${chalk.cyan('badgr receipts')} Show cost history
42
45
  ${chalk.cyan('badgr test')} Run an end-to-end test (provision → run → teardown)
@@ -46,6 +49,11 @@ ${chalk.bold('COMMANDS')}
46
49
  ${chalk.cyan('badgr workload run <name>')} Rerun a saved workload
47
50
  ${chalk.cyan('badgr workspace list')} List workspace trackers (job history + cost per named context)
48
51
  ${chalk.cyan('badgr workspace create')} Create a workspace tracker (link jobs to a named storage path)
52
+ ${chalk.cyan('badgr batch run <workload.yml>')} Run a generic containerized batch job with artifact capture
53
+ ${chalk.cyan('badgr batch status <run_id>')} Show status, failure reason, cost, teardown
54
+ ${chalk.cyan('badgr batch artifacts <run_id>')} Download and extract output artifacts
55
+ ${chalk.cyan('badgr batch receipt <run_id>')} Show the full batch receipt
56
+ ${chalk.cyan('badgr batch compare <a> <b>')} Compare success_metric between two runs
49
57
 
50
58
  ${chalk.bold('SHORTCUTS')} ${chalk.dim('(wrappers around run / serve for common workloads)')}
51
59
  ${chalk.cyan('badgr comfyui run <workflow.json>')} Launch ComfyUI, return endpoint URL
@@ -93,6 +101,11 @@ ${chalk.bold('EXAMPLES')}
93
101
  ${chalk.dim('# Generate embeddings:')}
94
102
  badgr embed BAAI/bge-large-en-v1.5 documents.txt --max-cost 2
95
103
 
104
+ ${chalk.dim('# Generic batch workload (CV/video/scientific batch, sim, physical-AI eval):')}
105
+ badgr batch run workload.yml
106
+ badgr batch artifacts dep-abc123
107
+ badgr batch compare dep-abc123 dep-def456
108
+
96
109
  ${chalk.dim('# Tier 2 — marketplace routing, lower-cost options:')}
97
110
  badgr serve meta-llama/Llama-3.1-8B-Instruct --tier 2 --max-cost 10
98
111
 
@@ -163,6 +176,7 @@ async function main() {
163
176
  case 'logs': return logsCommand(config, rest, chalk);
164
177
  case 'down': return downCommand(config, rest, chalk);
165
178
  case 'restart': return restartCommand(config, rest, chalk);
179
+ case 'rerun': return rerunCommand(config, rest, chalk);
166
180
  case 'heartbeat': return heartbeatCommand(config, rest, chalk);
167
181
  case 'receipts': return receiptsCommand(config, rest, chalk);
168
182
  case 'models': return modelsCommand(config, chalk);
@@ -175,6 +189,7 @@ async function main() {
175
189
  case 'embed': return embedCommand(config, rest, chalk);
176
190
  case 'template': return templateCommand(config, rest, chalk);
177
191
  case 'workload': return workloadCommand(config, rest, chalk);
192
+ case 'batch': return batchCommand(config, rest, chalk);
178
193
  case 'workspace': return workspaceCommand(config, rest, chalk);
179
194
  // legacy aliases kept for compatibility
180
195
  case 'up': return upCommand(config, rest, chalk);