@tuned-tensor/cli 0.26.2 → 0.27.0
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 +8 -0
- package/dist/index.js +239 -103
- package/dist/index.js.map +1 -1
- package/docs/local-runtime/decision.md +2 -1
- package/docs/local-runtime/hosting.md +121 -0
- package/package.json +1 -1
- package/training/serving/uv.lock +3 -3
package/dist/index.js
CHANGED
|
@@ -1050,9 +1050,9 @@ async function launchBackgroundSupervisor(args2) {
|
|
|
1050
1050
|
stdio: "ignore"
|
|
1051
1051
|
});
|
|
1052
1052
|
if (child.pid === void 0) {
|
|
1053
|
-
await new Promise((
|
|
1053
|
+
await new Promise((resolve14, reject) => {
|
|
1054
1054
|
child.once("error", reject);
|
|
1055
|
-
child.once("spawn", () =>
|
|
1055
|
+
child.once("spawn", () => resolve14());
|
|
1056
1056
|
});
|
|
1057
1057
|
}
|
|
1058
1058
|
} catch (error) {
|
|
@@ -1117,15 +1117,15 @@ async function superviseBackgroundRun(options) {
|
|
|
1117
1117
|
detached: process.platform !== "win32",
|
|
1118
1118
|
stdio: ["ignore", resultFd, logFd]
|
|
1119
1119
|
});
|
|
1120
|
-
const closed = new Promise((
|
|
1120
|
+
const closed = new Promise((resolve14) => {
|
|
1121
1121
|
child.once("error", (error) => {
|
|
1122
1122
|
state.spawnError = error;
|
|
1123
|
-
|
|
1123
|
+
resolve14();
|
|
1124
1124
|
});
|
|
1125
1125
|
child.once("close", (code2, signal) => {
|
|
1126
1126
|
state.exitCode = code2;
|
|
1127
1127
|
state.exitSignal = signal;
|
|
1128
|
-
|
|
1128
|
+
resolve14();
|
|
1129
1129
|
});
|
|
1130
1130
|
});
|
|
1131
1131
|
if (child.pid !== void 0) {
|
|
@@ -1705,7 +1705,7 @@ function formatCents(cents) {
|
|
|
1705
1705
|
return `$${(cents / 100).toFixed(2)}`;
|
|
1706
1706
|
}
|
|
1707
1707
|
function sleep(ms) {
|
|
1708
|
-
return new Promise((
|
|
1708
|
+
return new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
1709
1709
|
}
|
|
1710
1710
|
function isTransientError(error) {
|
|
1711
1711
|
if (error instanceof ApiError) return error.status === 429 || error.status >= 500;
|
|
@@ -2215,10 +2215,10 @@ function registerLabelCommands(parent) {
|
|
|
2215
2215
|
console.log(`Follow progress with \`tt cloud label watch ${shortId(job.id)}\`.`);
|
|
2216
2216
|
return;
|
|
2217
2217
|
}
|
|
2218
|
-
const
|
|
2219
|
-
if (isJsonMode()) return printJson(
|
|
2218
|
+
const finished2 = await watchJob(job.id, opts);
|
|
2219
|
+
if (isJsonMode()) return printJson(finished2);
|
|
2220
2220
|
printSuccess(
|
|
2221
|
-
`Labeling ${
|
|
2221
|
+
`Labeling ${finished2.status === "awaiting_review" ? "complete" : finished2.status}: ${finished2.labeled_count}/${finished2.row_count} rows labeled.`
|
|
2222
2222
|
);
|
|
2223
2223
|
console.log(
|
|
2224
2224
|
`Review with \`tt cloud label rows ${shortId(job.id)} --status labeled\`, then \`tt cloud label download ${shortId(job.id)}\` to write local training files.`
|
|
@@ -3577,7 +3577,7 @@ async function fetchHuggingFaceSearch(kind, query, limit, filters, options) {
|
|
|
3577
3577
|
let lastError = new Error("Hugging Face search failed.");
|
|
3578
3578
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
3579
3579
|
if (attempt > 0) {
|
|
3580
|
-
await new Promise((
|
|
3580
|
+
await new Promise((resolve14) => setTimeout(resolve14, options.huggingFaceRetryDelayMs ?? 750));
|
|
3581
3581
|
}
|
|
3582
3582
|
try {
|
|
3583
3583
|
const payload = await fetchHuggingFaceJson(url, options);
|
|
@@ -3958,7 +3958,7 @@ function createTunedTensorTools(api, options = {}) {
|
|
|
3958
3958
|
dry_run: "tt pipeline run --dry-run --spec tunedtensor.json",
|
|
3959
3959
|
run: "tt pipeline run --spec tunedtensor.json"
|
|
3960
3960
|
},
|
|
3961
|
-
note: "Runs locally on CPU, Apple MPS or CUDA; runtime.gpu (AWS) is not used. The tuned model directory loads in Python with laya.load(<model_dir>).",
|
|
3961
|
+
note: "Runs locally on CPU, Apple MPS or CUDA; runtime.gpu (AWS) is not used. The tuned model directory loads in Python with laya.load(<model_dir>). For paid serverless CPU hosting, the user can run tt cloud endpoints create --model <model_dir> --name <name>; see docs/local-runtime/hosting.md. This uploads weights to the TT account, returns an authenticated inference URL and scoped key, and charges prepaid credits per successful request.",
|
|
3962
3962
|
...host ? { host } : {}
|
|
3963
3963
|
};
|
|
3964
3964
|
}
|
|
@@ -4602,11 +4602,11 @@ function createLocalAgentClient(options) {
|
|
|
4602
4602
|
const runs = options.backgroundRuns?.store;
|
|
4603
4603
|
if (!runs) return void 0;
|
|
4604
4604
|
try {
|
|
4605
|
-
const
|
|
4606
|
-
if (
|
|
4607
|
-
await runs.markReported(
|
|
4605
|
+
const finished2 = (await runs.list()).filter((run) => run.requested_by.thread_id === threadId && !isActiveBackgroundRun(run) && !run.reported_at);
|
|
4606
|
+
if (finished2.length === 0) return void 0;
|
|
4607
|
+
await runs.markReported(finished2.map((run) => run.id));
|
|
4608
4608
|
return `[Background run outcomes, recorded by tt]
|
|
4609
|
-
${
|
|
4609
|
+
${finished2.map((run) => JSON.stringify(describeBackgroundRun(run))).join("\n")}
|
|
4610
4610
|
These runs finished since your last turn. Mention them briefly when relevant; use get_background_run for logs.`;
|
|
4611
4611
|
} catch {
|
|
4612
4612
|
return void 0;
|
|
@@ -6787,12 +6787,12 @@ async function promptKeyChoice(message, input = stdin, output = stdout) {
|
|
|
6787
6787
|
terminal.setRawMode(true);
|
|
6788
6788
|
input.resume();
|
|
6789
6789
|
output.write(`${message} ${hint()}`);
|
|
6790
|
-
const choice = await new Promise((
|
|
6790
|
+
const choice = await new Promise((resolve14) => {
|
|
6791
6791
|
const finish = (decision) => {
|
|
6792
6792
|
input.removeListener("keypress", onKeypress);
|
|
6793
6793
|
input.removeListener("end", onEnd);
|
|
6794
6794
|
input.removeListener("close", onEnd);
|
|
6795
|
-
|
|
6795
|
+
resolve14(decision);
|
|
6796
6796
|
};
|
|
6797
6797
|
const onKeypress = (text3, key) => {
|
|
6798
6798
|
const decided = keyChoiceFor(key, text3);
|
|
@@ -12272,31 +12272,166 @@ Eval Results (${data3._evals.length}):`);
|
|
|
12272
12272
|
});
|
|
12273
12273
|
}
|
|
12274
12274
|
|
|
12275
|
+
// src/commands/endpoints.ts
|
|
12276
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "crypto";
|
|
12277
|
+
import { createReadStream as createReadStream2, readFileSync as readFileSync11, statSync as statSync4, openSync as openSync3, readSync, closeSync as closeSync3 } from "fs";
|
|
12278
|
+
import { open as open4 } from "fs/promises";
|
|
12279
|
+
import { finished } from "stream/promises";
|
|
12280
|
+
import { resolve as resolve10, join as join15 } from "path";
|
|
12281
|
+
import { z } from "zod";
|
|
12282
|
+
async function inspectCheckpoint(modelPath) {
|
|
12283
|
+
const directory = resolve10(modelPath);
|
|
12284
|
+
const config = JSON.parse(readFileSync11(join15(directory, "rl_agent_config.json"), "utf8"));
|
|
12285
|
+
if (config.encoder !== "answerdotai/ModernBERT-large" || config.head_layers !== 2 || config.max_len !== 512 || config.head_max_len !== 192) {
|
|
12286
|
+
throw new Error("Hosting currently supports only the pinned English Laya checkpoint and TT decision fine-tunes.");
|
|
12287
|
+
}
|
|
12288
|
+
const kind = config.tuned_tensor ? "tuned" : "base";
|
|
12289
|
+
if (kind === "tuned" && (JSON.stringify(config.temperature) !== "[1,1,1]" || config.temperature_by_options)) {
|
|
12290
|
+
throw new Error("Custom calibration is not supported by hosted decision inference.");
|
|
12291
|
+
}
|
|
12292
|
+
const file = join15(directory, "model.safetensors");
|
|
12293
|
+
const size = statSync4(file).size;
|
|
12294
|
+
if (size <= 8 || size > 2e9) throw new Error("Weights must be a safetensors file smaller than 2 GB. GPU and adapter models are not supported.");
|
|
12295
|
+
const fd = openSync3(file, "r");
|
|
12296
|
+
try {
|
|
12297
|
+
const length = Buffer.alloc(8);
|
|
12298
|
+
if (readSync(fd, length, 0, 8, 0) !== 8) throw new Error("Invalid safetensors header.");
|
|
12299
|
+
const headerSize = Number(length.readBigUInt64LE());
|
|
12300
|
+
if (!Number.isSafeInteger(headerSize) || headerSize < 2 || headerSize > 1e6 || headerSize + 8 >= size) throw new Error("Invalid safetensors header.");
|
|
12301
|
+
const header = Buffer.alloc(headerSize);
|
|
12302
|
+
if (readSync(fd, header, 0, headerSize, 8) !== headerSize) throw new Error("Truncated safetensors header.");
|
|
12303
|
+
const tensors = JSON.parse(header.toString("utf8"));
|
|
12304
|
+
for (const prefix of ["encoder.", "type_emb.", "scorer.", "act_head."]) {
|
|
12305
|
+
if (!Object.keys(tensors).some((key) => key.startsWith(prefix))) throw new Error("Not a complete Laya checkpoint.");
|
|
12306
|
+
}
|
|
12307
|
+
} finally {
|
|
12308
|
+
closeSync3(fd);
|
|
12309
|
+
}
|
|
12310
|
+
const hash = createHash8("sha256");
|
|
12311
|
+
for await (const chunk of createReadStream2(file)) hash.update(chunk);
|
|
12312
|
+
return { file, weights_bytes: size, weights_sha256: hash.digest("hex"), checkpoint_kind: kind };
|
|
12313
|
+
}
|
|
12314
|
+
function readInferencePayload(file) {
|
|
12315
|
+
const path = resolve10(file);
|
|
12316
|
+
if (statSync4(path).size > 131072) throw new Error("Inference JSON must be at most 128 KiB.");
|
|
12317
|
+
const data3 = JSON.parse(readFileSync11(path, "utf8"));
|
|
12318
|
+
return z.record(z.string(), z.json()).refine((value) => Object.keys(value).length > 0).parse(data3);
|
|
12319
|
+
}
|
|
12320
|
+
async function uploadWeights(endpoint, file) {
|
|
12321
|
+
const url = new URL(endpoint.upload.url);
|
|
12322
|
+
if (url.protocol !== "https:" || url.username || url.password || !/\.s3\.[a-z0-9-]+\.amazonaws\.com$/.test(url.hostname)) {
|
|
12323
|
+
throw new Error("The server returned an invalid model upload URL.");
|
|
12324
|
+
}
|
|
12325
|
+
const handle = await open4(file, "r");
|
|
12326
|
+
const stream = handle.createReadStream();
|
|
12327
|
+
const completion = finished(stream);
|
|
12328
|
+
void completion.catch(() => {
|
|
12329
|
+
});
|
|
12330
|
+
try {
|
|
12331
|
+
const response = await fetch(url, {
|
|
12332
|
+
method: "PUT",
|
|
12333
|
+
headers: endpoint.upload.headers,
|
|
12334
|
+
body: stream,
|
|
12335
|
+
duplex: "half",
|
|
12336
|
+
redirect: "error",
|
|
12337
|
+
signal: AbortSignal.timeout(60 * 6e4)
|
|
12338
|
+
});
|
|
12339
|
+
if (!response.ok) throw new Error(`Model upload failed (${response.status}). Delete endpoint ${endpoint.id} and retry.`);
|
|
12340
|
+
} finally {
|
|
12341
|
+
stream.destroy();
|
|
12342
|
+
await completion.catch(() => {
|
|
12343
|
+
});
|
|
12344
|
+
}
|
|
12345
|
+
}
|
|
12346
|
+
function show(endpoint, opts) {
|
|
12347
|
+
const result2 = { ...endpoint, invocation_url: new URL(endpoint.invocation_path, getBaseUrl(opts)).toString() };
|
|
12348
|
+
if (isJsonMode()) return printJson(result2);
|
|
12349
|
+
printDetail([
|
|
12350
|
+
["Endpoint", result2.id],
|
|
12351
|
+
["Name", result2.name],
|
|
12352
|
+
["Status", result2.status],
|
|
12353
|
+
["Inference URL", result2.invocation_url],
|
|
12354
|
+
["Price per successful request", `${result2.price_cents} cents`],
|
|
12355
|
+
...result2.inference_key ? [["Inference key (save securely)", result2.inference_key]] : []
|
|
12356
|
+
]);
|
|
12357
|
+
}
|
|
12358
|
+
function registerEndpointCommands(parent) {
|
|
12359
|
+
const endpoints = parent.command("endpoints").description("Host small CPU decision models using prepaid TT credits");
|
|
12360
|
+
endpoints.command("create").description("Upload Laya weights and deploy a serverless endpoint").requiredOption("--model <directory>", "Local Laya checkpoint (e.g. a decision run's train/model)").requiredOption("--name <name>", "Endpoint display name").action(async (options) => {
|
|
12361
|
+
const opts = parent.optsWithGlobals();
|
|
12362
|
+
const { file, ...artifact } = await inspectCheckpoint(options.model);
|
|
12363
|
+
const { data: data3 } = await post("/endpoints", { name: options.name, format: "laya-safetensors-v1", ...artifact }, opts);
|
|
12364
|
+
if (!isJsonMode()) console.error(`Endpoint ${data3.id} created. Uploading ${(artifact.weights_bytes / 1e9).toFixed(2)} GB of weights...`);
|
|
12365
|
+
try {
|
|
12366
|
+
await uploadWeights(data3, file);
|
|
12367
|
+
const { data: deployed } = await post(`/endpoints/${data3.id}/deploy`, {}, opts);
|
|
12368
|
+
show({ ...deployed, inference_key: data3.inference_key }, opts);
|
|
12369
|
+
} catch (error) {
|
|
12370
|
+
throw new Error(`Endpoint ${data3.id}: ${error instanceof Error ? error.message : "upload/deployment failed"}. Use tt cloud endpoints get ${data3.id} or delete ${data3.id}. Rotate its key if the create response was lost.`, { cause: error });
|
|
12371
|
+
}
|
|
12372
|
+
});
|
|
12373
|
+
endpoints.command("list").action(async () => {
|
|
12374
|
+
const opts = parent.optsWithGlobals();
|
|
12375
|
+
const { data: data3 } = await get("/endpoints", void 0, opts);
|
|
12376
|
+
if (isJsonMode()) return printJson(data3);
|
|
12377
|
+
for (const row of data3) show(row, opts);
|
|
12378
|
+
});
|
|
12379
|
+
endpoints.command("get <id>").description("Check deployment or deletion status").action(async (id) => {
|
|
12380
|
+
z.uuid().parse(id);
|
|
12381
|
+
const opts = parent.optsWithGlobals();
|
|
12382
|
+
show((await get(`/endpoints/${id}`, void 0, opts)).data, opts);
|
|
12383
|
+
});
|
|
12384
|
+
endpoints.command("delete <id>").description("Stop serving and delete cloud weights and resources").action(async (id) => {
|
|
12385
|
+
z.uuid().parse(id);
|
|
12386
|
+
const opts = parent.optsWithGlobals();
|
|
12387
|
+
show((await del(`/endpoints/${id}`, opts)).data, opts);
|
|
12388
|
+
});
|
|
12389
|
+
endpoints.command("rotate-key <id>").description("Revoke the old inference key and return a new key").action(async (id) => {
|
|
12390
|
+
z.uuid().parse(id);
|
|
12391
|
+
const { data: data3 } = await post(`/endpoints/${id}/key`, {}, parent.optsWithGlobals());
|
|
12392
|
+
if (isJsonMode()) return printJson(data3);
|
|
12393
|
+
printDetail([["Inference key (save securely)", data3.inference_key]]);
|
|
12394
|
+
});
|
|
12395
|
+
endpoints.command("invoke <id>").requiredOption("--payload <file>", "Complete model request as a JSON object (up to 128 KiB)").option("--request-id <uuid>", "Reuse this ID to retry without a second charge").action(async (id, options) => {
|
|
12396
|
+
z.uuid().parse(id);
|
|
12397
|
+
const requestId = options.requestId ?? randomUUID10();
|
|
12398
|
+
z.uuid().parse(requestId);
|
|
12399
|
+
const payload = readInferencePayload(options.payload);
|
|
12400
|
+
if (!isJsonMode()) console.error(`Request ID: ${requestId} (reuse with --request-id when retrying)`);
|
|
12401
|
+
try {
|
|
12402
|
+
const { data: data3 } = await post(`/endpoints/${id}/invoke`, payload, parent.optsWithGlobals(), { "Idempotency-Key": requestId });
|
|
12403
|
+
printJson({ request_id: requestId, data: data3 });
|
|
12404
|
+
} catch (error) {
|
|
12405
|
+
throw new Error(`Request ${requestId}: ${error instanceof Error ? error.message : "inference failed"}. Retry with --request-id ${requestId}.`, { cause: error });
|
|
12406
|
+
}
|
|
12407
|
+
});
|
|
12408
|
+
}
|
|
12409
|
+
|
|
12275
12410
|
// src/commands/models.ts
|
|
12276
12411
|
import { spawn as spawn3, execFileSync } from "child_process";
|
|
12277
|
-
import { createHash as
|
|
12412
|
+
import { createHash as createHash9 } from "crypto";
|
|
12278
12413
|
import {
|
|
12279
12414
|
existsSync as existsSync10,
|
|
12280
12415
|
mkdirSync as mkdirSync5,
|
|
12281
|
-
statSync as
|
|
12416
|
+
statSync as statSync5,
|
|
12282
12417
|
createWriteStream,
|
|
12283
12418
|
unlinkSync,
|
|
12284
|
-
readFileSync as
|
|
12419
|
+
readFileSync as readFileSync13,
|
|
12285
12420
|
writeFileSync as writeFileSync6,
|
|
12286
12421
|
readdirSync,
|
|
12287
12422
|
rmSync
|
|
12288
12423
|
} from "fs";
|
|
12289
12424
|
import { homedir as homedir3 } from "os";
|
|
12290
|
-
import { dirname as dirname13, join as
|
|
12425
|
+
import { dirname as dirname13, join as join16, resolve as resolve12, basename as basename9, normalize, isAbsolute as isAbsolute6 } from "path";
|
|
12291
12426
|
import { Readable, Transform } from "stream";
|
|
12292
12427
|
import { pipeline } from "stream/promises";
|
|
12293
12428
|
|
|
12294
12429
|
// src/commands/init.ts
|
|
12295
|
-
import { existsSync as existsSync9, readFileSync as
|
|
12296
|
-
import { resolve as
|
|
12430
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
|
|
12431
|
+
import { resolve as resolve11 } from "path";
|
|
12297
12432
|
var DEFAULT_SPEC_FILE2 = "tunedtensor.json";
|
|
12298
12433
|
function loadSpec(filePath) {
|
|
12299
|
-
const resolved =
|
|
12434
|
+
const resolved = resolve11(filePath || DEFAULT_SPEC_FILE2);
|
|
12300
12435
|
if (!existsSync9(resolved)) {
|
|
12301
12436
|
printError(
|
|
12302
12437
|
`Spec file not found: ${filePath || DEFAULT_SPEC_FILE2}
|
|
@@ -12304,13 +12439,13 @@ Run \`tt init\` to create one.`
|
|
|
12304
12439
|
);
|
|
12305
12440
|
process.exit(1);
|
|
12306
12441
|
}
|
|
12307
|
-
const raw = JSON.parse(
|
|
12442
|
+
const raw = JSON.parse(readFileSync12(resolved, "utf-8"));
|
|
12308
12443
|
return raw;
|
|
12309
12444
|
}
|
|
12310
12445
|
|
|
12311
12446
|
// src/serve-manager.ts
|
|
12312
12447
|
import { spawn as spawn2 } from "child_process";
|
|
12313
|
-
import { randomUUID as
|
|
12448
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
12314
12449
|
import { appendFileSync, mkdirSync as mkdirSync4 } from "fs";
|
|
12315
12450
|
import { createServer } from "http";
|
|
12316
12451
|
import { createServer as createNetServer } from "net";
|
|
@@ -12327,10 +12462,10 @@ function parsePositiveInteger(value, fallback) {
|
|
|
12327
12462
|
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
12328
12463
|
}
|
|
12329
12464
|
function sleep2(ms) {
|
|
12330
|
-
return new Promise((
|
|
12465
|
+
return new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
12331
12466
|
}
|
|
12332
12467
|
function readRequestBody(req) {
|
|
12333
|
-
return new Promise((
|
|
12468
|
+
return new Promise((resolve14, reject) => {
|
|
12334
12469
|
if (Number(req.headers["content-length"]) > MAX_SERVE_REQUEST_BYTES) {
|
|
12335
12470
|
reject(new RequestTooLargeError());
|
|
12336
12471
|
return;
|
|
@@ -12360,7 +12495,7 @@ function readRequestBody(req) {
|
|
|
12360
12495
|
};
|
|
12361
12496
|
const onEnd = () => {
|
|
12362
12497
|
cleanup();
|
|
12363
|
-
|
|
12498
|
+
resolve14(Buffer.concat(chunks, bytes));
|
|
12364
12499
|
};
|
|
12365
12500
|
req.on("data", onData);
|
|
12366
12501
|
req.on("end", onEnd);
|
|
@@ -12437,7 +12572,7 @@ function errorSummary(response, fallback) {
|
|
|
12437
12572
|
return typeof message === "string" ? message : fallback;
|
|
12438
12573
|
}
|
|
12439
12574
|
async function allocatePort(host) {
|
|
12440
|
-
return new Promise((
|
|
12575
|
+
return new Promise((resolve14, reject) => {
|
|
12441
12576
|
const server = createNetServer();
|
|
12442
12577
|
server.on("error", reject);
|
|
12443
12578
|
server.listen(0, host, () => {
|
|
@@ -12447,7 +12582,7 @@ async function allocatePort(host) {
|
|
|
12447
12582
|
return;
|
|
12448
12583
|
}
|
|
12449
12584
|
const port = address.port;
|
|
12450
|
-
server.close(() =>
|
|
12585
|
+
server.close(() => resolve14(port));
|
|
12451
12586
|
});
|
|
12452
12587
|
});
|
|
12453
12588
|
}
|
|
@@ -12488,11 +12623,11 @@ var ManagedModelServer = class {
|
|
|
12488
12623
|
sendJson(res, 500, { error: { message: err instanceof Error ? err.message : String(err) } });
|
|
12489
12624
|
});
|
|
12490
12625
|
});
|
|
12491
|
-
await new Promise((
|
|
12626
|
+
await new Promise((resolve14, reject) => {
|
|
12492
12627
|
this.server?.once("error", reject);
|
|
12493
12628
|
this.server?.listen(this.options.publicPort, this.options.publicHost, () => {
|
|
12494
12629
|
this.server?.off("error", reject);
|
|
12495
|
-
|
|
12630
|
+
resolve14();
|
|
12496
12631
|
});
|
|
12497
12632
|
});
|
|
12498
12633
|
}
|
|
@@ -12502,15 +12637,15 @@ var ManagedModelServer = class {
|
|
|
12502
12637
|
if (!this.server) return;
|
|
12503
12638
|
const server = this.server;
|
|
12504
12639
|
this.server = null;
|
|
12505
|
-
await new Promise((
|
|
12506
|
-
server.close((err) => err ? reject(err) :
|
|
12640
|
+
await new Promise((resolve14, reject) => {
|
|
12641
|
+
server.close((err) => err ? reject(err) : resolve14());
|
|
12507
12642
|
});
|
|
12508
12643
|
}
|
|
12509
12644
|
async run() {
|
|
12510
12645
|
await this.start();
|
|
12511
|
-
await new Promise((
|
|
12646
|
+
await new Promise((resolve14, reject) => {
|
|
12512
12647
|
this.server?.once("error", reject);
|
|
12513
|
-
this.server?.once("close",
|
|
12648
|
+
this.server?.once("close", resolve14);
|
|
12514
12649
|
});
|
|
12515
12650
|
}
|
|
12516
12651
|
async handle(req, res) {
|
|
@@ -12591,7 +12726,7 @@ var ManagedModelServer = class {
|
|
|
12591
12726
|
});
|
|
12592
12727
|
}
|
|
12593
12728
|
async processGeneration(route, body, res, receivedAt) {
|
|
12594
|
-
const requestId = `ttreq-${
|
|
12729
|
+
const requestId = `ttreq-${randomUUID11()}`;
|
|
12595
12730
|
const startedAt = Date.now();
|
|
12596
12731
|
const queuedMs = startedAt - receivedAt;
|
|
12597
12732
|
this.activeRequests += 1;
|
|
@@ -12697,7 +12832,7 @@ var ManagedModelServer = class {
|
|
|
12697
12832
|
try {
|
|
12698
12833
|
child.kill("SIGTERM");
|
|
12699
12834
|
await Promise.race([
|
|
12700
|
-
new Promise((
|
|
12835
|
+
new Promise((resolve14) => child.once("exit", () => resolve14())),
|
|
12701
12836
|
sleep2(5e3).then(() => {
|
|
12702
12837
|
if (child.exitCode == null && child.signalCode == null) child.kill("SIGKILL");
|
|
12703
12838
|
})
|
|
@@ -13328,8 +13463,8 @@ function validateDownloadFilename(filename) {
|
|
|
13328
13463
|
function resolveOutputPath(output, filename) {
|
|
13329
13464
|
validateDownloadFilename(filename);
|
|
13330
13465
|
if (!output) return filename;
|
|
13331
|
-
if (existsSync10(output) &&
|
|
13332
|
-
return
|
|
13466
|
+
if (existsSync10(output) && statSync5(output).isDirectory()) {
|
|
13467
|
+
return join16(output, filename);
|
|
13333
13468
|
}
|
|
13334
13469
|
return output;
|
|
13335
13470
|
}
|
|
@@ -13436,15 +13571,15 @@ async function downloadUrlToFile(url, outputPath) {
|
|
|
13436
13571
|
return contentLength;
|
|
13437
13572
|
}
|
|
13438
13573
|
function defaultCacheDir() {
|
|
13439
|
-
const root = process.env.XDG_CACHE_HOME ||
|
|
13440
|
-
return
|
|
13574
|
+
const root = process.env.XDG_CACHE_HOME || join16(homedir3(), ".cache");
|
|
13575
|
+
return join16(root, "tuned-tensor", "models");
|
|
13441
13576
|
}
|
|
13442
13577
|
function runtimeDir(cacheDir) {
|
|
13443
|
-
return
|
|
13578
|
+
return join16(cacheDir, "_runtime");
|
|
13444
13579
|
}
|
|
13445
13580
|
function runtimePythonPath(cacheDir) {
|
|
13446
13581
|
const dir = runtimeDir(cacheDir);
|
|
13447
|
-
return process.platform === "win32" ?
|
|
13582
|
+
return process.platform === "win32" ? join16(dir, "Scripts", "python.exe") : join16(dir, "bin", "python");
|
|
13448
13583
|
}
|
|
13449
13584
|
function resolveServePython(cacheDir, explicitPython) {
|
|
13450
13585
|
if (explicitPython) return explicitPython;
|
|
@@ -13517,7 +13652,7 @@ print(json.dumps({"missing": missing}))
|
|
|
13517
13652
|
}
|
|
13518
13653
|
}
|
|
13519
13654
|
function setupRuntimeCommands(python, venvDir, deps) {
|
|
13520
|
-
const venvPython = process.platform === "win32" ?
|
|
13655
|
+
const venvPython = process.platform === "win32" ? join16(venvDir, "Scripts", "python.exe") : join16(venvDir, "bin", "python");
|
|
13521
13656
|
return [
|
|
13522
13657
|
[python, "-m", "venv", venvDir],
|
|
13523
13658
|
[venvPython, "-m", "pip", "install", "--upgrade", "pip"],
|
|
@@ -13528,7 +13663,7 @@ function safeSegment(value) {
|
|
|
13528
13663
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "model";
|
|
13529
13664
|
}
|
|
13530
13665
|
function directoryHasFiles(path) {
|
|
13531
|
-
return existsSync10(path) &&
|
|
13666
|
+
return existsSync10(path) && statSync5(path).isDirectory() && readdirSync(path).length > 0;
|
|
13532
13667
|
}
|
|
13533
13668
|
function validateArchiveEntryPath(entry) {
|
|
13534
13669
|
const normalized = normalize(entry).replace(/^[\\/]+/, "");
|
|
@@ -13555,9 +13690,9 @@ function extractArchive(archivePath, targetDir, force) {
|
|
|
13555
13690
|
return targetDir;
|
|
13556
13691
|
}
|
|
13557
13692
|
function localArchiveCacheDir(archivePath, cacheDir) {
|
|
13558
|
-
const resolved =
|
|
13559
|
-
const digest =
|
|
13560
|
-
return
|
|
13693
|
+
const resolved = resolve12(archivePath);
|
|
13694
|
+
const digest = createHash9("sha256").update(resolved).digest("hex").slice(0, 12);
|
|
13695
|
+
return join16(cacheDir, `local-${safeSegment(basename9(archivePath))}-${digest}`);
|
|
13561
13696
|
}
|
|
13562
13697
|
function buildSystemPrompt(spec) {
|
|
13563
13698
|
const parts = [];
|
|
@@ -13573,40 +13708,40 @@ ${spec.constraints.map((c) => `- ${c}`).join("\n")}`);
|
|
|
13573
13708
|
return parts.join("\n\n");
|
|
13574
13709
|
}
|
|
13575
13710
|
function findSpecPath(explicitPath, modelPath) {
|
|
13576
|
-
const candidates = explicitPath ? [explicitPath] : [
|
|
13711
|
+
const candidates = explicitPath ? [explicitPath] : [join16(process.cwd(), DEFAULT_SPEC_FILE2), join16(modelPath, DEFAULT_SPEC_FILE2)];
|
|
13577
13712
|
for (const candidate of candidates) {
|
|
13578
|
-
const resolved =
|
|
13579
|
-
if (existsSync10(resolved) &&
|
|
13713
|
+
const resolved = resolve12(candidate);
|
|
13714
|
+
if (existsSync10(resolved) && statSync5(resolved).isFile()) return resolved;
|
|
13580
13715
|
}
|
|
13581
13716
|
return null;
|
|
13582
13717
|
}
|
|
13583
13718
|
function loadSystemPromptFromSpec(specPath) {
|
|
13584
|
-
const spec = JSON.parse(
|
|
13719
|
+
const spec = JSON.parse(readFileSync13(specPath, "utf8"));
|
|
13585
13720
|
return buildSystemPrompt(spec);
|
|
13586
13721
|
}
|
|
13587
13722
|
function loadJsonSchemaForServe(schemaPath) {
|
|
13588
|
-
const resolved =
|
|
13589
|
-
if (!existsSync10(resolved) || !
|
|
13723
|
+
const resolved = resolve12(schemaPath);
|
|
13724
|
+
if (!existsSync10(resolved) || !statSync5(resolved).isFile()) {
|
|
13590
13725
|
throw new Error(`JSON schema file not found: ${schemaPath}`);
|
|
13591
13726
|
}
|
|
13592
13727
|
try {
|
|
13593
|
-
const schema = JSON.parse(
|
|
13728
|
+
const schema = JSON.parse(readFileSync13(resolved, "utf8"));
|
|
13594
13729
|
return JSON.stringify(schema);
|
|
13595
13730
|
} catch (err) {
|
|
13596
13731
|
throw new Error(`JSON schema file is not valid JSON: ${schemaPath}`);
|
|
13597
13732
|
}
|
|
13598
13733
|
}
|
|
13599
13734
|
function writeReferenceServerScript(cacheDir) {
|
|
13600
|
-
const scriptDir =
|
|
13735
|
+
const scriptDir = join16(cacheDir, "_server");
|
|
13601
13736
|
mkdirSync5(scriptDir, { recursive: true });
|
|
13602
|
-
const scriptPath =
|
|
13737
|
+
const scriptPath = join16(scriptDir, "openai_reference_server.py");
|
|
13603
13738
|
writeFileSync6(scriptPath, REFERENCE_SERVER_SCRIPT, "utf8");
|
|
13604
13739
|
return scriptPath;
|
|
13605
13740
|
}
|
|
13606
13741
|
async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
13607
13742
|
if (existsSync10(target)) {
|
|
13608
|
-
const resolved =
|
|
13609
|
-
const stats =
|
|
13743
|
+
const resolved = resolve12(target);
|
|
13744
|
+
const stats = statSync5(resolved);
|
|
13610
13745
|
if (stats.isDirectory()) {
|
|
13611
13746
|
return {
|
|
13612
13747
|
modelPath: resolved,
|
|
@@ -13615,7 +13750,7 @@ async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
|
13615
13750
|
};
|
|
13616
13751
|
}
|
|
13617
13752
|
if (stats.isFile() && (resolved.endsWith(".tar.gz") || resolved.endsWith(".tgz"))) {
|
|
13618
|
-
const extractDir2 =
|
|
13753
|
+
const extractDir2 = join16(localArchiveCacheDir(resolved, cacheDir), "model");
|
|
13619
13754
|
return {
|
|
13620
13755
|
modelPath: extractArchive(resolved, extractDir2, forceDownload),
|
|
13621
13756
|
modelName: basename9(resolved).replace(/\.t(ar\.)?gz$/, ""),
|
|
@@ -13629,9 +13764,9 @@ async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
|
13629
13764
|
const { data: data3 } = await get(`/models/${fullId}/download`, void 0, opts);
|
|
13630
13765
|
validateDownloadFilename(fullId);
|
|
13631
13766
|
validateDownloadFilename(data3.filename);
|
|
13632
|
-
const modelCacheDir =
|
|
13633
|
-
const archivePath =
|
|
13634
|
-
const extractDir =
|
|
13767
|
+
const modelCacheDir = join16(cacheDir, fullId);
|
|
13768
|
+
const archivePath = join16(modelCacheDir, data3.filename);
|
|
13769
|
+
const extractDir = join16(modelCacheDir, "model");
|
|
13635
13770
|
if (!existsSync10(archivePath) || forceDownload) {
|
|
13636
13771
|
await downloadUrlToFile(data3.url, archivePath);
|
|
13637
13772
|
}
|
|
@@ -13736,8 +13871,8 @@ function ollamaSlug(name) {
|
|
|
13736
13871
|
}
|
|
13737
13872
|
function firstExisting(candidates) {
|
|
13738
13873
|
for (const candidate of candidates) {
|
|
13739
|
-
if (candidate && existsSync10(candidate) &&
|
|
13740
|
-
return
|
|
13874
|
+
if (candidate && existsSync10(candidate) && statSync5(candidate).isFile()) {
|
|
13875
|
+
return resolve12(candidate);
|
|
13741
13876
|
}
|
|
13742
13877
|
}
|
|
13743
13878
|
return null;
|
|
@@ -13747,14 +13882,14 @@ function llamaCppDir(explicit) {
|
|
|
13747
13882
|
}
|
|
13748
13883
|
function resolveConvertScript(opts, required) {
|
|
13749
13884
|
if (opts.convertScript) {
|
|
13750
|
-
const resolved =
|
|
13885
|
+
const resolved = resolve12(opts.convertScript);
|
|
13751
13886
|
if (required && !existsSync10(resolved)) {
|
|
13752
13887
|
throw new Error(`Conversion script not found: ${opts.convertScript}`);
|
|
13753
13888
|
}
|
|
13754
13889
|
return resolved;
|
|
13755
13890
|
}
|
|
13756
13891
|
const dir = llamaCppDir(opts.llamaCpp);
|
|
13757
|
-
const candidates = dir ? [
|
|
13892
|
+
const candidates = dir ? [join16(dir, "convert_hf_to_gguf.py"), join16(dir, "convert-hf-to-gguf.py")] : [];
|
|
13758
13893
|
const found = firstExisting(candidates);
|
|
13759
13894
|
if (found) return found;
|
|
13760
13895
|
if (required) {
|
|
@@ -13762,11 +13897,11 @@ function resolveConvertScript(opts, required) {
|
|
|
13762
13897
|
"Could not find convert_hf_to_gguf.py. Pass --llama-cpp <dir> (a llama.cpp checkout) or --convert-script <path>. Get it from https://github.com/ggml-org/llama.cpp."
|
|
13763
13898
|
);
|
|
13764
13899
|
}
|
|
13765
|
-
return dir ?
|
|
13900
|
+
return dir ? join16(dir, "convert_hf_to_gguf.py") : "convert_hf_to_gguf.py";
|
|
13766
13901
|
}
|
|
13767
13902
|
function resolveQuantizeBin(opts, required) {
|
|
13768
13903
|
if (opts.quantizeBin) {
|
|
13769
|
-
const resolved =
|
|
13904
|
+
const resolved = resolve12(opts.quantizeBin);
|
|
13770
13905
|
if (required && !existsSync10(resolved)) {
|
|
13771
13906
|
throw new Error(`llama-quantize binary not found: ${opts.quantizeBin}`);
|
|
13772
13907
|
}
|
|
@@ -13775,10 +13910,10 @@ function resolveQuantizeBin(opts, required) {
|
|
|
13775
13910
|
const dir = llamaCppDir(opts.llamaCpp);
|
|
13776
13911
|
if (dir) {
|
|
13777
13912
|
const candidates = [
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13913
|
+
join16(dir, "build", "bin", "llama-quantize"),
|
|
13914
|
+
join16(dir, "build", "bin", "quantize"),
|
|
13915
|
+
join16(dir, "llama-quantize"),
|
|
13916
|
+
join16(dir, "quantize")
|
|
13782
13917
|
];
|
|
13783
13918
|
const found = firstExisting(candidates);
|
|
13784
13919
|
if (found) return found;
|
|
@@ -13926,7 +14061,7 @@ function registerModelsCommands(parent) {
|
|
|
13926
14061
|
}
|
|
13927
14062
|
const quantPlan = planQuant(String(cmdOpts.quant));
|
|
13928
14063
|
const printOnly = Boolean(cmdOpts.printCommand);
|
|
13929
|
-
const cacheDir =
|
|
14064
|
+
const cacheDir = resolve12(cmdOpts.cacheDir || defaultCacheDir());
|
|
13930
14065
|
mkdirSync5(cacheDir, { recursive: true });
|
|
13931
14066
|
const serveTarget = await resolveServeTarget(
|
|
13932
14067
|
target,
|
|
@@ -13935,9 +14070,9 @@ function registerModelsCommands(parent) {
|
|
|
13935
14070
|
Boolean(cmdOpts.forceDownload)
|
|
13936
14071
|
);
|
|
13937
14072
|
const slug = ollamaSlug(serveTarget.modelName);
|
|
13938
|
-
const outputDir =
|
|
13939
|
-
const finalPath =
|
|
13940
|
-
const intermediatePath = quantPlan.requiresQuantize ?
|
|
14073
|
+
const outputDir = resolve12(cmdOpts.output || join16(process.cwd(), `${slug}-gguf`));
|
|
14074
|
+
const finalPath = join16(outputDir, `${slug}.${quantPlan.quant}.gguf`);
|
|
14075
|
+
const intermediatePath = quantPlan.requiresQuantize ? join16(outputDir, `${slug}.f16.gguf`) : void 0;
|
|
13941
14076
|
const convertScript = resolveConvertScript(cmdOpts, !printOnly);
|
|
13942
14077
|
const convertOutfile = intermediatePath ?? finalPath;
|
|
13943
14078
|
const steps = [
|
|
@@ -13975,7 +14110,7 @@ function registerModelsCommands(parent) {
|
|
|
13975
14110
|
}
|
|
13976
14111
|
if (specPath) systemPrompt2 = loadSystemPromptFromSpec(specPath);
|
|
13977
14112
|
}
|
|
13978
|
-
modelfilePath =
|
|
14113
|
+
modelfilePath = join16(outputDir, "Modelfile");
|
|
13979
14114
|
modelfileContent = buildModelfile(basename9(finalPath), systemPrompt2);
|
|
13980
14115
|
const createModel = cmdOpts.ollamaCreate !== false;
|
|
13981
14116
|
if (createModel) {
|
|
@@ -14062,7 +14197,7 @@ function registerModelsCommands(parent) {
|
|
|
14062
14197
|
}
|
|
14063
14198
|
});
|
|
14064
14199
|
models.command("setup-runtime").description("Install an isolated Python runtime for local model serving").option("--python <path>", "Python 3.10-3.12 executable to create the runtime").option("--cache-dir <path>", "Cache directory for the managed runtime").option("-f, --force", "Recreate the runtime if it already exists").option("--print-command", "Print the setup commands without running them").action(async (cmdOpts) => {
|
|
14065
|
-
const cacheDir =
|
|
14200
|
+
const cacheDir = resolve12(cmdOpts.cacheDir || defaultCacheDir());
|
|
14066
14201
|
const venvDir = runtimeDir(cacheDir);
|
|
14067
14202
|
const venvPython = runtimePythonPath(cacheDir);
|
|
14068
14203
|
const python = pickRuntimePython(cmdOpts.python);
|
|
@@ -14108,7 +14243,7 @@ function registerModelsCommands(parent) {
|
|
|
14108
14243
|
});
|
|
14109
14244
|
models.command("serve").description("Serve a downloaded model with an OpenAI-compatible local API").argument("<target>", "Model ID/prefix, model directory, or .tar.gz artifact").option("--spec <path>", "Behavior spec JSON to apply as the default system prompt").option("--no-spec-prompt", "Do not auto-apply a behavior spec system prompt").option("--host <host>", "Host to bind", "127.0.0.1").option("--port <port>", "Port to bind", "8000").option("--python <path>", "Python executable").option("--cache-dir <path>", "Cache directory for downloaded/extracted models").option("--device <device>", "Inference device: auto, cpu, cuda, or mps", "auto").option("--force-download", "Re-download and re-extract model artifacts").option("--max-tokens <n>", "Default max completion tokens", "512").option("--temperature <n>", "Default sampling temperature", "0.7").option("--json-schema <path>", "JSON Schema file to enforce by default for chat completions").option("--json-repair-attempts <n>", "Number of JSON/schema repair retries", "1").option("--trust-remote-code", "Pass trust_remote_code=True to transformers").option("--managed", "Run a local lifecycle manager in front of the model server").option("--idle-timeout <seconds>", "Managed mode idle timeout before stopping the model", "300").option("--restart-after-requests <n>", "Managed mode restart threshold; 0 disables request-count restarts", "100").option("--gate-field <field>", "Response JSON field to log as the managed serving gate result", "should_process").option("--log-file <path>", "Write managed serving JSONL request logs to a file").option("--print-command", "Print the underlying Python command without starting it").action(async (target, cmdOpts) => {
|
|
14110
14245
|
const opts = parent.optsWithGlobals();
|
|
14111
|
-
const cacheDir =
|
|
14246
|
+
const cacheDir = resolve12(cmdOpts.cacheDir || defaultCacheDir());
|
|
14112
14247
|
mkdirSync5(cacheDir, { recursive: true });
|
|
14113
14248
|
const python = resolveServePython(cacheDir, cmdOpts.python);
|
|
14114
14249
|
if (!cmdOpts.printCommand) ensureServingRuntime(python, cacheDir);
|
|
@@ -14157,7 +14292,7 @@ function registerModelsCommands(parent) {
|
|
|
14157
14292
|
idle_timeout_seconds: idleTimeoutSeconds,
|
|
14158
14293
|
restart_after_requests: restartAfterRequests,
|
|
14159
14294
|
gate_field: String(cmdOpts.gateField),
|
|
14160
|
-
log_file: cmdOpts.logFile ?
|
|
14295
|
+
log_file: cmdOpts.logFile ? resolve12(cmdOpts.logFile) : void 0
|
|
14161
14296
|
} : void 0;
|
|
14162
14297
|
if (cmdOpts.printCommand) return printServeCommand(python, args2, env, managedConfig);
|
|
14163
14298
|
if (!isJsonMode()) {
|
|
@@ -14194,7 +14329,7 @@ function registerModelsCommands(parent) {
|
|
|
14194
14329
|
idleTimeoutSeconds,
|
|
14195
14330
|
restartAfterRequests,
|
|
14196
14331
|
gateField: String(cmdOpts.gateField),
|
|
14197
|
-
logFile: cmdOpts.logFile ?
|
|
14332
|
+
logFile: cmdOpts.logFile ? resolve12(cmdOpts.logFile) : void 0
|
|
14198
14333
|
});
|
|
14199
14334
|
return;
|
|
14200
14335
|
}
|
|
@@ -14220,15 +14355,15 @@ function registerModelsCommands(parent) {
|
|
|
14220
14355
|
}
|
|
14221
14356
|
|
|
14222
14357
|
// src/commands/push.ts
|
|
14223
|
-
import { readFileSync as
|
|
14224
|
-
import { resolve as
|
|
14358
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
14359
|
+
import { resolve as resolve13 } from "path";
|
|
14225
14360
|
function persistRemoteId(filePath, id) {
|
|
14226
|
-
const raw = JSON.parse(
|
|
14361
|
+
const raw = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
14227
14362
|
raw.id = id;
|
|
14228
14363
|
writeFileSync7(filePath, JSON.stringify(raw, null, 2) + "\n");
|
|
14229
14364
|
}
|
|
14230
14365
|
async function pushLocalSpec(file, opts) {
|
|
14231
|
-
const filePath =
|
|
14366
|
+
const filePath = resolve13(file);
|
|
14232
14367
|
const spec = loadSpec(file);
|
|
14233
14368
|
const evalCaseErrors = validateEvalCases(spec);
|
|
14234
14369
|
if (evalCaseErrors.length > 0) {
|
|
@@ -14287,6 +14422,7 @@ function registerCloudCommands(parent) {
|
|
|
14287
14422
|
registerLabelCommands(cloud);
|
|
14288
14423
|
registerRunsCommands(cloud);
|
|
14289
14424
|
registerModelsCommands(cloud);
|
|
14425
|
+
registerEndpointCommands(cloud);
|
|
14290
14426
|
}
|
|
14291
14427
|
function weeklyRows(data3) {
|
|
14292
14428
|
if (typeof data3.weekly_remaining_percent !== "number" || !Number.isFinite(data3.weekly_remaining_percent) || typeof data3.weekly_cost_limit_usd !== "number" || !Number.isFinite(data3.weekly_cost_limit_usd) || data3.weekly_cost_limit_usd <= 0) return [];
|
|
@@ -14326,14 +14462,14 @@ Use \`tt balance\` for cloud training credits.`);
|
|
|
14326
14462
|
|
|
14327
14463
|
// src/commands/upgrade.ts
|
|
14328
14464
|
import { spawn as spawn5 } from "child_process";
|
|
14329
|
-
import { accessSync, constants as constants2, existsSync as existsSync11, readFileSync as
|
|
14330
|
-
import { dirname as dirname15, join as
|
|
14465
|
+
import { accessSync, constants as constants2, existsSync as existsSync11, readFileSync as readFileSync16, realpathSync } from "fs";
|
|
14466
|
+
import { dirname as dirname15, join as join18 } from "path";
|
|
14331
14467
|
import chalk14 from "chalk";
|
|
14332
14468
|
|
|
14333
14469
|
// src/update-check.ts
|
|
14334
14470
|
import { spawn as spawn4 } from "child_process";
|
|
14335
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
14336
|
-
import { dirname as dirname14, join as
|
|
14471
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
|
|
14472
|
+
import { dirname as dirname14, join as join17 } from "path";
|
|
14337
14473
|
import chalk13 from "chalk";
|
|
14338
14474
|
var CLI_PACKAGE_NAME = "@tuned-tensor/cli";
|
|
14339
14475
|
var PACKAGE_LATEST_URL = "https://registry.npmjs.org/@tuned-tensor%2fcli/latest";
|
|
@@ -14382,14 +14518,14 @@ function compareVersions(left, right) {
|
|
|
14382
14518
|
return comparePrerelease(left.prerelease, right.prerelease);
|
|
14383
14519
|
}
|
|
14384
14520
|
function getCliUpdateCacheFile(env = process.env) {
|
|
14385
|
-
return
|
|
14521
|
+
return join17(getTunedTensorHome(env), "update-check.json");
|
|
14386
14522
|
}
|
|
14387
14523
|
function cliUpdateChecksDisabled(env = process.env) {
|
|
14388
14524
|
return [env.TT_NO_UPDATE_CHECK, env.NO_UPDATE_NOTIFIER, env.CI].some((value) => value !== void 0 && value !== "" && value !== "0" && value !== "false");
|
|
14389
14525
|
}
|
|
14390
14526
|
function readUpdateCache(file) {
|
|
14391
14527
|
try {
|
|
14392
|
-
const payload = JSON.parse(
|
|
14528
|
+
const payload = JSON.parse(readFileSync15(file, "utf8"));
|
|
14393
14529
|
if (typeof payload.checkedAt !== "number" || typeof payload.latestVersion !== "string" || !parseVersion(payload.latestVersion)) return null;
|
|
14394
14530
|
return { checkedAt: payload.checkedAt, latestVersion: payload.latestVersion };
|
|
14395
14531
|
} catch {
|
|
@@ -14441,10 +14577,10 @@ async function fetchLatestCliVersion(options = {}) {
|
|
|
14441
14577
|
return null;
|
|
14442
14578
|
}
|
|
14443
14579
|
})();
|
|
14444
|
-
const deadline = new Promise((
|
|
14580
|
+
const deadline = new Promise((resolve14) => {
|
|
14445
14581
|
timeout = setTimeout(() => {
|
|
14446
14582
|
controller.abort();
|
|
14447
|
-
|
|
14583
|
+
resolve14(null);
|
|
14448
14584
|
}, timeoutMs);
|
|
14449
14585
|
});
|
|
14450
14586
|
try {
|
|
@@ -14529,7 +14665,7 @@ function resolveGlobalInstall(entrypoint, platform = process.platform) {
|
|
|
14529
14665
|
return { prefix: match[1], packageDir: dirname15(dirname15(script)) };
|
|
14530
14666
|
}
|
|
14531
14667
|
function prefixIsWritable(prefix, platform) {
|
|
14532
|
-
const modules = platform === "win32" ?
|
|
14668
|
+
const modules = platform === "win32" ? join18(prefix, "node_modules") : join18(prefix, "lib", "node_modules");
|
|
14533
14669
|
try {
|
|
14534
14670
|
accessSync(existsSync11(modules) ? modules : prefix, constants2.W_OK);
|
|
14535
14671
|
return true;
|
|
@@ -14539,7 +14675,7 @@ function prefixIsWritable(prefix, platform) {
|
|
|
14539
14675
|
}
|
|
14540
14676
|
function installedVersion(packageDir) {
|
|
14541
14677
|
try {
|
|
14542
|
-
const manifest = JSON.parse(
|
|
14678
|
+
const manifest = JSON.parse(readFileSync16(join18(packageDir, "package.json"), "utf8"));
|
|
14543
14679
|
return typeof manifest.version === "string" ? manifest.version : void 0;
|
|
14544
14680
|
} catch {
|
|
14545
14681
|
return void 0;
|
|
@@ -14549,7 +14685,7 @@ function quoteForCmd(arg) {
|
|
|
14549
14685
|
return /[\s"&|<>^]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg;
|
|
14550
14686
|
}
|
|
14551
14687
|
function defaultNpmRunner(platform) {
|
|
14552
|
-
return async (args2) => await new Promise((
|
|
14688
|
+
return async (args2) => await new Promise((resolve14, reject) => {
|
|
14553
14689
|
const windows = platform === "win32";
|
|
14554
14690
|
const child = spawn5(
|
|
14555
14691
|
windows ? "npm.cmd" : "npm",
|
|
@@ -14561,7 +14697,7 @@ function defaultNpmRunner(platform) {
|
|
|
14561
14697
|
}
|
|
14562
14698
|
);
|
|
14563
14699
|
child.once("error", reject);
|
|
14564
|
-
child.once("close", (code2) =>
|
|
14700
|
+
child.once("close", (code2) => resolve14(code2 ?? 1));
|
|
14565
14701
|
});
|
|
14566
14702
|
}
|
|
14567
14703
|
function formatCommand(args2) {
|
|
@@ -14802,7 +14938,7 @@ async function runSelfCommand(args2, options = {}) {
|
|
|
14802
14938
|
if (!entrypoint) {
|
|
14803
14939
|
throw new Error("Cannot locate the tt CLI entrypoint.");
|
|
14804
14940
|
}
|
|
14805
|
-
return await new Promise((
|
|
14941
|
+
return await new Promise((resolve14, reject) => {
|
|
14806
14942
|
const child = spawn6(process.execPath, [entrypoint, ...options.captureJson ? ["--json"] : [], ...args2], {
|
|
14807
14943
|
cwd: options.cwd,
|
|
14808
14944
|
env: options.env ?? process.env,
|
|
@@ -14849,7 +14985,7 @@ async function runSelfCommand(args2, options = {}) {
|
|
|
14849
14985
|
child.once("close", (exitCode, signal) => {
|
|
14850
14986
|
cleanup();
|
|
14851
14987
|
const signalNumber = signal ? osConstants2.signals[signal] : void 0;
|
|
14852
|
-
|
|
14988
|
+
resolve14({
|
|
14853
14989
|
exitCode: exitCode ?? (typeof signalNumber === "number" ? 128 + signalNumber : 1),
|
|
14854
14990
|
signal,
|
|
14855
14991
|
...options.captureJson ? { stdout: stdout3 } : {}
|
|
@@ -15084,7 +15220,7 @@ ${formatCliUpdateNotice(update)}
|
|
|
15084
15220
|
}
|
|
15085
15221
|
|
|
15086
15222
|
// src/index.ts
|
|
15087
|
-
runCli("0.
|
|
15223
|
+
runCli("0.27.0").catch((err) => {
|
|
15088
15224
|
reportError(err);
|
|
15089
15225
|
process.exit(1);
|
|
15090
15226
|
});
|