trainfabric 0.1.25 → 0.1.26
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/index.cjs +94 -31
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8820,12 +8820,16 @@ var import_node_fs = __toESM(require("node:fs"), 1);
|
|
|
8820
8820
|
var import_node_os = __toESM(require("node:os"), 1);
|
|
8821
8821
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
8822
8822
|
var idPatterns = {
|
|
8823
|
+
apiKey: /^key_[A-Za-z0-9_-]+$/,
|
|
8823
8824
|
dataset: /^ds_[A-Za-z0-9_-]+$/,
|
|
8824
8825
|
deployment: /^dep_[A-Za-z0-9_-]+$/,
|
|
8825
8826
|
model: /^mdl_[A-Za-z0-9_-]+$/,
|
|
8826
8827
|
org: /^org_[A-Za-z0-9_-]+$/,
|
|
8828
|
+
pool: /^pool_[A-Za-z0-9_-]+$/,
|
|
8827
8829
|
project: /^proj_[A-Za-z0-9_-]+$/,
|
|
8828
|
-
run: /^run_[A-Za-z0-9_-]
|
|
8830
|
+
run: /^run_[A-Za-z0-9_-]+$/,
|
|
8831
|
+
serviceAccount: /^svc_[A-Za-z0-9_-]+$/,
|
|
8832
|
+
supplier: /^[A-Za-z][A-Za-z0-9_-]*$/
|
|
8829
8833
|
};
|
|
8830
8834
|
var allowedBillingUnits = /* @__PURE__ */ new Set(["normalized_tflop_seconds", "reserved_gpu_seconds", "usd"]);
|
|
8831
8835
|
function collectRuntimeFiles(repoPath) {
|
|
@@ -8961,7 +8965,10 @@ function decrypt(payload) {
|
|
|
8961
8965
|
}
|
|
8962
8966
|
function parseApiKeyScopes(input) {
|
|
8963
8967
|
const allowedScopes = new Set(apiKeyScopes);
|
|
8964
|
-
const scopes = input.split(",").map((scope) => scope.trim())
|
|
8968
|
+
const scopes = input.split(",").map((scope) => scope.trim());
|
|
8969
|
+
if (scopes.some((scope) => scope.length === 0)) {
|
|
8970
|
+
throw new Error("API key scopes cannot contain empty entries.");
|
|
8971
|
+
}
|
|
8965
8972
|
const invalidScope = scopes.find((scope) => !allowedScopes.has(scope));
|
|
8966
8973
|
if (invalidScope) {
|
|
8967
8974
|
throw new Error(`Invalid API key scope: ${invalidScope}`);
|
|
@@ -9014,36 +9021,75 @@ var BASE_MODEL_ALIASES = {
|
|
|
9014
9021
|
"qwen2.5-7b": "qwen-2.5-7b",
|
|
9015
9022
|
qwen_2_5_7b: "qwen-2.5-7b"
|
|
9016
9023
|
};
|
|
9024
|
+
var ACCELERATOR_CLASSES = /* @__PURE__ */ new Set(["a10g", "l4", "a40", "l40s", "a100", "h100", "h200", "b200"]);
|
|
9025
|
+
var PRECISION_MODES = /* @__PURE__ */ new Set(["fp16_bf16", "fp8", "fp32"]);
|
|
9026
|
+
var INTERCONNECT_TYPES = /* @__PURE__ */ new Set(["pcie", "nvlink"]);
|
|
9027
|
+
function normalizePositiveInteger(value, label, fallback) {
|
|
9028
|
+
const parsed = Number(value ?? String(fallback));
|
|
9029
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
9030
|
+
throw new Error(`${label} must be a positive integer.`);
|
|
9031
|
+
}
|
|
9032
|
+
return parsed;
|
|
9033
|
+
}
|
|
9034
|
+
function normalizeOptionalPositiveNumber(value, label) {
|
|
9035
|
+
if (value === void 0) {
|
|
9036
|
+
return void 0;
|
|
9037
|
+
}
|
|
9038
|
+
const parsed = Number(value);
|
|
9039
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
9040
|
+
throw new Error(`${label} must be a positive number.`);
|
|
9041
|
+
}
|
|
9042
|
+
return parsed;
|
|
9043
|
+
}
|
|
9044
|
+
function normalizeOptionalChoice(value, allowed, label, examples) {
|
|
9045
|
+
if (value === void 0) {
|
|
9046
|
+
return void 0;
|
|
9047
|
+
}
|
|
9048
|
+
const normalized = String(value).trim().toLowerCase();
|
|
9049
|
+
if (!allowed.has(normalized)) {
|
|
9050
|
+
throw new Error(`${label} is invalid. Use ${examples}.`);
|
|
9051
|
+
}
|
|
9052
|
+
return normalized;
|
|
9053
|
+
}
|
|
9017
9054
|
function normalizeBaseModel(model) {
|
|
9018
9055
|
return BASE_MODEL_ALIASES[model] ?? model;
|
|
9019
9056
|
}
|
|
9020
9057
|
function buildComputeSpec(options) {
|
|
9021
|
-
const gpuCount =
|
|
9022
|
-
const nodeCount =
|
|
9058
|
+
const gpuCount = normalizePositiveInteger(options.gpus, "GPU count", 1);
|
|
9059
|
+
const nodeCount = normalizePositiveInteger(options.nodes, "Node count", 1);
|
|
9023
9060
|
const compute = {
|
|
9024
9061
|
gpuCount,
|
|
9025
9062
|
nodeCount,
|
|
9026
9063
|
distributionStrategy: gpuCount > 1 || nodeCount > 1 ? "ddp" : "single_gpu",
|
|
9027
9064
|
target: "local"
|
|
9028
9065
|
};
|
|
9029
|
-
|
|
9030
|
-
|
|
9066
|
+
const accelerator = normalizeOptionalChoice(
|
|
9067
|
+
options.accelerator,
|
|
9068
|
+
ACCELERATOR_CLASSES,
|
|
9069
|
+
"Accelerator",
|
|
9070
|
+
"a10g, l4, a40, l40s, a100, h100, h200, or b200"
|
|
9071
|
+
);
|
|
9072
|
+
const minMemory = normalizeOptionalPositiveNumber(options.minMemory, "Minimum GPU memory");
|
|
9073
|
+
const precision = normalizeOptionalChoice(options.precision, PRECISION_MODES, "Precision", "fp16_bf16, fp8, or fp32");
|
|
9074
|
+
const interconnect = normalizeOptionalChoice(options.interconnect, INTERCONNECT_TYPES, "Interconnect", "pcie or nvlink");
|
|
9075
|
+
if (accelerator) {
|
|
9076
|
+
compute.acceleratorClass = accelerator;
|
|
9031
9077
|
}
|
|
9032
|
-
if (
|
|
9033
|
-
compute.minGpuMemoryGb =
|
|
9078
|
+
if (minMemory !== void 0) {
|
|
9079
|
+
compute.minGpuMemoryGb = minMemory;
|
|
9034
9080
|
}
|
|
9035
|
-
if (
|
|
9036
|
-
compute.precision =
|
|
9081
|
+
if (precision) {
|
|
9082
|
+
compute.precision = precision;
|
|
9037
9083
|
}
|
|
9038
|
-
if (
|
|
9039
|
-
compute.interconnect =
|
|
9084
|
+
if (interconnect) {
|
|
9085
|
+
compute.interconnect = interconnect;
|
|
9040
9086
|
}
|
|
9041
9087
|
return compute;
|
|
9042
9088
|
}
|
|
9043
9089
|
|
|
9044
9090
|
// src/index.ts
|
|
9045
9091
|
var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
|
|
9046
|
-
var CLI_VERSION = "0.1.
|
|
9092
|
+
var CLI_VERSION = "0.1.26";
|
|
9047
9093
|
var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
|
|
9048
9094
|
var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
|
|
9049
9095
|
var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
|
|
@@ -9441,14 +9487,28 @@ function filterQuoteBundleForRequestedMode(bundle, options) {
|
|
|
9441
9487
|
};
|
|
9442
9488
|
}
|
|
9443
9489
|
function redactInlineSource(value) {
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9490
|
+
const redact = (current) => {
|
|
9491
|
+
if (Array.isArray(current)) {
|
|
9492
|
+
return current.map((item) => redact(item));
|
|
9493
|
+
}
|
|
9494
|
+
if (!current || typeof current !== "object") {
|
|
9449
9495
|
return current;
|
|
9450
|
-
}
|
|
9451
|
-
|
|
9496
|
+
}
|
|
9497
|
+
const object = current;
|
|
9498
|
+
const next = {};
|
|
9499
|
+
for (const [key, child] of Object.entries(object)) {
|
|
9500
|
+
next[key] = key === "content" && typeof child === "string" ? "<redacted>" : redact(child);
|
|
9501
|
+
}
|
|
9502
|
+
return next;
|
|
9503
|
+
};
|
|
9504
|
+
return redact(value);
|
|
9505
|
+
}
|
|
9506
|
+
function normalizePositiveUsd(value, label) {
|
|
9507
|
+
const amount = Number(value);
|
|
9508
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
9509
|
+
throw new Error(`${label} must be a positive USD amount.`);
|
|
9510
|
+
}
|
|
9511
|
+
return amount;
|
|
9452
9512
|
}
|
|
9453
9513
|
async function watchRun(runId, json = false, timeoutMs, pollMs) {
|
|
9454
9514
|
const handle = await createClient(loadConfig()).runs.watch(runId);
|
|
@@ -9687,12 +9747,13 @@ program2.command("datasets:upload").argument("<file>").option("--project <projec
|
|
|
9687
9747
|
printJson(dataset);
|
|
9688
9748
|
});
|
|
9689
9749
|
program2.command("runs:create").option("--project <projectId>").requiredOption("--dataset <datasetId>").requiredOption("--model <baseModel>").option("--eval <evalDatasetId>").option("--epochs <epochs>", "number of epochs", "3").option("--lr <lr>", "learning rate", "0.0002").option("--gpus <gpuCount>", "gpu count", "1").option("--nodes <nodeCount>", "node count", "1").option("--accelerator <acceleratorClass>", "optional hard accelerator constraint (for example: a10g, a100, h100)").option("--min-memory <gigabytes>", "minimum GPU memory in GB").option("--precision <precision>", "fp16_bf16, fp8, or fp32").option("--interconnect <interconnect>", "pcie or nvlink").option("--mode <mode>", "efficient, balanced, or power", "balanced").option("--quote <pricingQuoteId>", "launch the exact accepted quote id from runs:quote").option("--repo <path>", "local repo path for runtime autodetect").option("--git <url>", "git repo URL for runtime metadata").option("--branch <branch>", "git branch for runtime metadata").option("--yes", "confirm that you reviewed pricing with runs:quote --summary and accept fluctuating realized usage").description("Create a training run").action(async (options) => {
|
|
9750
|
+
const config = loadConfig();
|
|
9751
|
+
const runInput = buildRunInput(options, config);
|
|
9690
9752
|
if (!options.yes) {
|
|
9691
9753
|
throw new Error("Refusing to launch without explicit cost acceptance. Run `trainfabric runs:quote --summary ...` first, then rerun `runs:create` with --yes.");
|
|
9692
9754
|
}
|
|
9693
|
-
const config = loadConfig();
|
|
9694
9755
|
const client = createClient(config);
|
|
9695
|
-
const run = await client.runs.create(
|
|
9756
|
+
const run = await client.runs.create(runInput);
|
|
9696
9757
|
printJson(run.snapshot);
|
|
9697
9758
|
});
|
|
9698
9759
|
program2.command("runtime:detect").option("--project <projectId>").option("--repo <path>").option("--git <url>").option("--branch <branch>").description("Detect a supported runtime from a local repo snapshot or git metadata").action(async (options) => {
|
|
@@ -9726,7 +9787,7 @@ program2.command("runs:quote").option("--project <projectId>").requiredOption("-
|
|
|
9726
9787
|
if (options.summary) {
|
|
9727
9788
|
printQuoteSummary(bundle);
|
|
9728
9789
|
} else {
|
|
9729
|
-
printJson(bundle);
|
|
9790
|
+
printJson(redactInlineSource(bundle));
|
|
9730
9791
|
}
|
|
9731
9792
|
});
|
|
9732
9793
|
program2.command("runs:list").option("--project <projectId>").description("List runs").action(async (options) => {
|
|
@@ -9794,7 +9855,7 @@ program2.command("models:list").description("List exported models").action(async
|
|
|
9794
9855
|
printJson(await createClient(loadConfig()).models.list());
|
|
9795
9856
|
});
|
|
9796
9857
|
program2.command("models:export").argument("<modelId>").description("Fetch the export package path for a model").action(async (modelId) => {
|
|
9797
|
-
printJson(await createClient(loadConfig()).models.export(
|
|
9858
|
+
printJson(await createClient(loadConfig()).models.export(normalizeId(modelId, "model", "Model ID")));
|
|
9798
9859
|
});
|
|
9799
9860
|
program2.command("deployments:list").description("List deployments").action(async () => {
|
|
9800
9861
|
printJson(await createClient(loadConfig()).deployments.list());
|
|
@@ -9849,9 +9910,9 @@ program2.command("treasury:funding").description("List supplier funding summarie
|
|
|
9849
9910
|
program2.command("treasury:funding-preview").requiredOption("--estimated-supplier-cost <usd>").option("--supplier <supplierId>").option("--pool <poolId>").description("Preview treasury funding readiness for a supplier-backed launch").action(async (options) => {
|
|
9850
9911
|
printJson(
|
|
9851
9912
|
await createClient(loadConfig()).treasury.previewFunding({
|
|
9852
|
-
estimatedSupplierCostUsd:
|
|
9853
|
-
poolId: options.pool,
|
|
9854
|
-
supplier: options.supplier
|
|
9913
|
+
estimatedSupplierCostUsd: normalizePositiveUsd(options.estimatedSupplierCost, "Estimated supplier cost"),
|
|
9914
|
+
poolId: normalizeOptionalId(options.pool, "pool", "Pool ID"),
|
|
9915
|
+
supplier: normalizeOptionalId(options.supplier, "supplier", "Supplier ID")
|
|
9855
9916
|
})
|
|
9856
9917
|
);
|
|
9857
9918
|
});
|
|
@@ -9870,8 +9931,9 @@ program2.command("api-keys:list").description("List API keys").action(async () =
|
|
|
9870
9931
|
printJson(await createClient(loadConfig()).apiKeys.list());
|
|
9871
9932
|
});
|
|
9872
9933
|
program2.command("api-keys:revoke").argument("<apiKeyId>").description("Revoke an API key").action(async (apiKeyId) => {
|
|
9873
|
-
|
|
9874
|
-
|
|
9934
|
+
const normalizedApiKeyId = normalizeId(apiKeyId, "apiKey", "API key ID");
|
|
9935
|
+
await createClient(loadConfig()).apiKeys.revoke(normalizedApiKeyId);
|
|
9936
|
+
console.log(`Revoked API key ${normalizedApiKeyId}.`);
|
|
9875
9937
|
});
|
|
9876
9938
|
program2.command("service-accounts:create").requiredOption("--name <name>").option("--scopes <scopes>", "comma-separated scopes", "org:read,project:read,project:write,dataset:read,dataset:write,run:read,run:write").description("Create a service account").action(async (options) => {
|
|
9877
9939
|
printJson(
|
|
@@ -9885,8 +9947,9 @@ program2.command("service-accounts:list").description("List service accounts").a
|
|
|
9885
9947
|
printJson(await createClient(loadConfig()).serviceAccounts.list());
|
|
9886
9948
|
});
|
|
9887
9949
|
program2.command("service-accounts:revoke").argument("<serviceAccountId>").description("Revoke a service account").action(async (serviceAccountId) => {
|
|
9888
|
-
|
|
9889
|
-
|
|
9950
|
+
const normalizedServiceAccountId = normalizeId(serviceAccountId, "serviceAccount", "Service account ID");
|
|
9951
|
+
await createClient(loadConfig()).serviceAccounts.revoke(normalizedServiceAccountId);
|
|
9952
|
+
console.log(`Revoked service account ${normalizedServiceAccountId}.`);
|
|
9890
9953
|
});
|
|
9891
9954
|
void program2.parseAsync(process.argv).catch((error) => {
|
|
9892
9955
|
console.error(error instanceof Error ? error.message : String(error));
|