trainfabric 0.1.28 → 0.1.30
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 +2 -0
- package/dist/index.cjs +125 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,8 @@ Secrets are stored in macOS Keychain when available. Other platforms use an encr
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
trainfabric projects:list
|
|
29
|
+
trainfabric projects:create --name <name>
|
|
30
|
+
trainfabric projects:delete <projectId>
|
|
29
31
|
trainfabric datasets:upload ./train.jsonl --project <projectId>
|
|
30
32
|
trainfabric runs:quote --summary --project <projectId> --dataset <datasetId> --model llama-3-8b
|
|
31
33
|
trainfabric runs:create --yes --quote <quoteId> --project <projectId> --dataset <datasetId> --model llama-3-8b
|
package/dist/index.cjs
CHANGED
|
@@ -8077,6 +8077,15 @@ var ResourceClient = class {
|
|
|
8077
8077
|
};
|
|
8078
8078
|
|
|
8079
8079
|
// ../sdk/dist/client/admin.js
|
|
8080
|
+
var apiKeyIdPattern = /^key_[A-Za-z0-9_-]+$/;
|
|
8081
|
+
var serviceAccountIdPattern = /^svc_[A-Za-z0-9_-]+$/;
|
|
8082
|
+
function normalizeRequiredId(value, pattern, label) {
|
|
8083
|
+
const id = String(value ?? "").trim();
|
|
8084
|
+
if (!pattern.test(id)) {
|
|
8085
|
+
throw new Error(`${label} is invalid.`);
|
|
8086
|
+
}
|
|
8087
|
+
return encodeURIComponent(id);
|
|
8088
|
+
}
|
|
8080
8089
|
var ApiKeysClient = class extends ResourceClient {
|
|
8081
8090
|
create(input) {
|
|
8082
8091
|
apiKeyCreateSchema.parse(input);
|
|
@@ -8086,7 +8095,7 @@ var ApiKeysClient = class extends ResourceClient {
|
|
|
8086
8095
|
return this.requestGet("/v1/api-keys");
|
|
8087
8096
|
}
|
|
8088
8097
|
revoke(apiKeyId) {
|
|
8089
|
-
return this.requestDelete(`/v1/api-keys/${apiKeyId}`);
|
|
8098
|
+
return this.requestDelete(`/v1/api-keys/${normalizeRequiredId(apiKeyId, apiKeyIdPattern, "API key ID")}`);
|
|
8090
8099
|
}
|
|
8091
8100
|
};
|
|
8092
8101
|
var ServiceAccountsClient = class extends ResourceClient {
|
|
@@ -8098,7 +8107,7 @@ var ServiceAccountsClient = class extends ResourceClient {
|
|
|
8098
8107
|
return this.requestGet("/v1/service-accounts");
|
|
8099
8108
|
}
|
|
8100
8109
|
revoke(serviceAccountId) {
|
|
8101
|
-
return this.requestDelete(`/v1/service-accounts/${serviceAccountId}`);
|
|
8110
|
+
return this.requestDelete(`/v1/service-accounts/${normalizeRequiredId(serviceAccountId, serviceAccountIdPattern, "Service account ID")}`);
|
|
8102
8111
|
}
|
|
8103
8112
|
};
|
|
8104
8113
|
|
|
@@ -8164,6 +8173,14 @@ var ClusterClient = class extends ResourceClient {
|
|
|
8164
8173
|
// ../sdk/dist/client/datasets.js
|
|
8165
8174
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
8166
8175
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
8176
|
+
var datasetIdPattern = /^ds_[A-Za-z0-9_-]+$/;
|
|
8177
|
+
function encodeDatasetId(datasetId) {
|
|
8178
|
+
const id = String(datasetId ?? "").trim();
|
|
8179
|
+
if (!datasetIdPattern.test(id)) {
|
|
8180
|
+
throw new Error("Dataset ID is invalid.");
|
|
8181
|
+
}
|
|
8182
|
+
return encodeURIComponent(id);
|
|
8183
|
+
}
|
|
8167
8184
|
var DatasetsClient = class extends ResourceClient {
|
|
8168
8185
|
async create(input) {
|
|
8169
8186
|
const validation = await this.validate({
|
|
@@ -8178,7 +8195,7 @@ var DatasetsClient = class extends ResourceClient {
|
|
|
8178
8195
|
throw new Error("projectId is required.");
|
|
8179
8196
|
}
|
|
8180
8197
|
const fileName = import_node_path.default.basename(input.path);
|
|
8181
|
-
const fileBuffer = await
|
|
8198
|
+
const fileBuffer = await readDatasetFile(input.path);
|
|
8182
8199
|
const uploadSessionInput = uploadSessionCreateSchema.parse({
|
|
8183
8200
|
projectId,
|
|
8184
8201
|
fileName,
|
|
@@ -8204,21 +8221,46 @@ var DatasetsClient = class extends ResourceClient {
|
|
|
8204
8221
|
if (input.format !== "chat_jsonl") {
|
|
8205
8222
|
throw new Error("Only chat_jsonl datasets are supported.");
|
|
8206
8223
|
}
|
|
8207
|
-
return validateChatJsonl(await
|
|
8224
|
+
return validateChatJsonl(await readDatasetFile(input.path, "utf8"));
|
|
8208
8225
|
}
|
|
8209
8226
|
get(datasetId) {
|
|
8210
|
-
return this.requestGet(`/v1/datasets/${datasetId}`);
|
|
8227
|
+
return this.requestGet(`/v1/datasets/${encodeDatasetId(datasetId)}`);
|
|
8211
8228
|
}
|
|
8212
8229
|
list(projectId) {
|
|
8213
8230
|
const effectiveProjectId = projectId ?? this.parent.projectId;
|
|
8214
|
-
|
|
8231
|
+
const params = new URLSearchParams();
|
|
8232
|
+
if (effectiveProjectId) {
|
|
8233
|
+
params.set("projectId", effectiveProjectId);
|
|
8234
|
+
}
|
|
8235
|
+
const query = params.toString();
|
|
8236
|
+
return this.requestGet(`/v1/datasets${query ? `?${query}` : ""}`);
|
|
8215
8237
|
}
|
|
8216
8238
|
delete(datasetId) {
|
|
8217
|
-
return this.requestDelete(`/v1/datasets/${datasetId}`);
|
|
8239
|
+
return this.requestDelete(`/v1/datasets/${encodeDatasetId(datasetId)}`);
|
|
8218
8240
|
}
|
|
8219
8241
|
};
|
|
8242
|
+
async function readDatasetFile(pathname, encoding) {
|
|
8243
|
+
let stats;
|
|
8244
|
+
try {
|
|
8245
|
+
stats = await import_promises.default.stat(pathname);
|
|
8246
|
+
} catch {
|
|
8247
|
+
throw new Error(`Dataset file not found: ${pathname}`);
|
|
8248
|
+
}
|
|
8249
|
+
if (!stats.isFile()) {
|
|
8250
|
+
throw new Error(`Dataset path must be a file: ${pathname}`);
|
|
8251
|
+
}
|
|
8252
|
+
return encoding ? import_promises.default.readFile(pathname, encoding) : import_promises.default.readFile(pathname);
|
|
8253
|
+
}
|
|
8220
8254
|
|
|
8221
8255
|
// ../sdk/dist/client/deployments.js
|
|
8256
|
+
var deploymentIdPattern = /^dep_[A-Za-z0-9_-]+$/;
|
|
8257
|
+
function encodeDeploymentId(deploymentId) {
|
|
8258
|
+
const id = String(deploymentId ?? "").trim();
|
|
8259
|
+
if (!deploymentIdPattern.test(id)) {
|
|
8260
|
+
throw new Error("Deployment ID is invalid.");
|
|
8261
|
+
}
|
|
8262
|
+
return encodeURIComponent(id);
|
|
8263
|
+
}
|
|
8222
8264
|
var DeploymentsClient = class extends ResourceClient {
|
|
8223
8265
|
list() {
|
|
8224
8266
|
return this.requestGet("/v1/deployments");
|
|
@@ -8227,23 +8269,31 @@ var DeploymentsClient = class extends ResourceClient {
|
|
|
8227
8269
|
return this.requestPost("/v1/deployments", input);
|
|
8228
8270
|
}
|
|
8229
8271
|
get(id) {
|
|
8230
|
-
return this.requestGet(`/v1/deployments/${id}`);
|
|
8272
|
+
return this.requestGet(`/v1/deployments/${encodeDeploymentId(id)}`);
|
|
8231
8273
|
}
|
|
8232
8274
|
delete(id) {
|
|
8233
|
-
return this.requestDelete(`/v1/deployments/${id}`);
|
|
8275
|
+
return this.requestDelete(`/v1/deployments/${encodeDeploymentId(id)}`);
|
|
8234
8276
|
}
|
|
8235
8277
|
};
|
|
8236
8278
|
|
|
8237
8279
|
// ../sdk/dist/client/models.js
|
|
8280
|
+
var modelIdPattern = /^mdl_[A-Za-z0-9_-]+$/;
|
|
8281
|
+
function normalizeModelId(modelId) {
|
|
8282
|
+
const normalized = String(modelId ?? "").trim();
|
|
8283
|
+
if (!modelIdPattern.test(normalized)) {
|
|
8284
|
+
throw new Error("Model ID is invalid.");
|
|
8285
|
+
}
|
|
8286
|
+
return encodeURIComponent(normalized);
|
|
8287
|
+
}
|
|
8238
8288
|
var ModelsClient = class extends ResourceClient {
|
|
8239
8289
|
list() {
|
|
8240
8290
|
return this.requestGet("/v1/models");
|
|
8241
8291
|
}
|
|
8242
8292
|
get(modelId) {
|
|
8243
|
-
return this.requestGet(`/v1/models/${modelId}`);
|
|
8293
|
+
return this.requestGet(`/v1/models/${normalizeModelId(modelId)}`);
|
|
8244
8294
|
}
|
|
8245
8295
|
export(modelId) {
|
|
8246
|
-
return this.requestPost(`/v1/models/${modelId}/export`);
|
|
8296
|
+
return this.requestPost(`/v1/models/${normalizeModelId(modelId)}/export`);
|
|
8247
8297
|
}
|
|
8248
8298
|
};
|
|
8249
8299
|
|
|
@@ -8255,12 +8305,20 @@ var ProjectsClient = class extends ResourceClient {
|
|
|
8255
8305
|
organizationId: input.organizationId ?? this.parent.orgId
|
|
8256
8306
|
});
|
|
8257
8307
|
}
|
|
8308
|
+
delete(projectId) {
|
|
8309
|
+
return this.requestDelete(`/v1/projects/${projectId}`);
|
|
8310
|
+
}
|
|
8258
8311
|
get(projectId) {
|
|
8259
8312
|
return this.requestGet(`/v1/projects/${projectId}`);
|
|
8260
8313
|
}
|
|
8261
8314
|
list(organizationId) {
|
|
8262
8315
|
const suffix = organizationId ?? this.parent.orgId;
|
|
8263
|
-
|
|
8316
|
+
const params = new URLSearchParams();
|
|
8317
|
+
if (suffix) {
|
|
8318
|
+
params.set("organizationId", suffix);
|
|
8319
|
+
}
|
|
8320
|
+
const query = params.toString();
|
|
8321
|
+
return this.requestGet(`/v1/projects${query ? `?${query}` : ""}`);
|
|
8264
8322
|
}
|
|
8265
8323
|
};
|
|
8266
8324
|
var OrganizationsClient = class extends ResourceClient {
|
|
@@ -8514,6 +8572,14 @@ var RunHandle = class {
|
|
|
8514
8572
|
};
|
|
8515
8573
|
|
|
8516
8574
|
// ../sdk/dist/client/runs.js
|
|
8575
|
+
var runIdPattern = /^run_[A-Za-z0-9_-]+$/;
|
|
8576
|
+
function encodeRunId(runId) {
|
|
8577
|
+
const id = String(runId ?? "").trim();
|
|
8578
|
+
if (!runIdPattern.test(id)) {
|
|
8579
|
+
throw new Error("Run ID is invalid.");
|
|
8580
|
+
}
|
|
8581
|
+
return encodeURIComponent(id);
|
|
8582
|
+
}
|
|
8517
8583
|
var RunsClient = class extends ResourceClient {
|
|
8518
8584
|
describeEmptyQuoteFailure(input) {
|
|
8519
8585
|
const compute = input.compute && input.compute !== "auto" && input.compute !== "cpu-sim" ? input.compute : void 0;
|
|
@@ -8616,42 +8682,47 @@ var RunsClient = class extends ResourceClient {
|
|
|
8616
8682
|
return new RunHandle(this.parent, run);
|
|
8617
8683
|
}
|
|
8618
8684
|
get(runId) {
|
|
8619
|
-
return this.requestGet(`/v1/runs/${runId}`);
|
|
8685
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}`);
|
|
8620
8686
|
}
|
|
8621
8687
|
list(projectId) {
|
|
8622
8688
|
const effectiveProjectId = projectId ?? this.parent.projectId;
|
|
8623
|
-
|
|
8689
|
+
const params = new URLSearchParams();
|
|
8690
|
+
if (effectiveProjectId) {
|
|
8691
|
+
params.set("projectId", effectiveProjectId);
|
|
8692
|
+
}
|
|
8693
|
+
const query = params.toString();
|
|
8694
|
+
return this.requestGet(`/v1/runs${query ? `?${query}` : ""}`);
|
|
8624
8695
|
}
|
|
8625
8696
|
cancel(runId) {
|
|
8626
|
-
return this.requestPost(`/v1/runs/${runId}/cancel`);
|
|
8697
|
+
return this.requestPost(`/v1/runs/${encodeRunId(runId)}/cancel`);
|
|
8627
8698
|
}
|
|
8628
8699
|
resume(runId) {
|
|
8629
|
-
return this.requestPost(`/v1/runs/${runId}/resume`);
|
|
8700
|
+
return this.requestPost(`/v1/runs/${encodeRunId(runId)}/resume`);
|
|
8630
8701
|
}
|
|
8631
8702
|
terminate(runId) {
|
|
8632
|
-
return this.requestPost(`/v1/runs/${runId}/terminate`);
|
|
8703
|
+
return this.requestPost(`/v1/runs/${encodeRunId(runId)}/terminate`);
|
|
8633
8704
|
}
|
|
8634
8705
|
logs(runId) {
|
|
8635
|
-
return this.requestGet(`/v1/runs/${runId}/logs`);
|
|
8706
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/logs`);
|
|
8636
8707
|
}
|
|
8637
8708
|
async watch(runId) {
|
|
8638
8709
|
const detail = await this.get(runId);
|
|
8639
8710
|
return new RunHandle(this.parent, detail.run);
|
|
8640
8711
|
}
|
|
8641
8712
|
allocation(runId) {
|
|
8642
|
-
return this.requestGet(`/v1/runs/${runId}/allocation`);
|
|
8713
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/allocation`);
|
|
8643
8714
|
}
|
|
8644
8715
|
usage(runId) {
|
|
8645
|
-
return this.requestGet(`/v1/runs/${runId}/usage`);
|
|
8716
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/usage`);
|
|
8646
8717
|
}
|
|
8647
8718
|
costBreakdown(runId) {
|
|
8648
|
-
return this.requestGet(`/v1/runs/${runId}/cost-breakdown`);
|
|
8719
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/cost-breakdown`);
|
|
8649
8720
|
}
|
|
8650
8721
|
configuration(runId) {
|
|
8651
|
-
return this.requestGet(`/v1/runs/${runId}/configuration`);
|
|
8722
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/configuration`);
|
|
8652
8723
|
}
|
|
8653
8724
|
explanation(runId) {
|
|
8654
|
-
return this.requestGet(`/v1/runs/${runId}/explanation`);
|
|
8725
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/explanation`);
|
|
8655
8726
|
}
|
|
8656
8727
|
async wait(runId, options) {
|
|
8657
8728
|
const handle = await this.watch(runId);
|
|
@@ -8823,6 +8894,7 @@ var idPatterns = {
|
|
|
8823
8894
|
apiKey: /^key_[A-Za-z0-9_-]+$/,
|
|
8824
8895
|
dataset: /^ds_[A-Za-z0-9_-]+$/,
|
|
8825
8896
|
deployment: /^dep_[A-Za-z0-9_-]+$/,
|
|
8897
|
+
detection: /^det_[A-Za-z0-9_-]+$/,
|
|
8826
8898
|
model: /^mdl_[A-Za-z0-9_-]+$/,
|
|
8827
8899
|
org: /^org_[A-Za-z0-9_-]+$/,
|
|
8828
8900
|
pool: /^pool_[A-Za-z0-9_-]+$/,
|
|
@@ -8919,7 +8991,12 @@ function validateRepoPath(repoPath) {
|
|
|
8919
8991
|
if (absolute === parsed.root || absolute === import_node_os.default.homedir()) {
|
|
8920
8992
|
throw new Error(`Refusing to package unsafe repository path: ${repoPath}`);
|
|
8921
8993
|
}
|
|
8922
|
-
|
|
8994
|
+
let stat;
|
|
8995
|
+
try {
|
|
8996
|
+
stat = import_node_fs.default.statSync(absolute);
|
|
8997
|
+
} catch {
|
|
8998
|
+
throw new Error(`Repository path not found: ${repoPath}`);
|
|
8999
|
+
}
|
|
8923
9000
|
if (!stat.isDirectory()) {
|
|
8924
9001
|
throw new Error(`Repository path must be a directory: ${repoPath}`);
|
|
8925
9002
|
}
|
|
@@ -9133,7 +9210,7 @@ function buildComputeSpec(options) {
|
|
|
9133
9210
|
|
|
9134
9211
|
// src/index.ts
|
|
9135
9212
|
var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
|
|
9136
|
-
var CLI_VERSION = "0.1.
|
|
9213
|
+
var CLI_VERSION = "0.1.30";
|
|
9137
9214
|
var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
|
|
9138
9215
|
var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
|
|
9139
9216
|
var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
|
|
@@ -9755,6 +9832,11 @@ program2.command("projects:create").requiredOption("--name <name>").option("--or
|
|
|
9755
9832
|
})
|
|
9756
9833
|
);
|
|
9757
9834
|
});
|
|
9835
|
+
program2.command("projects:delete").argument("<projectId>").description("Delete an empty project").action(async (projectId) => {
|
|
9836
|
+
const normalizedProjectId = normalizeId(projectId, "project", "Project ID");
|
|
9837
|
+
await createClient(loadConfig()).projects.delete(normalizedProjectId);
|
|
9838
|
+
printJson({ deleted: true, id: normalizedProjectId });
|
|
9839
|
+
});
|
|
9758
9840
|
program2.command("datasets:validate").argument("<file>").description("Validate a local dataset file").action(async (file) => {
|
|
9759
9841
|
assertReadableFile(file, "Dataset path");
|
|
9760
9842
|
const validation = await createClient(loadConfig()).datasets.validate({
|
|
@@ -9806,10 +9888,23 @@ program2.command("runtime:detect").option("--project <projectId>").option("--rep
|
|
|
9806
9888
|
throw new Error("Provide --repo or --git.");
|
|
9807
9889
|
}
|
|
9808
9890
|
const config = loadConfig();
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9891
|
+
let detection;
|
|
9892
|
+
try {
|
|
9893
|
+
detection = await createClient(config).runtime.detect({
|
|
9894
|
+
projectId: requireProjectId(options, config),
|
|
9895
|
+
source: sourceOptions.source
|
|
9896
|
+
});
|
|
9897
|
+
} catch (error) {
|
|
9898
|
+
if (sourceOptions.source.kind === "git" && error instanceof Error && /Request failed with status 404/.test(error.message)) {
|
|
9899
|
+
throw new Error("Git repository could not be resolved. Check the repository URL, branch, and access permissions.");
|
|
9900
|
+
}
|
|
9901
|
+
throw error;
|
|
9902
|
+
}
|
|
9903
|
+
if (sourceOptions.source.kind === "git" && detection.status !== "detected") {
|
|
9904
|
+
throw new Error(
|
|
9905
|
+
`Runtime source is ${detection.status}. Git repository could not be resolved into a supported runtime source.`
|
|
9906
|
+
);
|
|
9907
|
+
}
|
|
9813
9908
|
printJson(redactInlineSource(detection));
|
|
9814
9909
|
});
|
|
9815
9910
|
program2.command("runtime:build").option("--project <projectId>").requiredOption("--detection <detectionId>").description("Build or reuse a cached runtime image from a runtime detection").action(async (options) => {
|
|
@@ -9817,7 +9912,7 @@ program2.command("runtime:build").option("--project <projectId>").requiredOption
|
|
|
9817
9912
|
printJson(
|
|
9818
9913
|
await createClient(config).runtime.build({
|
|
9819
9914
|
projectId: requireProjectId(options, config),
|
|
9820
|
-
detectionId: options.detection
|
|
9915
|
+
detectionId: normalizeId(options.detection, "detection", "Runtime detection ID")
|
|
9821
9916
|
})
|
|
9822
9917
|
);
|
|
9823
9918
|
});
|