trainfabric 0.1.11 → 0.1.12

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
@@ -29,7 +29,7 @@ trainfabric projects:list
29
29
  trainfabric datasets:upload ./train.jsonl --project <projectId>
30
30
  trainfabric runs:quote --summary --project <projectId> --dataset <datasetId> --model llama-3-8b
31
31
  trainfabric runs:create --yes --project <projectId> --dataset <datasetId> --model llama-3-8b
32
- trainfabric runs:watch <runId>
32
+ trainfabric runs:watch <runId> --timeout 30m
33
33
  trainfabric runs:cost-breakdown <runId> --summary
34
34
  ```
35
35
 
package/dist/index.cjs CHANGED
@@ -8388,8 +8388,11 @@ var RunHandle = class {
8388
8388
  this.listeners.get(event)?.delete(listener);
8389
8389
  };
8390
8390
  }
8391
- async wait() {
8391
+ async wait(options) {
8392
8392
  this.ensureStreaming();
8393
+ const startedAt = Date.now();
8394
+ const pollMs = options?.pollMs ?? 1e3;
8395
+ const timeoutMs = options?.timeoutMs;
8393
8396
  for (; ; ) {
8394
8397
  const detail = await this.client.runs.get(this.snapshot.id);
8395
8398
  this.snapshot = detail.run;
@@ -8406,7 +8409,11 @@ var RunHandle = class {
8406
8409
  }
8407
8410
  return detail;
8408
8411
  }
8409
- await new Promise((resolve) => setTimeout(resolve, 1e3));
8412
+ if (timeoutMs !== void 0 && Date.now() - startedAt > timeoutMs) {
8413
+ this.close();
8414
+ throw new Error(`Timed out waiting for run ${this.snapshot.id}.`);
8415
+ }
8416
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
8410
8417
  }
8411
8418
  }
8412
8419
  close() {
@@ -8624,9 +8631,9 @@ var RunsClient = class extends ResourceClient {
8624
8631
  explanation(runId) {
8625
8632
  return this.requestGet(`/v1/runs/${runId}/explanation`);
8626
8633
  }
8627
- async wait(runId) {
8634
+ async wait(runId, options) {
8628
8635
  const handle = await this.watch(runId);
8629
- return handle.wait();
8636
+ return handle.wait(options);
8630
8637
  }
8631
8638
  };
8632
8639
 
@@ -8914,7 +8921,7 @@ function buildComputeSpec(options) {
8914
8921
 
8915
8922
  // src/index.ts
8916
8923
  var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
8917
- var CLI_VERSION = "0.1.11";
8924
+ var CLI_VERSION = "0.1.12";
8918
8925
  var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
8919
8926
  var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
8920
8927
  var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
@@ -9290,7 +9297,7 @@ function assertQuoteOptions(bundle, options) {
9290
9297
  )}). Omit --accelerator or increase --min-memory.`
9291
9298
  );
9292
9299
  }
9293
- async function watchRun(runId, json = false) {
9300
+ async function watchRun(runId, json = false, timeoutMs) {
9294
9301
  const handle = await createClient(loadConfig()).runs.watch(runId);
9295
9302
  if (json) {
9296
9303
  const emit = (type, payload) => printJson({ type, payload });
@@ -9327,9 +9334,26 @@ async function watchRun(runId, json = false) {
9327
9334
  console.log(`[failed] ${payload.reason ?? "Run failed."}`);
9328
9335
  });
9329
9336
  }
9330
- const detail = await handle.wait();
9337
+ const detail = await handle.wait({ timeoutMs });
9331
9338
  printJson(detail);
9332
9339
  }
9340
+ function parseDurationMs(value) {
9341
+ if (!value) {
9342
+ return void 0;
9343
+ }
9344
+ const trimmed = value.trim().toLowerCase();
9345
+ const match = trimmed.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/);
9346
+ if (!match) {
9347
+ throw new Error(`Invalid duration "${value}". Use values like 30s, 10m, 1h, or 5000ms.`);
9348
+ }
9349
+ const amount = Number(match[1]);
9350
+ const unit = match[2] ?? "ms";
9351
+ const multiplier = unit === "h" ? 36e5 : unit === "m" ? 6e4 : unit === "s" ? 1e3 : 1;
9352
+ return Math.max(1, Math.round(amount * multiplier));
9353
+ }
9354
+ function parsePositiveMs(value, fallback) {
9355
+ return parseDurationMs(value) ?? fallback;
9356
+ }
9333
9357
  function createClient(config) {
9334
9358
  return new TrainingClient({
9335
9359
  accessToken: config.accessToken,
@@ -9498,11 +9522,16 @@ program2.command("runs:status").argument("<runId>").description("Fetch full run
9498
9522
  program2.command("runs:logs").argument("<runId>").description("Fetch run logs").action(async (runId) => {
9499
9523
  printJson(await createClient(loadConfig()).runs.logs(String(runId)));
9500
9524
  });
9501
- program2.command("runs:wait").argument("<runId>").description("Wait for a run to reach a terminal state").action(async (runId) => {
9502
- printJson(await createClient(loadConfig()).runs.wait(String(runId)));
9525
+ program2.command("runs:wait").argument("<runId>").option("--timeout <duration>", "maximum wait duration, for example 30s, 10m, or 1h").option("--poll <duration>", "poll interval, for example 1s or 500ms").description("Wait for a run to reach a terminal state").action(async (runId, options) => {
9526
+ printJson(
9527
+ await createClient(loadConfig()).runs.wait(String(runId), {
9528
+ timeoutMs: parseDurationMs(options.timeout),
9529
+ pollMs: parsePositiveMs(options.poll, 1e3)
9530
+ })
9531
+ );
9503
9532
  });
9504
- program2.command("runs:watch").argument("<runId>").option("--json", "emit event output as JSON").description("Stream a run until it completes").action(async (runId, options) => {
9505
- await watchRun(String(runId), Boolean(options.json));
9533
+ program2.command("runs:watch").argument("<runId>").option("--json", "emit event output as JSON").option("--timeout <duration>", "maximum watch duration, for example 30s, 10m, or 1h").description("Stream a run until it completes").action(async (runId, options) => {
9534
+ await watchRun(String(runId), Boolean(options.json), parseDurationMs(options.timeout));
9506
9535
  });
9507
9536
  program2.command("runs:usage").argument("<runId>").option("--summary", "print a human-readable cost summary instead of raw JSON").description("Fetch run usage summary").action(async (runId, options) => {
9508
9537
  const usage = await createClient(loadConfig()).runs.usage(String(runId));
@@ -9553,7 +9582,7 @@ program2.command("models:export").argument("<modelId>").description("Fetch the e
9553
9582
  program2.command("deployments:list").description("List deployments").action(async () => {
9554
9583
  printJson(await createClient(loadConfig()).deployments.list());
9555
9584
  });
9556
- program2.command("deployments:create").requiredOption("--model <modelId>").description("Create a deployment for a model").action(async (options) => {
9585
+ program2.command("deployments:create").requiredOption("--model <modelId>").option("--project <projectId>", "accepted for consistency; deployment project is inferred from the model").description("Create a deployment for a model").action(async (options) => {
9557
9586
  printJson(await createClient(loadConfig()).deployments.create({ modelId: options.model }));
9558
9587
  });
9559
9588
  program2.command("deployments:get").argument("<deploymentId>").description("Fetch a deployment").action(async (deploymentId) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trainfabric",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Trainfabric CLI for launching GPU training jobs on the hosted Trainfabric backend.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",