trainfabric 0.1.23 → 0.1.24
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 +62 -12
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8816,6 +8816,11 @@ var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
|
8816
8816
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
8817
8817
|
var import_node_os = __toESM(require("node:os"), 1);
|
|
8818
8818
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
8819
|
+
var idPatterns = {
|
|
8820
|
+
org: /^org_[A-Za-z0-9_-]+$/,
|
|
8821
|
+
project: /^proj_[A-Za-z0-9_-]+$/,
|
|
8822
|
+
run: /^run_[A-Za-z0-9_-]+$/
|
|
8823
|
+
};
|
|
8819
8824
|
function collectRuntimeFiles(repoPath) {
|
|
8820
8825
|
const manifestFiles = /* @__PURE__ */ new Set([
|
|
8821
8826
|
"training.yaml",
|
|
@@ -8912,6 +8917,29 @@ function parseApiKeyScopes(input) {
|
|
|
8912
8917
|
}
|
|
8913
8918
|
return scopes;
|
|
8914
8919
|
}
|
|
8920
|
+
function normalizeHumanName(value, label) {
|
|
8921
|
+
let name = String(value ?? "").trim();
|
|
8922
|
+
while (name.length >= 2 && (name.startsWith("'") && name.endsWith("'") || name.startsWith('"') && name.endsWith('"'))) {
|
|
8923
|
+
name = name.slice(1, -1).trim();
|
|
8924
|
+
}
|
|
8925
|
+
if (!/[A-Za-z0-9]/.test(name)) {
|
|
8926
|
+
throw new Error(`${label} is required.`);
|
|
8927
|
+
}
|
|
8928
|
+
return name;
|
|
8929
|
+
}
|
|
8930
|
+
function normalizeId(value, kind, label) {
|
|
8931
|
+
const id = String(value ?? "").trim();
|
|
8932
|
+
if (!id || !idPatterns[kind].test(id)) {
|
|
8933
|
+
throw new Error(`${label} is invalid.`);
|
|
8934
|
+
}
|
|
8935
|
+
return id;
|
|
8936
|
+
}
|
|
8937
|
+
function normalizeOptionalId(value, kind, label) {
|
|
8938
|
+
if (value === void 0) {
|
|
8939
|
+
return void 0;
|
|
8940
|
+
}
|
|
8941
|
+
return normalizeId(value, kind, label);
|
|
8942
|
+
}
|
|
8915
8943
|
|
|
8916
8944
|
// src/run_input.ts
|
|
8917
8945
|
var BASE_MODEL_ALIASES = {
|
|
@@ -8954,7 +8982,7 @@ function buildComputeSpec(options) {
|
|
|
8954
8982
|
|
|
8955
8983
|
// src/index.ts
|
|
8956
8984
|
var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
|
|
8957
|
-
var CLI_VERSION = "0.1.
|
|
8985
|
+
var CLI_VERSION = "0.1.24";
|
|
8958
8986
|
var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
|
|
8959
8987
|
var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
|
|
8960
8988
|
var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
|
|
@@ -9293,7 +9321,7 @@ function visibleConfig(config) {
|
|
|
9293
9321
|
};
|
|
9294
9322
|
}
|
|
9295
9323
|
function requireProjectId(options, config) {
|
|
9296
|
-
const projectId = options.project ?? config.projectId;
|
|
9324
|
+
const projectId = normalizeOptionalId(options.project ?? config.projectId, "project", "Project ID");
|
|
9297
9325
|
if (!projectId) {
|
|
9298
9326
|
throw new Error("Project is required. Pass --project <projectId> or run `trainfabric config:set-project <projectId>`.");
|
|
9299
9327
|
}
|
|
@@ -9418,6 +9446,17 @@ function createClient(config) {
|
|
|
9418
9446
|
projectId: config.projectId
|
|
9419
9447
|
});
|
|
9420
9448
|
}
|
|
9449
|
+
function assertReadableFile(filePath, label) {
|
|
9450
|
+
let stats;
|
|
9451
|
+
try {
|
|
9452
|
+
stats = import_node_fs2.default.statSync(filePath);
|
|
9453
|
+
} catch {
|
|
9454
|
+
throw new Error(`${label} not found: ${filePath}`);
|
|
9455
|
+
}
|
|
9456
|
+
if (!stats.isFile()) {
|
|
9457
|
+
throw new Error(`${label} must be a file: ${filePath}`);
|
|
9458
|
+
}
|
|
9459
|
+
}
|
|
9421
9460
|
function normalizeHttpBaseUrl(value) {
|
|
9422
9461
|
let url;
|
|
9423
9462
|
try {
|
|
@@ -9485,8 +9524,9 @@ program2.command("config:set-base-url").argument("<baseUrl>").description("Set t
|
|
|
9485
9524
|
printJson(visibleConfig(config));
|
|
9486
9525
|
});
|
|
9487
9526
|
program2.command("config:set-org").argument("<orgId>").description("Set the default organization ID").action(async (orgId) => {
|
|
9527
|
+
const normalizedOrgId = normalizeId(orgId, "org", "Organization ID");
|
|
9488
9528
|
const currentConfig = loadConfig();
|
|
9489
|
-
const organization = await createClient(currentConfig).organizations.get(
|
|
9529
|
+
const organization = await createClient(currentConfig).organizations.get(normalizedOrgId);
|
|
9490
9530
|
const updatedConfig = updateConfig((current) => {
|
|
9491
9531
|
current.orgId = organization.id;
|
|
9492
9532
|
if (current.projectId) {
|
|
@@ -9496,8 +9536,9 @@ program2.command("config:set-org").argument("<orgId>").description("Set the defa
|
|
|
9496
9536
|
printJson(visibleConfig(updatedConfig));
|
|
9497
9537
|
});
|
|
9498
9538
|
program2.command("config:set-project").argument("<projectId>").description("Set the default project ID").action(async (projectId) => {
|
|
9539
|
+
const normalizedProjectId = normalizeId(projectId, "project", "Project ID");
|
|
9499
9540
|
const currentConfig = loadConfig();
|
|
9500
|
-
const project = await createClient(currentConfig).projects.get(
|
|
9541
|
+
const project = await createClient(currentConfig).projects.get(normalizedProjectId);
|
|
9501
9542
|
if (currentConfig.orgId && project.organizationId !== currentConfig.orgId) {
|
|
9502
9543
|
throw new Error(`Project ${project.id} does not belong to configured organization ${currentConfig.orgId}.`);
|
|
9503
9544
|
}
|
|
@@ -9532,9 +9573,15 @@ program2.command("projects:list").description("List projects in the active organ
|
|
|
9532
9573
|
printJson(await createClient(loadConfig()).projects.list());
|
|
9533
9574
|
});
|
|
9534
9575
|
program2.command("projects:create").requiredOption("--name <name>").option("--org <organizationId>").description("Create a project").action(async (options) => {
|
|
9535
|
-
printJson(
|
|
9576
|
+
printJson(
|
|
9577
|
+
await createClient(loadConfig()).projects.create({
|
|
9578
|
+
name: normalizeHumanName(options.name, "Project name"),
|
|
9579
|
+
organizationId: normalizeOptionalId(options.org, "org", "Organization ID")
|
|
9580
|
+
})
|
|
9581
|
+
);
|
|
9536
9582
|
});
|
|
9537
9583
|
program2.command("datasets:validate").argument("<file>").description("Validate a local dataset file").action(async (file) => {
|
|
9584
|
+
assertReadableFile(file, "Dataset path");
|
|
9538
9585
|
const validation = await createClient(loadConfig()).datasets.validate({
|
|
9539
9586
|
path: file,
|
|
9540
9587
|
format: "chat_jsonl"
|
|
@@ -9545,7 +9592,7 @@ program2.command("datasets:validate").argument("<file>").description("Validate a
|
|
|
9545
9592
|
}
|
|
9546
9593
|
});
|
|
9547
9594
|
program2.command("datasets:list").option("--project <projectId>").description("List datasets").action(async (options) => {
|
|
9548
|
-
printJson(await createClient(loadConfig()).datasets.list(options.project));
|
|
9595
|
+
printJson(await createClient(loadConfig()).datasets.list(normalizeOptionalId(options.project, "project", "Project ID")));
|
|
9549
9596
|
});
|
|
9550
9597
|
program2.command("datasets:get").argument("<datasetId>").description("Fetch dataset detail").action(async (datasetId) => {
|
|
9551
9598
|
printJson(await createClient(loadConfig()).datasets.get(String(datasetId)));
|
|
@@ -9555,12 +9602,15 @@ program2.command("datasets:delete").argument("<datasetId>").description("Delete
|
|
|
9555
9602
|
printJson({ deleted: true, id: String(datasetId) });
|
|
9556
9603
|
});
|
|
9557
9604
|
program2.command("datasets:upload").argument("<file>").option("--project <projectId>").option("--name <name>").description("Upload a dataset through upload sessions").action(async (file, options) => {
|
|
9605
|
+
assertReadableFile(file, "Dataset path");
|
|
9558
9606
|
const config = loadConfig();
|
|
9607
|
+
const projectId = normalizeOptionalId(options.project ?? config.projectId, "project", "Project ID");
|
|
9608
|
+
const name = options.name === void 0 ? void 0 : normalizeHumanName(options.name, "Dataset name");
|
|
9559
9609
|
const dataset = await createClient(config).datasets.create({
|
|
9560
9610
|
path: file,
|
|
9561
9611
|
format: "chat_jsonl",
|
|
9562
|
-
name
|
|
9563
|
-
projectId
|
|
9612
|
+
name,
|
|
9613
|
+
projectId
|
|
9564
9614
|
});
|
|
9565
9615
|
printJson(dataset);
|
|
9566
9616
|
});
|
|
@@ -9609,7 +9659,7 @@ program2.command("runs:quote").option("--project <projectId>").requiredOption("-
|
|
|
9609
9659
|
}
|
|
9610
9660
|
});
|
|
9611
9661
|
program2.command("runs:list").option("--project <projectId>").description("List runs").action(async (options) => {
|
|
9612
|
-
printJson(await createClient(loadConfig()).runs.list(options.project));
|
|
9662
|
+
printJson(await createClient(loadConfig()).runs.list(normalizeOptionalId(options.project, "project", "Project ID")));
|
|
9613
9663
|
});
|
|
9614
9664
|
program2.command("runs:status").argument("<runId>").description("Fetch full run detail").action(async (runId) => {
|
|
9615
9665
|
printJson(await createClient(loadConfig()).runs.get(String(runId)));
|
|
@@ -9691,7 +9741,7 @@ program2.command("billing:summary").description("Fetch billing summary").action(
|
|
|
9691
9741
|
printJson(await createClient(loadConfig()).billing.getSummary());
|
|
9692
9742
|
});
|
|
9693
9743
|
program2.command("billing:usage").option("--unit <unit>", "normalized_tflop_seconds, reserved_gpu_seconds, or usd").option("--run <runId>", "filter usage records to one run").description("List billing usage records").action(async (options) => {
|
|
9694
|
-
printJson(await createClient(loadConfig()).billing.getUsage(options.unit, options.run));
|
|
9744
|
+
printJson(await createClient(loadConfig()).billing.getUsage(options.unit, normalizeOptionalId(options.run, "run", "Run ID")));
|
|
9695
9745
|
});
|
|
9696
9746
|
program2.command("billing:invoices").description("List invoices").action(async () => {
|
|
9697
9747
|
printJson(await createClient(loadConfig()).billing.listInvoices());
|
|
@@ -9724,7 +9774,7 @@ program2.command("api-keys:create").requiredOption("--name <name>").option("--ow
|
|
|
9724
9774
|
const config = loadConfig();
|
|
9725
9775
|
const session = await createClient(config).auth.me();
|
|
9726
9776
|
const apiKey = await createClient(config).apiKeys.create({
|
|
9727
|
-
name: options.name,
|
|
9777
|
+
name: normalizeHumanName(options.name, "API key name"),
|
|
9728
9778
|
ownerType: options.ownerType,
|
|
9729
9779
|
ownerId: options.ownerId ?? session.user.id,
|
|
9730
9780
|
scopes: parseApiKeyScopes(String(options.scopes))
|
|
@@ -9741,7 +9791,7 @@ program2.command("api-keys:revoke").argument("<apiKeyId>").description("Revoke a
|
|
|
9741
9791
|
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) => {
|
|
9742
9792
|
printJson(
|
|
9743
9793
|
await createClient(loadConfig()).serviceAccounts.create({
|
|
9744
|
-
name: options.name,
|
|
9794
|
+
name: normalizeHumanName(options.name, "Service account name"),
|
|
9745
9795
|
scopes: parseApiKeyScopes(String(options.scopes))
|
|
9746
9796
|
})
|
|
9747
9797
|
);
|