trajectories-sh 1.18.1 → 1.18.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/dist/cli.js
CHANGED
|
@@ -64,11 +64,18 @@ auth.command("status").description("Show current authentication status").action(
|
|
|
64
64
|
console.log(chalk.dim(" Not logged in. Run: trajectories auth login"));
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
-
async function uploadTrajectoryAction(
|
|
67
|
+
async function uploadTrajectoryAction(pathArg, opts) {
|
|
68
68
|
const chalk = (await import("chalk")).default;
|
|
69
69
|
const { existsSync, statSync } = await import("fs");
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
const exists = existsSync(pathArg);
|
|
71
|
+
const isZip = pathArg.toLowerCase().endsWith(".zip");
|
|
72
|
+
const isDir = exists && statSync(pathArg).isDirectory();
|
|
73
|
+
if (!exists) {
|
|
74
|
+
console.error(chalk.red(` \u2717 Path not found: ${pathArg}`));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
if (!isDir && !isZip) {
|
|
78
|
+
console.error(chalk.red(` \u2717 ${pathArg} is not a directory or .zip file`));
|
|
72
79
|
process.exit(1);
|
|
73
80
|
}
|
|
74
81
|
if (opts.apiKey) {
|
|
@@ -90,13 +97,38 @@ async function uploadTrajectoryAction(directory, opts) {
|
|
|
90
97
|
)
|
|
91
98
|
);
|
|
92
99
|
}
|
|
93
|
-
|
|
100
|
+
if (isZip) {
|
|
101
|
+
const { uploadZip } = await import("./upload-YDTMBIW2.js");
|
|
102
|
+
const slug2 = opts.slug ?? pathArg.replace(/\.zip$/i, "").replace(/\/+$/, "").split("/").pop();
|
|
103
|
+
console.log(chalk.bold(`
|
|
104
|
+
Uploading ZIP ${pathArg} \u2192 ${chalk.cyan(slug2)}
|
|
105
|
+
`));
|
|
106
|
+
try {
|
|
107
|
+
const results = await uploadZip(pathArg, { slug: slug2, name: opts.name });
|
|
108
|
+
for (const r of results) {
|
|
109
|
+
console.log(chalk.green.bold(` \u2713 ${r.slug}`));
|
|
110
|
+
console.log(` Trials: ${r.nTrials}`);
|
|
111
|
+
if (r.meanReward != null) {
|
|
112
|
+
console.log(` Pass rate: ${(r.meanReward * 100).toFixed(0)}%`);
|
|
113
|
+
}
|
|
114
|
+
console.log(` Viewer: ${r.viewerUrl}`);
|
|
115
|
+
}
|
|
116
|
+
console.log("");
|
|
117
|
+
} catch (e) {
|
|
118
|
+
console.error(chalk.red(`
|
|
119
|
+
\u2717 ${e.message}
|
|
120
|
+
`));
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const slug = opts.slug ?? pathArg.replace(/\/+$/, "").split("/").pop();
|
|
94
126
|
console.log(chalk.bold(`
|
|
95
|
-
Uploading trajectory ${
|
|
127
|
+
Uploading trajectory ${pathArg} \u2192 ${chalk.cyan(slug)}
|
|
96
128
|
`));
|
|
97
129
|
try {
|
|
98
|
-
const { uploadJob } = await import("./upload-
|
|
99
|
-
const result = await uploadJob(
|
|
130
|
+
const { uploadJob } = await import("./upload-YDTMBIW2.js");
|
|
131
|
+
const result = await uploadJob(pathArg, {
|
|
100
132
|
slug,
|
|
101
133
|
name: opts.name
|
|
102
134
|
});
|
|
@@ -242,7 +274,7 @@ async function deleteTrajectoryAction(url, opts) {
|
|
|
242
274
|
}
|
|
243
275
|
}
|
|
244
276
|
var upload = program.command("upload").description("Upload trajectories or tasks");
|
|
245
|
-
upload.command("trajectory <
|
|
277
|
+
upload.command("trajectory <path>").description("Upload a trajectory job directory or ZIP file (always uploaded as unlisted)").option("-s, --slug <slug>", "URL slug (default: directory name)").option("-n, --name <name>", "Display name (default: slug)").option("--api-key <key>", "API key (or set TRAJECTORIES_API_KEY in your env)").option("-v, --visibility <vis>", "(deprecated, ignored \u2014 set visibility in the UI)").action(uploadTrajectoryAction);
|
|
246
278
|
upload.command("task <directory>").description("Upload a benchmark task directory").option("-n, --name <name>", "Task name (default: directory name)").option("--api-key <key>", "API key (or set TRAJECTORIES_API_KEY in your env)").option("-v, --visibility <vis>", "public or private", "public").action(uploadTaskAction);
|
|
247
279
|
var download = program.command("download").description("Download trajectories");
|
|
248
280
|
download.command("trajectory <url>").description("Download a trajectory job from trajectories.sh").option("-o, --output <dir>", "Output directory (default: slug name)").action(downloadTrajectoryAction);
|
|
@@ -50,6 +50,74 @@ async function apiPost(path, body, timeout = 3e5) {
|
|
|
50
50
|
signal: AbortSignal.timeout(timeout)
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
+
async function uploadZip(zipPath, opts) {
|
|
54
|
+
const { readFileSync: readFileSync2, statSync: statSync2 } = await import("fs");
|
|
55
|
+
const { getApiUrl: _getApiUrl, getAuthHeader: _getAuthHeader } = await import("./config-4XJRECIW.js");
|
|
56
|
+
const auth = await _getAuthHeader();
|
|
57
|
+
if (!auth) throw new Error("Not authenticated. Run: trajectories auth login");
|
|
58
|
+
const fileStat = statSync2(zipPath);
|
|
59
|
+
const sizeMB = (fileStat.size / (1024 * 1024)).toFixed(1);
|
|
60
|
+
console.log(` ZIP size: ${sizeMB} MB`);
|
|
61
|
+
console.log(" Uploading to server (server-side extraction)...");
|
|
62
|
+
const fileData = readFileSync2(zipPath);
|
|
63
|
+
const formData = new FormData();
|
|
64
|
+
formData.append("file", new Blob([fileData]), zipPath.split("/").pop() ?? "upload.zip");
|
|
65
|
+
if (opts.slug) formData.append("slug", opts.slug);
|
|
66
|
+
if (opts.name) formData.append("name", opts.name);
|
|
67
|
+
formData.append("visibility", "unlisted");
|
|
68
|
+
const apiUrl = _getApiUrl();
|
|
69
|
+
const resp = await fetch(`${apiUrl}/api/cli/push/zip`, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { Authorization: auth },
|
|
72
|
+
body: formData,
|
|
73
|
+
signal: AbortSignal.timeout(6e5)
|
|
74
|
+
});
|
|
75
|
+
if (!resp.ok) {
|
|
76
|
+
let detail;
|
|
77
|
+
try {
|
|
78
|
+
const body = await resp.json();
|
|
79
|
+
detail = body.detail || JSON.stringify(body);
|
|
80
|
+
} catch {
|
|
81
|
+
detail = await resp.text();
|
|
82
|
+
}
|
|
83
|
+
throw new Error(`ZIP upload failed (${resp.status}): ${detail}`);
|
|
84
|
+
}
|
|
85
|
+
const initResult = await resp.json();
|
|
86
|
+
console.log(` Server received ZIP. Extracting ${initResult.total_jobs} job(s)...`);
|
|
87
|
+
let lastStatus = "";
|
|
88
|
+
while (true) {
|
|
89
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
90
|
+
const statusResp = await fetch(`${apiUrl}/api/cli/push/zip/${initResult.task_id}/status`, {
|
|
91
|
+
headers: { Authorization: auth },
|
|
92
|
+
signal: AbortSignal.timeout(3e4)
|
|
93
|
+
});
|
|
94
|
+
if (!statusResp.ok) {
|
|
95
|
+
throw new Error(`Failed to check ZIP status: ${statusResp.status}`);
|
|
96
|
+
}
|
|
97
|
+
const status = await statusResp.json();
|
|
98
|
+
if (status.status !== lastStatus) {
|
|
99
|
+
console.log(` ${status.status}${status.current_job ? ` (${status.current_job})` : ""} [${status.completed_jobs}/${status.total_jobs}]`);
|
|
100
|
+
lastStatus = status.status;
|
|
101
|
+
}
|
|
102
|
+
if (status.status === "done") {
|
|
103
|
+
const result2 = { jobs: status.jobs };
|
|
104
|
+
var finalResult = result2;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
if (status.status === "error") {
|
|
108
|
+
throw new Error(`Server-side extraction failed: ${status.error}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const result = finalResult;
|
|
112
|
+
const siteUrl = apiUrl.includes("localhost") ? "http://localhost:3000" : apiUrl.replace("api.", "").replace(/\/$/, "");
|
|
113
|
+
return result.jobs.map((j) => ({
|
|
114
|
+
jobId: j.job_id,
|
|
115
|
+
slug: j.slug,
|
|
116
|
+
nTrials: j.n_trials,
|
|
117
|
+
meanReward: j.mean_reward ?? void 0,
|
|
118
|
+
viewerUrl: `${siteUrl}/t/${j.job_id}`
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
53
121
|
async function convertToWebP(dir) {
|
|
54
122
|
const { files } = collectFiles(dir);
|
|
55
123
|
const pngs = files.filter((f) => f.relPath.toLowerCase().endsWith(".png"));
|
|
@@ -522,5 +590,6 @@ function truncate(s, n) {
|
|
|
522
590
|
}
|
|
523
591
|
export {
|
|
524
592
|
collectFiles,
|
|
525
|
-
uploadJob
|
|
593
|
+
uploadJob,
|
|
594
|
+
uploadZip
|
|
526
595
|
};
|