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(directory, opts) {
67
+ async function uploadTrajectoryAction(pathArg, opts) {
68
68
  const chalk = (await import("chalk")).default;
69
69
  const { existsSync, statSync } = await import("fs");
70
- if (!existsSync(directory) || !statSync(directory).isDirectory()) {
71
- console.error(chalk.red(` \u2717 Directory not found: ${directory}`));
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
- const slug = opts.slug ?? directory.replace(/\/+$/, "").split("/").pop();
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 ${directory} \u2192 ${chalk.cyan(slug)}
127
+ Uploading trajectory ${pathArg} \u2192 ${chalk.cyan(slug)}
96
128
  `));
97
129
  try {
98
- const { uploadJob } = await import("./upload-JHU236SW.js");
99
- const result = await uploadJob(directory, {
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 <directory>").description("Upload a trajectory job directory (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);
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trajectories-sh",
3
- "version": "1.18.1",
3
+ "version": "1.18.3",
4
4
  "description": "CLI for uploading trajectory jobs to trajectories.sh",
5
5
  "type": "module",
6
6
  "bin": {