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 +4 -2
- package/src/api.js +39 -0
- package/src/badgr.js +15 -0
- package/src/commands/batch.js +620 -0
- package/src/commands/rerun.js +75 -0
- package/src/commands/run.js +3 -19
- package/src/commands/train.js +49 -21
- package/src/store.js +27 -0
- package/src/workloadSpec.js +126 -0
- package/tests/api.test.js +29 -1
- package/tests/batch.test.js +329 -0
- package/tests/rerun.test.js +94 -0
- package/tests/train-lora-dataset.test.js +176 -0
- package/tests/workload-spec.test.js +180 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "badgr-cli",
|
|
3
|
-
"version": "1.0.
|
|
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);
|