@tuned-tensor/cli 0.13.0-beta.0 → 0.13.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 CHANGED
@@ -8,19 +8,57 @@
8
8
 
9
9
  ## Cloud sunset
10
10
 
11
- This release unregisters the hosted API commands (`tt auth`, `tt push`,
12
- `tt balance`, `tt topup`, `tt cloud`, and the rest of the managed tree). The
13
- modules remain in the repository so they can be restored later. `tt local …`
14
- is kept as a hidden alias; new scripts should call `tt run`, `tt doctor`,
15
- `tt runs list`, and so on directly.
11
+ This release unregisters the hosted API commands (`tt auth`, `tt publish`,
12
+ `tt push`, `tt balance`, `tt topup`, `tt cloud`, and the rest of the managed
13
+ tree). The modules remain in the repository so they can be restored later.
14
+ `tt local …` is kept as a hidden alias; new scripts should call `tt run`,
15
+ `tt doctor`, `tt runs list`, and so on directly.
16
+
17
+ ## Migrating from 0.11
18
+
19
+ `0.13` is the local-only CLI. If you are coming from `0.11.0`:
20
+
21
+ - Call `tt run`, `tt doctor`, and `tt serve` at the root. `tt local …` still
22
+ works as a hidden alias.
23
+ - Hosted account commands (`tt auth`, `tt publish`, `tt push`, and the rest)
24
+ are unregistered.
25
+ - `Qwen/Qwen3.5-2B` is pinned to Hugging Face snapshot
26
+ `15852e8c16360a2fea060d615a32b45270f8a8fc`. Prefetch, train, eval, and serve
27
+ reject any other revision.
28
+ - `tt serve active` fails unless an adapter is activated. Activation requires
29
+ a `generalRegression` suite in `local-runner.json`.
30
+ - `tt info` reports `status: local`.
16
31
 
17
32
  ## Install
18
33
 
34
+ On Linux or macOS:
35
+
19
36
  ```bash
20
- npm install -g @tuned-tensor/cli
37
+ curl -fsSL https://tunedtensor.com/install.sh | sh
21
38
  tt --version
22
39
  ```
23
40
 
41
+ The installer bootstraps Node.js 22.19+ if needed, installs
42
+ `@tuned-tensor/cli` with npm `--ignore-scripts`, and falls back to
43
+ `~/.local` when the global npm prefix is not writable. Inspect it first
44
+ with `curl -fsSL https://tunedtensor.com/install.sh | less`. Pin a
45
+ dist-tag or version on `sh`, not `curl`:
46
+
47
+ ```bash
48
+ curl -fsSL https://tunedtensor.com/install.sh | TT_VERSION=beta sh
49
+ curl -fsSL https://tunedtensor.com/install.sh | TT_VERSION=0.13.0 sh
50
+ ```
51
+
52
+ Or install the package directly:
53
+
54
+ ```bash
55
+ npm install -g --ignore-scripts @tuned-tensor/cli
56
+ tt --version
57
+ ```
58
+
59
+ Uninstall with `npm uninstall -g @tuned-tensor/cli` (add
60
+ `--prefix ~/.local` if the curl installer used that prefix).
61
+
24
62
  Node.js 22.19.0 or newer is required. Local training additionally needs
25
63
  [`uv`](https://docs.astral.sh/uv/) and a supported NVIDIA CUDA host; the locked
26
64
  Python runner ships with the npm package and is prepared on first use.
@@ -67,7 +105,7 @@ If a newer stable release is available it recommends
67
105
  checks are ignored.
68
106
 
69
107
  ```text
70
- tt v0.13.0-beta.0
108
+ tt v0.13.0
71
109
  agent anthropic/claude-sonnet-4-5 · workflow model base
72
110
  ctrl+c stop/clear · ctrl+d exit · /help commands · tab complete
73
111
 
@@ -173,7 +211,8 @@ tt models verify local-<run-id>
173
211
  tt models serve local-<run-id> --config local-runner.json
174
212
  ```
175
213
 
176
- Local currently certifies text SFT with `Qwen/Qwen3.5-2B`,
214
+ Local currently certifies text SFT with `Qwen/Qwen3.5-2B` (pinned to snapshot
215
+ `15852e8c16360a2fea060d615a32b45270f8a8fc`),
177
216
  `nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16`, and
178
217
  `meta-models/Muse-Glimmer-30B`, using LoRA/PEFT and CUDA. The 30B/3B-active
179
218
  Nemotron path is intended for DGX Spark-class unified memory, uses activation
@@ -184,7 +223,9 @@ vision tower frozen and unused. Evaluation and serving may use CPU. Training
184
223
  artifacts, datasets, and model weights remain on the execution host.
185
224
 
186
225
  Activation is optional and requires the run to pass a configured
187
- `generalRegression` gate. Once activated, use
226
+ `generalRegression` gate. Without that suite, `tt models activate` fails
227
+ closed. `tt serve active` also fails closed if nothing is activated — it does
228
+ not silently serve the protected base model. Once activated, use
188
229
  `tt serve active --config local-runner.json`.
189
230
 
190
231
  `tt serve base` does not automatically inject the adjacent project spec.
@@ -558,12 +558,14 @@ async function assertArtifactManifest(manifestPath, options = {}) {
558
558
  import { lstat as lstat2, readdir as readdir2 } from "fs/promises";
559
559
  import { resolve as resolve2 } from "path";
560
560
  import { fileURLToPath } from "url";
561
+ var QWEN_3_5_2B_REVISION = "15852e8c16360a2fea060d615a32b45270f8a8fc";
561
562
  var NEMOTRON_BF16_REVISION = "ce38b6ab8b252b4b8ee7165b4605e93191cafd73";
562
563
  var MUSE_GLIMMER_BF16_REVISION = "a4e59da52a7bc87ae7251dd5545c0dd437c44b68";
563
564
  var TRAINING_MODELS = [
564
565
  {
565
566
  id: "Qwen/Qwen3.5-2B",
566
567
  family: "qwen3_5",
568
+ defaultRevision: QWEN_3_5_2B_REVISION,
567
569
  modelLoader: "causal_lm",
568
570
  defaultLearningRate: 1e-5,
569
571
  defaultPerDeviceBatchSize: 1,
@@ -1403,7 +1405,7 @@ function localRuntimePackageRoot(moduleUrl) {
1403
1405
  // src/local-runtime/store.ts
1404
1406
  import { appendFile, copyFile as copyFile2, mkdir as mkdir3, readdir as readdir3, readFile as readFile4, rename as rename2, rm, stat as stat3, writeFile as writeFile3 } from "fs/promises";
1405
1407
  import { homedir as homedir2 } from "os";
1406
- import { dirname as dirname4, join as join2, resolve as resolve5 } from "path";
1408
+ import { dirname as dirname4, join as join2, resolve as resolve5, sep as sep2 } from "path";
1407
1409
  import { randomUUID as randomUUID3 } from "crypto";
1408
1410
  function isTerminalRunState(state) {
1409
1411
  return state.status === "stage_completed" || state.status === "completed" || state.status === "failed" || state.status === "cancelled" && state.current_stage === "cancelled" && Boolean(state.completed_at);
@@ -1476,6 +1478,11 @@ function compareCreatedAt(left, right) {
1476
1478
  function findByIdOrPrefix(records, id) {
1477
1479
  return records.find((record) => record.id === id) ?? records.find((record) => record.id.startsWith(id));
1478
1480
  }
1481
+ function isPathInside(root, candidate) {
1482
+ const resolvedRoot = resolve5(root);
1483
+ const resolvedCandidate = resolve5(candidate);
1484
+ return resolvedCandidate === resolvedRoot || resolvedCandidate.startsWith(`${resolvedRoot}${sep2}`);
1485
+ }
1479
1486
  function createLocalStore(root = defaultLocalHome()) {
1480
1487
  const resolvedRoot = resolve5(root);
1481
1488
  const paths = localStorePaths(resolvedRoot);
@@ -1853,11 +1860,19 @@ function createLocalStore(root = defaultLocalHome()) {
1853
1860
  },
1854
1861
  async getRunReport(id) {
1855
1862
  const state = await getRun(id);
1856
- if (state.report_path && await exists2(state.report_path)) {
1857
- return readJson2(state.report_path);
1863
+ const candidates = [];
1864
+ if (state.report_path) {
1865
+ const reportPath = resolve5(state.report_path);
1866
+ const allowedRoots = [resolvedRoot];
1867
+ if (state.artifact_dir) allowedRoots.push(resolve5(state.artifact_dir));
1868
+ if (allowedRoots.some((allowed) => isPathInside(allowed, reportPath))) {
1869
+ candidates.push(reportPath);
1870
+ }
1871
+ }
1872
+ candidates.push(runReportPath(state.id));
1873
+ for (const path of candidates) {
1874
+ if (await exists2(path)) return readJson2(path);
1858
1875
  }
1859
- const copiedReportPath = runReportPath(state.id);
1860
- if (await exists2(copiedReportPath)) return readJson2(copiedReportPath);
1861
1876
  throw new Error(`Run has no report yet: ${id}`);
1862
1877
  },
1863
1878
  async listModels() {
@@ -1875,7 +1890,7 @@ function createLocalStore(root = defaultLocalHome()) {
1875
1890
  import { createHash as createHash4 } from "crypto";
1876
1891
  import { createReadStream as createReadStream2 } from "fs";
1877
1892
  import { lstat as lstat3, mkdir as mkdir5, readFile as readFile5, readdir as readdir4, realpath as realpath2, stat as stat4 } from "fs/promises";
1878
- import { isAbsolute as isAbsolute3, join as join5, relative as relative2, resolve as resolve8, sep as sep2 } from "path";
1893
+ import { isAbsolute as isAbsolute3, join as join5, relative as relative2, resolve as resolve8, sep as sep3 } from "path";
1879
1894
 
1880
1895
  // src/local-runtime/process-runner.ts
1881
1896
  import { createHash as createHash3 } from "crypto";
@@ -1904,6 +1919,7 @@ function buildBundledPythonCommand(entrypoint, args = []) {
1904
1919
  const commandArgs = [
1905
1920
  "run",
1906
1921
  "--frozen",
1922
+ "--quiet",
1907
1923
  "--project",
1908
1924
  bundledProject,
1909
1925
  "python",
@@ -2221,7 +2237,7 @@ async function certifiedFileDigest(path, expected) {
2221
2237
  }
2222
2238
  function isStrictPhysicalDescendant(parent, child) {
2223
2239
  const candidate = relative2(parent, child);
2224
- return candidate !== "" && candidate !== ".." && !candidate.startsWith(`..${sep2}`) && !isAbsolute3(candidate);
2240
+ return candidate !== "" && candidate !== ".." && !candidate.startsWith(`..${sep3}`) && !isAbsolute3(candidate);
2225
2241
  }
2226
2242
  async function verifySnapshotCacheLocation(path, modelId, revision, modelCache) {
2227
2243
  const repository = `models--${modelId.replaceAll("/", "--")}`;
@@ -2292,9 +2308,7 @@ async function verifyCertifiedLocalSnapshot(path, modelId, snapshotFiles, modelC
2292
2308
  const revision = defaultBaseModelRevision(modelId);
2293
2309
  if (!revision) return;
2294
2310
  const digests = certifiedFileDigests(modelId);
2295
- if (!digests) {
2296
- throw new Error(`No certified file digests are registered for pinned model ${modelId}.`);
2297
- }
2311
+ if (!digests) return;
2298
2312
  if (!modelCache) {
2299
2313
  throw new Error(`A certified local snapshot for ${modelId} requires paths.modelCache.`);
2300
2314
  }
@@ -4797,4 +4811,4 @@ export {
4797
4811
  runLocalPipeline,
4798
4812
  runLocalFineTune
4799
4813
  };
4800
- //# sourceMappingURL=chunk-HDGBDHOB.js.map
4814
+ //# sourceMappingURL=chunk-YJYCGSHJ.js.map