@tuned-tensor/cli 0.9.0 → 0.9.2

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.js CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ assertLocalRunInputReady,
4
+ loadLocalRunInput,
5
+ loadLocalRunnerConfig,
6
+ runLocalPipeline
7
+ } from "./chunk-DAP2Z7EZ.js";
2
8
 
3
9
  // src/cli.ts
4
10
  import { spawn as spawn4 } from "child_process";
@@ -120,7 +126,8 @@ import {
120
126
  getAgentDir,
121
127
  ModelRuntime
122
128
  } from "@earendil-works/pi-coding-agent";
123
- import { join } from "path";
129
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
130
+ import { dirname, join } from "path";
124
131
  function resolveAgentModel(runtime, selection) {
125
132
  const resolved = resolveAgentModelDefinition(runtime, selection);
126
133
  if (!runtime.hasConfiguredAuth(selection.provider)) {
@@ -154,12 +161,41 @@ function resolveAgentModelDefinition(runtime, selection) {
154
161
  }
155
162
  async function createPiModelRuntime() {
156
163
  const agentDir = getAgentDir();
164
+ const modelsPath = join(agentDir, "models.json");
165
+ ensureOpenRouterAppHeaders(modelsPath);
157
166
  return await ModelRuntime.create({
158
167
  authPath: join(agentDir, "auth.json"),
159
- modelsPath: join(agentDir, "models.json"),
168
+ modelsPath,
160
169
  allowModelNetwork: false
161
170
  });
162
171
  }
172
+ var OPENROUTER_APP_HEADERS = {
173
+ "HTTP-Referer": "https://tunedtensor.com",
174
+ "X-Title": "Tuned Tensor"
175
+ };
176
+ function ensureOpenRouterAppHeaders(modelsPath) {
177
+ let config = {};
178
+ if (existsSync(modelsPath)) {
179
+ try {
180
+ const parsed = JSON.parse(readFileSync(modelsPath, "utf-8"));
181
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
182
+ config = parsed;
183
+ }
184
+ } catch {
185
+ return;
186
+ }
187
+ }
188
+ const before = JSON.stringify(config);
189
+ const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
190
+ const empty = () => ({});
191
+ const providers = asRecord(config.providers) ?? (config.providers = empty());
192
+ const openrouter = asRecord(providers.openrouter) ?? (providers.openrouter = empty());
193
+ const headers = asRecord(openrouter.headers) ?? (openrouter.headers = empty());
194
+ Object.assign(headers, OPENROUTER_APP_HEADERS);
195
+ if (JSON.stringify(config) === before) return;
196
+ mkdirSync(dirname(modelsPath), { recursive: true });
197
+ writeFileSync(modelsPath, JSON.stringify(config, null, 2) + "\n");
198
+ }
163
199
 
164
200
  // src/agent-tools.ts
165
201
  import { randomUUID } from "crypto";
@@ -235,6 +271,77 @@ function canonicalizeSpecBaseModel(body) {
235
271
  return body;
236
272
  }
237
273
 
274
+ // src/pipeline.ts
275
+ import {
276
+ canonicalPipeline as canonicalPortablePipeline,
277
+ parsePipeline,
278
+ pipelineDocumentSchema
279
+ } from "@tuned-tensor/pipeline-contract";
280
+ import {
281
+ PIPELINE_DOCUMENT_VERSION,
282
+ PIPELINE_EVALUATORS,
283
+ PIPELINE_MAX_STEPS,
284
+ PIPELINE_MAX_TRAIN_STEPS,
285
+ PIPELINE_STEP_CAPABILITIES,
286
+ PIPELINE_STEP_USES,
287
+ PIPELINE_TARGETS,
288
+ canonicalJson,
289
+ parsePipeline as parsePipeline2,
290
+ pipelineDocumentSchema as pipelineDocumentSchema2,
291
+ pipelineHash
292
+ } from "@tuned-tensor/pipeline-contract";
293
+ function stepReferences(step) {
294
+ if (step.uses === "evaluate") return step.with.model === "base" ? [] : [step.with.model];
295
+ if (step.uses === "compare") return [step.with.before, step.with.after];
296
+ return [];
297
+ }
298
+ function producerId(reference) {
299
+ return reference.from.slice(0, reference.from.lastIndexOf("."));
300
+ }
301
+ function validatePipeline(pipeline2) {
302
+ const structural = pipelineDocumentSchema.safeParse(pipeline2);
303
+ if (!structural.success) {
304
+ return structural.error.issues.map((issue) => {
305
+ const path = issue.path.map(String).join(".");
306
+ return path ? `${path}: ${issue.message}` : issue.message;
307
+ });
308
+ }
309
+ try {
310
+ parsePipeline(pipeline2);
311
+ return [];
312
+ } catch (error) {
313
+ return [error instanceof Error ? error.message : String(error)];
314
+ }
315
+ }
316
+ function canonicalPipeline(target = "local") {
317
+ return canonicalPortablePipeline(target);
318
+ }
319
+ function createExecutionPlan(pipeline2, selection = {}) {
320
+ const errors = validatePipeline(pipeline2);
321
+ if (errors.length) throw new Error(`Invalid pipeline:
322
+ - ${errors.join("\n- ")}`);
323
+ const normalized = parsePipeline(pipeline2);
324
+ const allIds = new Set(normalized.steps.map((step) => step.id));
325
+ for (const id of [...selection.only ?? [], ...selection.skip ?? []]) {
326
+ if (!allIds.has(id)) throw new Error(`Unknown pipeline step: ${id}.`);
327
+ }
328
+ const only = selection.only?.length ? new Set(selection.only) : void 0;
329
+ const skip = new Set(selection.skip ?? []);
330
+ const steps = normalized.steps.filter((step) => (!only || only.has(step.id)) && !skip.has(step.id));
331
+ if (!steps.length) throw new Error("Selection leaves no pipeline steps to run.");
332
+ const retained = new Map(steps.map((step) => [step.id, step]));
333
+ const resolved = steps.map((step) => {
334
+ const transfers = [];
335
+ for (const reference of stepReferences(step)) {
336
+ const producer = retained.get(producerId(reference));
337
+ if (!producer) throw new Error(`Step ${step.id} has a dependency on ${producerId(reference)}, which was omitted by --only or --skip.`);
338
+ if (producer.target !== step.target) transfers.push({ from: reference.from, from_target: producer.target, to_target: step.target });
339
+ }
340
+ return { ...step, transfers };
341
+ });
342
+ return { version: 1, ...normalized.name ? { name: normalized.name } : {}, steps: resolved };
343
+ }
344
+
238
345
  // src/agent-tools.ts
239
346
  var MAX_TOOL_OUTPUT = 32e3;
240
347
  var MAX_PREPARED_ACTION = 24e3;
@@ -283,6 +390,17 @@ var RunBody = Type.Object({
283
390
  var BaseModel = Type.Union(
284
391
  SUPPORTED_BASE_MODELS.map((model) => Type.Literal(model))
285
392
  );
393
+ var PipelineDocument = Type.Object({
394
+ version: Type.Literal(1),
395
+ name: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
396
+ target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")])),
397
+ steps: Type.Array(Type.Object({
398
+ id: Type.String({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_-]*$" }),
399
+ uses: Type.Union([Type.Literal("train"), Type.Literal("evaluate"), Type.Literal("compare")]),
400
+ target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")])),
401
+ with: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
402
+ }, { additionalProperties: false }), { minItems: 1, maxItems: 16 })
403
+ }, { additionalProperties: false });
286
404
  var Example = Type.Object({
287
405
  input: Type.String({ minLength: 1, maxLength: 1e5 }),
288
406
  output: Type.String({ minLength: 1, maxLength: 1e5 })
@@ -460,7 +578,18 @@ function createTunedTensorTools(api) {
460
578
  }, { additionalProperties: false }), async (p) => await api.get("/billing/transactions", {
461
579
  page: p.page ?? 1,
462
580
  per_page: p.per_page ?? 10
463
- }))
581
+ })),
582
+ define("describe_pipeline", "Describe pipeline", "Describe the built-in v1 pipeline contract and canonical recipe. This never executes anything.", Type.Object({
583
+ target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")]))
584
+ }, { additionalProperties: false }), async (p) => ({
585
+ version: 1,
586
+ components: ["train", "evaluate", "compare"],
587
+ canonical: canonicalPipeline(p.target ?? "local")
588
+ })),
589
+ define("validate_pipeline", "Validate pipeline", "Validate an ordered pipeline and resolve targets/transfers without filesystem, network, or execution side effects.", Type.Object({ pipeline: PipelineDocument }, { additionalProperties: false }), async (p) => {
590
+ const errors = validatePipeline(p.pipeline);
591
+ return { valid: errors.length === 0, errors, ...errors.length ? {} : { plan: createExecutionPlan(p.pipeline) } };
592
+ })
464
593
  ];
465
594
  const mutations = [
466
595
  define("prepare_create_spec", "Prepare create spec", "Prepare creating a spec. This never mutates; /approve is required.", Type.Object({
@@ -480,6 +609,19 @@ function createTunedTensorTools(api) {
480
609
  changes: p.changes,
481
610
  expected_spec_updated_at: current.updated_at
482
611
  }));
612
+ }),
613
+ define("prepare_pipeline_run", "Prepare pipeline run", "Prepare a pipeline action for review only. It never executes a step, transfers an artifact, or reserves credits.", Type.Object({
614
+ pipeline: PipelineDocument,
615
+ dry_run: Type.Optional(Type.Boolean())
616
+ }, { additionalProperties: false }), async (p) => {
617
+ const errors = validatePipeline(p.pipeline);
618
+ if (errors.length) throw new Error(`Invalid pipeline:
619
+ - ${errors.join("\n- ")}`);
620
+ const plan = createExecutionPlan(p.pipeline);
621
+ return await api.propose(proposal("run_pipeline", "Run pipeline", "Review the resolved pipeline before any separate execution approval flow.", {
622
+ pipeline: p.pipeline,
623
+ dry_run: p.dry_run ?? true
624
+ }, { plan, execution: "not started" }));
483
625
  })
484
626
  ];
485
627
  return [...reads, ...mutations];
@@ -876,16 +1018,16 @@ var LocalAgentStore = class {
876
1018
  };
877
1019
 
878
1020
  // src/client.ts
879
- import { readFileSync as readFileSync2, statSync } from "fs";
1021
+ import { readFileSync as readFileSync3, statSync } from "fs";
880
1022
  import { basename } from "path";
881
1023
 
882
1024
  // src/config.ts
883
1025
  import {
884
1026
  chmodSync,
885
- existsSync,
886
- mkdirSync,
887
- readFileSync,
888
- writeFileSync
1027
+ existsSync as existsSync2,
1028
+ mkdirSync as mkdirSync2,
1029
+ readFileSync as readFileSync2,
1030
+ writeFileSync as writeFileSync2
889
1031
  } from "fs";
890
1032
  import { homedir } from "os";
891
1033
  import { join as join3 } from "path";
@@ -910,19 +1052,19 @@ function getConfigPath() {
910
1052
  }
911
1053
  function readConfig() {
912
1054
  const path = getConfigPath();
913
- if (!existsSync(path)) return {};
1055
+ if (!existsSync2(path)) return {};
914
1056
  try {
915
- return JSON.parse(readFileSync(path, "utf-8"));
1057
+ return JSON.parse(readFileSync2(path, "utf-8"));
916
1058
  } catch {
917
1059
  return {};
918
1060
  }
919
1061
  }
920
1062
  function writeConfig(config) {
921
1063
  const dir = getConfigDir();
922
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
1064
+ if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true, mode: 448 });
923
1065
  chmodSync(dir, 448);
924
1066
  const path = getConfigPath();
925
- writeFileSync(path, JSON.stringify(config, null, 2) + "\n", {
1067
+ writeFileSync2(path, JSON.stringify(config, null, 2) + "\n", {
926
1068
  mode: 384
927
1069
  });
928
1070
  chmodSync(path, 384);
@@ -933,7 +1075,7 @@ function updateConfig(partial) {
933
1075
  }
934
1076
  function clearConfig() {
935
1077
  const path = getConfigPath();
936
- if (existsSync(path)) writeConfig({});
1078
+ if (existsSync2(path)) writeConfig({});
937
1079
  }
938
1080
  var DEFAULT_BASE_URL = "https://tunedtensor.com";
939
1081
  function getBaseUrl(opts) {
@@ -963,10 +1105,10 @@ function getAgentSelection(env = process.env) {
963
1105
 
964
1106
  // src/client.ts
965
1107
  var ApiError = class extends Error {
966
- constructor(status2, code, message) {
1108
+ constructor(status2, code2, message) {
967
1109
  super(message);
968
1110
  this.status = status2;
969
- this.code = code;
1111
+ this.code = code2;
970
1112
  this.name = "ApiError";
971
1113
  }
972
1114
  };
@@ -1194,7 +1336,7 @@ function createCommandCompleter(getMode) {
1194
1336
  // src/shell-context.ts
1195
1337
  import { readFile as readFile2, readdir as readdir2, stat as stat2 } from "fs/promises";
1196
1338
  import { homedir as homedir2 } from "os";
1197
- import { basename as basename2, dirname, isAbsolute, join as join4, resolve } from "path";
1339
+ import { basename as basename2, dirname as dirname2, isAbsolute, join as join4, resolve } from "path";
1198
1340
  async function readJsonObject(path) {
1199
1341
  try {
1200
1342
  const parsed = JSON.parse(await readFile2(path, "utf8"));
@@ -1312,7 +1454,7 @@ async function discoverShellContext(options = {}) {
1312
1454
  if (localConfigJson.invalid) {
1313
1455
  warnings.push("local-runner.json could not be parsed.");
1314
1456
  }
1315
- const localConfigDirectory = hasAdjacentLocalConfig ? dirname(localConfigPath) : cwd;
1457
+ const localConfigDirectory = hasAdjacentLocalConfig ? dirname2(localConfigPath) : cwd;
1316
1458
  const configuredArtifactRoot = stringField(localConfigJson.value, "artifactRoot");
1317
1459
  const configuredStoreRoot = stringField(localConfigJson.value, "storeRoot");
1318
1460
  const artifactRoot = configuredArtifactRoot ? expandPath(configuredArtifactRoot, localConfigDirectory, homeDirectory) : resolve(cwd, ".tt-local", "artifacts");
@@ -1742,9 +1884,9 @@ function renderShellBanner(snapshot) {
1742
1884
  const heading = snapshot.version ? `${accent.bold("tt")} ${chalk.dim(`v${snapshot.version}`)}` : accent.bold("tt");
1743
1885
  const lines = [
1744
1886
  heading,
1745
- chalk.dim(
1746
- `${snapshot.mode} \xB7 ${snapshot.context.projectName} \xB7 ${spec} \xB7 model ${activeModelLabel(snapshot)}`
1747
- ),
1887
+ `${accent(snapshot.mode)}${chalk.dim(
1888
+ ` \xB7 ${snapshot.context.projectName} \xB7 ${spec} \xB7 model ${activeModelLabel(snapshot)}`
1889
+ )}`,
1748
1890
  chalk.dim("ctrl+c stop/clear \xB7 ctrl+d exit \xB7 /help commands \xB7 tab complete"),
1749
1891
  "",
1750
1892
  chalk.dim("Ask TT anything. Known commands run directly.")
@@ -2101,6 +2243,7 @@ function shouldStartInteractiveShell(options) {
2101
2243
  import chalk2 from "chalk";
2102
2244
  import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
2103
2245
  var accent2 = chalk2.hex("#8B5CF6");
2246
+ var code = chalk2.hex("#A78BFA");
2104
2247
  function sanitizeTerminalText(text2) {
2105
2248
  return stripVTControlCharacters2(text2).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, "");
2106
2249
  }
@@ -2138,7 +2281,7 @@ function renderInlineMarkdown(text2) {
2138
2281
  if (text2[index] === "`") {
2139
2282
  const close = closingDelimiter(text2, "`", index);
2140
2283
  if (close > index + 1) {
2141
- rendered += chalk2.cyan(text2.slice(index + 1, close));
2284
+ rendered += code(text2.slice(index + 1, close));
2142
2285
  index = close + 1;
2143
2286
  continue;
2144
2287
  }
@@ -2160,7 +2303,7 @@ function renderInlineMarkdown(text2) {
2160
2303
  return rendered;
2161
2304
  }
2162
2305
  function renderMarkdownLine(line, inCodeBlock) {
2163
- if (inCodeBlock) return chalk2.cyan(` ${line}`);
2306
+ if (inCodeBlock) return code(` ${line}`);
2164
2307
  const heading = line.match(/^\s{0,3}#{1,6}\s+(.+)$/);
2165
2308
  if (heading) return chalk2.bold(renderInlineMarkdown(heading[1]));
2166
2309
  const bullet = line.match(/^(\s*)[-+*]\s+(.+)$/);
@@ -2646,8 +2789,9 @@ ${chalk3.yellow.bold("Approval required")} ${chalk3.dim(action.id.slice(0, 8))}
2646
2789
  // src/local-runner.ts
2647
2790
  import { constants as osConstants } from "os";
2648
2791
  import { randomUUID as randomUUID4 } from "crypto";
2649
- import { createRequire } from "module";
2650
2792
  import { spawn } from "child_process";
2793
+ import { existsSync as existsSync3 } from "fs";
2794
+ import { fileURLToPath } from "url";
2651
2795
  import {
2652
2796
  readFile as readFile3,
2653
2797
  rm,
@@ -2656,7 +2800,7 @@ import {
2656
2800
  } from "fs/promises";
2657
2801
  import {
2658
2802
  basename as basename3,
2659
- dirname as dirname2,
2803
+ dirname as dirname3,
2660
2804
  isAbsolute as isAbsolute3,
2661
2805
  join as join5,
2662
2806
  resolve as resolve3
@@ -2728,6 +2872,7 @@ function unknownProjectSpecKeys(raw) {
2728
2872
  // src/output.ts
2729
2873
  import chalk4 from "chalk";
2730
2874
  import Table from "cli-table3";
2875
+ var labelStyle = chalk4.bold.hex("#A78BFA");
2731
2876
  var jsonMode = false;
2732
2877
  function setJsonMode(enabled) {
2733
2878
  jsonMode = enabled;
@@ -2740,7 +2885,7 @@ function printJson(data3) {
2740
2885
  }
2741
2886
  function printTable(headers, rows2, meta) {
2742
2887
  const table = new Table({
2743
- head: headers.map((h) => chalk4.bold.cyan(h)),
2888
+ head: headers.map((h) => labelStyle(h)),
2744
2889
  style: { head: [], border: [] }
2745
2890
  });
2746
2891
  for (const row of rows2) {
@@ -2761,7 +2906,7 @@ function printDetail(fields) {
2761
2906
  const maxLabel = Math.max(...fields.map(([l]) => l.length));
2762
2907
  for (const [label, value] of fields) {
2763
2908
  const paddedLabel = label.padEnd(maxLabel);
2764
- console.log(`${chalk4.bold.cyan(paddedLabel)} ${value ?? chalk4.dim("\u2014")}`);
2909
+ console.log(`${labelStyle(paddedLabel)} ${value ?? chalk4.dim("\u2014")}`);
2765
2910
  }
2766
2911
  }
2767
2912
  function printSuccess(message) {
@@ -2797,9 +2942,9 @@ function formatDate(iso) {
2797
2942
  function formatStatus(status2) {
2798
2943
  const map = {
2799
2944
  completed: chalk4.green,
2800
- running: chalk4.blue,
2801
- training: chalk4.blue,
2802
- evaluating: chalk4.blue,
2945
+ running: chalk4.hex("#A78BFA"),
2946
+ training: chalk4.hex("#A78BFA"),
2947
+ evaluating: chalk4.hex("#A78BFA"),
2803
2948
  preparing: chalk4.yellow,
2804
2949
  pending: chalk4.yellow,
2805
2950
  uploading: chalk4.yellow,
@@ -3274,7 +3419,6 @@ function renderLocalOutput(payload, options = {}) {
3274
3419
  }
3275
3420
 
3276
3421
  // src/local-runner.ts
3277
- var localRequire = createRequire(import.meta.url);
3278
3422
  var DEFAULT_SPEC_NAME = "tunedtensor.json";
3279
3423
  var VALUE_OPTIONS = /* @__PURE__ */ new Set([
3280
3424
  "--config",
@@ -3439,7 +3583,7 @@ async function projectSpecArguments(originalArgs, cwd) {
3439
3583
  };
3440
3584
  }
3441
3585
  const temporaryPath = join5(
3442
- dirname2(sourcePath),
3586
+ dirname3(sourcePath),
3443
3587
  `.${basename3(sourcePath)}.tt-local-${process.pid}-${randomUUID4()}.json`
3444
3588
  );
3445
3589
  await writeFile2(
@@ -3460,14 +3604,13 @@ async function projectSpecArguments(originalArgs, cwd) {
3460
3604
  };
3461
3605
  }
3462
3606
  function resolveLocalCliEntrypoint() {
3463
- try {
3464
- return localRequire.resolve("@tuned-tensor/local");
3465
- } catch (error) {
3607
+ const entrypoint = fileURLToPath(new URL("./local-runtime.js", import.meta.url));
3608
+ if (!existsSync3(entrypoint)) {
3466
3609
  throw new Error(
3467
- "TT Local is not installed. Reinstall @tuned-tensor/cli with its local runtime dependency.",
3468
- { cause: error }
3610
+ "The bundled local runtime is missing. Rebuild or reinstall @tuned-tensor/cli."
3469
3611
  );
3470
3612
  }
3613
+ return entrypoint;
3471
3614
  }
3472
3615
  function localCommandStreamsStdout(args2) {
3473
3616
  const serves = args2[0] === "serve" || args2[0] === "models" && args2[1] === "serve";
@@ -3572,10 +3715,10 @@ async function spawnLocalCli(args2) {
3572
3715
  child.once("error", (error) => {
3573
3716
  spawnError = error;
3574
3717
  });
3575
- child.once("close", (code, signal) => {
3718
+ child.once("close", (code2, signal) => {
3576
3719
  cleanup();
3577
3720
  resolveChild({
3578
- exitCode: spawnError ? 1 : code ?? signalExitCode(signal),
3721
+ exitCode: spawnError ? 1 : code2 ?? signalExitCode(signal),
3579
3722
  signal,
3580
3723
  stdout: stdout2,
3581
3724
  stderr,
@@ -3695,7 +3838,7 @@ function registerAuthCommands(parent) {
3695
3838
  console.log(
3696
3839
  ` To get your API key, go to ${chalk5.bold("Settings \u2192 API Keys")} in the Tuned Tensor dashboard:`
3697
3840
  );
3698
- console.log(` ${chalk5.cyan.underline(settingsUrl)}`);
3841
+ console.log(` ${chalk5.hex("#A78BFA").underline(settingsUrl)}`);
3699
3842
  console.log();
3700
3843
  apiKey = await promptForApiKey();
3701
3844
  }
@@ -3754,7 +3897,7 @@ function registerAuthCommands(parent) {
3754
3897
  }
3755
3898
 
3756
3899
  // src/commands/specs.ts
3757
- import { readFileSync as readFileSync3 } from "fs";
3900
+ import { readFileSync as readFileSync4 } from "fs";
3758
3901
 
3759
3902
  // src/resolve.ts
3760
3903
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -3858,7 +4001,7 @@ var SpecBodyError = class extends Error {
3858
4001
  function loadSpecBody(filePath, mode) {
3859
4002
  let parsed;
3860
4003
  try {
3861
- parsed = JSON.parse(readFileSync3(filePath, "utf-8"));
4004
+ parsed = JSON.parse(readFileSync4(filePath, "utf-8"));
3862
4005
  } catch (e) {
3863
4006
  throw new SpecBodyError(
3864
4007
  `Could not parse ${filePath}: ${e.message}`
@@ -4527,7 +4670,7 @@ Eval Results (${data3._evals.length}):`);
4527
4670
  }
4528
4671
 
4529
4672
  // src/commands/datasets.ts
4530
- import { existsSync as existsSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
4673
+ import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
4531
4674
  var DOCUMENT_OCR_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
4532
4675
  function formatBytes(bytes) {
4533
4676
  if (bytes < 1024) return `${bytes} B`;
@@ -4563,24 +4706,24 @@ var FORBIDDEN_CONTROL_CODEPOINTS = [
4563
4706
  ];
4564
4707
  function findControlChar(value) {
4565
4708
  for (let i = 0; i < value.length; i++) {
4566
- const code = value.charCodeAt(i);
4567
- if (code < 32 && code !== 9 && code !== 10 && code !== 13) {
4568
- const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code);
4569
- return { codepoint: code, offset: i, name: named?.name ?? "CONTROL CHARACTER" };
4709
+ const code2 = value.charCodeAt(i);
4710
+ if (code2 < 32 && code2 !== 9 && code2 !== 10 && code2 !== 13) {
4711
+ const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code2);
4712
+ return { codepoint: code2, offset: i, name: named?.name ?? "CONTROL CHARACTER" };
4570
4713
  }
4571
- if (code >= 128 && code <= 159) {
4572
- const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code);
4573
- return { codepoint: code, offset: i, name: named?.name ?? "C1 CONTROL CHARACTER" };
4714
+ if (code2 >= 128 && code2 <= 159) {
4715
+ const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code2);
4716
+ return { codepoint: code2, offset: i, name: named?.name ?? "C1 CONTROL CHARACTER" };
4574
4717
  }
4575
- if (code === 8232 || code === 8233) {
4576
- const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code);
4577
- return { codepoint: code, offset: i, name: named?.name ?? "LINE BREAK" };
4718
+ if (code2 === 8232 || code2 === 8233) {
4719
+ const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code === code2);
4720
+ return { codepoint: code2, offset: i, name: named?.name ?? "LINE BREAK" };
4578
4721
  }
4579
4722
  }
4580
4723
  return null;
4581
4724
  }
4582
- function formatCodepoint(code) {
4583
- return `U+${code.toString(16).toUpperCase().padStart(4, "0")}`;
4725
+ function formatCodepoint(code2) {
4726
+ return `U+${code2.toString(16).toUpperCase().padStart(4, "0")}`;
4584
4727
  }
4585
4728
  function detectRowFormat(record4) {
4586
4729
  const input = record4.input;
@@ -4657,7 +4800,7 @@ function parseDatasetFormat(value) {
4657
4800
  throw new Error("--format must be one of: jsonl, document_ocr_jsonl");
4658
4801
  }
4659
4802
  function validateDatasetFile(file, requestedFormat) {
4660
- const lines = readFileSync4(file, "utf8").split(/\r?\n/);
4803
+ const lines = readFileSync5(file, "utf8").split(/\r?\n/);
4661
4804
  const errors = [];
4662
4805
  let rowCount = 0;
4663
4806
  let detectedFormat = null;
@@ -4783,13 +4926,13 @@ function registerDatasetsCommands(parent) {
4783
4926
  });
4784
4927
  datasets.command("upload").description("Upload a JSONL dataset file").argument("<file>", "Path to JSONL file").option("-n, --name <name>", "Dataset name (defaults to filename)").option("-d, --description <desc>", "Dataset description").option("--format <format>", "Dataset format: jsonl or document_ocr_jsonl").action(async (file, cmdOpts) => {
4785
4928
  const opts = parent.opts();
4786
- if (!existsSync2(file)) {
4929
+ if (!existsSync4(file)) {
4787
4930
  printError(`File not found: ${file}`);
4788
4931
  process.exit(1);
4789
4932
  }
4790
4933
  const format = validateDatasetFile(file, parseDatasetFormat(cmdOpts.format));
4791
4934
  const name = cmdOpts.name || file.split("/").pop().replace(/\.jsonl?$/, "");
4792
- const fileBytes = readFileSync4(file);
4935
+ const fileBytes = readFileSync5(file);
4793
4936
  const uploadUrl = await post(
4794
4937
  "/datasets/upload-url",
4795
4938
  {
@@ -4834,12 +4977,12 @@ function registerDatasetsCommands(parent) {
4834
4977
  }
4835
4978
 
4836
4979
  // src/commands/label.ts
4837
- import { existsSync as existsSync3, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
4980
+ import { existsSync as existsSync5, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
4838
4981
  function formatCents2(cents) {
4839
4982
  return `$${(cents / 100).toFixed(2)}`;
4840
4983
  }
4841
4984
  function sleep(ms) {
4842
- return new Promise((resolve7) => setTimeout(resolve7, ms));
4985
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
4843
4986
  }
4844
4987
  function parseCsvHeader(line) {
4845
4988
  const fields = [];
@@ -4878,7 +5021,7 @@ function validateUnlabeledFile(file, inputColumn) {
4878
5021
  "CSV uploads need --input-column <name> to say which column holds the input text."
4879
5022
  );
4880
5023
  }
4881
- const firstLine = readFileSync5(file, "utf8").split(/\r?\n/, 1)[0] ?? "";
5024
+ const firstLine = readFileSync6(file, "utf8").split(/\r?\n/, 1)[0] ?? "";
4882
5025
  const columns = parseCsvHeader(firstLine);
4883
5026
  if (!columns.includes(inputColumn)) {
4884
5027
  throw new Error(
@@ -4890,7 +5033,7 @@ function validateUnlabeledFile(file, inputColumn) {
4890
5033
  if (!lower.endsWith(".jsonl") && !lower.endsWith(".json")) {
4891
5034
  throw new Error("Labeling source file must be .jsonl or .csv");
4892
5035
  }
4893
- const lines = readFileSync5(file, "utf8").split(/\r?\n/);
5036
+ const lines = readFileSync6(file, "utf8").split(/\r?\n/);
4894
5037
  const errors = [];
4895
5038
  let rowCount = 0;
4896
5039
  for (const [index, rawLine] of lines.entries()) {
@@ -5006,14 +5149,14 @@ function registerLabelCommands(parent) {
5006
5149
  const label = parent.command("label").description("Teacher-label real data into training datasets");
5007
5150
  label.command("upload").description("Upload unlabeled inputs (.jsonl or .csv) and start a labeling job").argument("<file>", 'Path to JSONL ({"input": ...} per line) or CSV file').requiredOption("-s, --spec <id>", "Behaviour spec the teacher labels under").option("-c, --input-column <name>", "CSV column that holds the input text").option("-n, --name <name>", "Job name (defaults to filename)").option("--watch", "Block and show progress until labeling finishes").action(async (file, cmdOpts) => {
5008
5151
  const opts = parent.opts();
5009
- if (!existsSync3(file)) {
5152
+ if (!existsSync5(file)) {
5010
5153
  printError(`File not found: ${file}`);
5011
5154
  process.exit(1);
5012
5155
  }
5013
5156
  const { format } = validateUnlabeledFile(file, cmdOpts.inputColumn);
5014
5157
  const specId = await resolveSpecId(cmdOpts.spec, opts);
5015
5158
  const name = cmdOpts.name || file.split("/").pop().replace(/\.(jsonl|json|csv)$/, "");
5016
- const fileBytes = readFileSync5(file);
5159
+ const fileBytes = readFileSync6(file);
5017
5160
  const contentType = format === "csv" ? "text/csv" : "application/jsonl";
5018
5161
  const { data: uploadUrl } = await post(
5019
5162
  "/labeling-jobs/upload-url",
@@ -5186,7 +5329,7 @@ function registerLabelCommands(parent) {
5186
5329
  printError("Provide --output <text> or --file <path>.");
5187
5330
  process.exit(1);
5188
5331
  }
5189
- const output = cmdOpts.output ?? readFileSync5(cmdOpts.file, "utf8");
5332
+ const output = cmdOpts.output ?? readFileSync6(cmdOpts.file, "utf8");
5190
5333
  const jobId = await resolveLabelingJobId(id, opts);
5191
5334
  const indexes = parseIndexList(cmdOpts.row);
5192
5335
  const rowIds = await resolveRowIds(jobId, indexes, opts);
@@ -5235,23 +5378,23 @@ function registerLabelCommands(parent) {
5235
5378
  import { spawn as spawn3, execFileSync } from "child_process";
5236
5379
  import { createHash } from "crypto";
5237
5380
  import {
5238
- existsSync as existsSync5,
5239
- mkdirSync as mkdirSync3,
5381
+ existsSync as existsSync7,
5382
+ mkdirSync as mkdirSync4,
5240
5383
  statSync as statSync4,
5241
5384
  createWriteStream,
5242
5385
  unlinkSync,
5243
- readFileSync as readFileSync7,
5244
- writeFileSync as writeFileSync3,
5386
+ readFileSync as readFileSync8,
5387
+ writeFileSync as writeFileSync4,
5245
5388
  readdirSync,
5246
5389
  rmSync
5247
5390
  } from "fs";
5248
5391
  import { homedir as homedir4 } from "os";
5249
- import { dirname as dirname4, join as join6, resolve as resolve5, basename as basename4, normalize, isAbsolute as isAbsolute4 } from "path";
5392
+ import { dirname as dirname5, join as join6, resolve as resolve5, basename as basename4, normalize, isAbsolute as isAbsolute4 } from "path";
5250
5393
  import { Readable, Transform } from "stream";
5251
5394
  import { pipeline } from "stream/promises";
5252
5395
 
5253
5396
  // src/commands/init.ts
5254
- import { existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
5397
+ import { existsSync as existsSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
5255
5398
  import { resolve as resolve4 } from "path";
5256
5399
  var DEFAULT_SPEC_FILE = "tunedtensor.json";
5257
5400
  var SCAFFOLD = {
@@ -5272,7 +5415,7 @@ var SCAFFOLD = {
5272
5415
  function registerInitCommand(parent) {
5273
5416
  parent.command("init").description("Create a behaviour spec project file").option("-n, --name <name>", "Spec name").option("--model <model>", "Base model ID").option("-f, --file <path>", "Output file path", DEFAULT_SPEC_FILE).action(async (cmdOpts) => {
5274
5417
  const filePath = resolve4(cmdOpts.file);
5275
- if (existsSync4(filePath)) {
5418
+ if (existsSync6(filePath)) {
5276
5419
  if (isJsonMode()) {
5277
5420
  printJson({ created: false, path: filePath });
5278
5421
  return;
@@ -5286,7 +5429,7 @@ function registerInitCommand(parent) {
5286
5429
  };
5287
5430
  if (cmdOpts.name) spec.name = cmdOpts.name;
5288
5431
  if (cmdOpts.model) spec.base_model = canonicalizeBaseModel(cmdOpts.model);
5289
- writeFileSync2(filePath, JSON.stringify(spec, null, 2) + "\n");
5432
+ writeFileSync3(filePath, JSON.stringify(spec, null, 2) + "\n");
5290
5433
  if (isJsonMode()) {
5291
5434
  printJson({ created: true, path: filePath, spec });
5292
5435
  return;
@@ -5301,36 +5444,36 @@ function registerInitCommand(parent) {
5301
5444
  }
5302
5445
  function loadSpec(filePath) {
5303
5446
  const resolved = resolve4(filePath || DEFAULT_SPEC_FILE);
5304
- if (!existsSync4(resolved)) {
5447
+ if (!existsSync6(resolved)) {
5305
5448
  printError(
5306
5449
  `Spec file not found: ${filePath || DEFAULT_SPEC_FILE}
5307
5450
  Run \`tt init\` to create one.`
5308
5451
  );
5309
5452
  process.exit(1);
5310
5453
  }
5311
- const raw = JSON.parse(readFileSync6(resolved, "utf-8"));
5454
+ const raw = JSON.parse(readFileSync7(resolved, "utf-8"));
5312
5455
  return raw;
5313
5456
  }
5314
5457
 
5315
5458
  // src/serve-manager.ts
5316
5459
  import { spawn as spawn2 } from "child_process";
5317
5460
  import { randomUUID as randomUUID5 } from "crypto";
5318
- import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
5461
+ import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
5319
5462
  import { createServer } from "http";
5320
5463
  import { createServer as createNetServer } from "net";
5321
- import { dirname as dirname3 } from "path";
5464
+ import { dirname as dirname4 } from "path";
5322
5465
  var COMPLETION_ROUTES = /* @__PURE__ */ new Set(["/v1/chat/completions", "/chat/completions"]);
5323
5466
  function parsePositiveInteger(value, fallback) {
5324
5467
  return Number.isInteger(value) && value >= 0 ? value : fallback;
5325
5468
  }
5326
5469
  function sleep2(ms) {
5327
- return new Promise((resolve7) => setTimeout(resolve7, ms));
5470
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
5328
5471
  }
5329
5472
  function readRequestBody(req) {
5330
- return new Promise((resolve7, reject) => {
5473
+ return new Promise((resolve8, reject) => {
5331
5474
  const chunks = [];
5332
5475
  req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
5333
- req.on("end", () => resolve7(Buffer.concat(chunks)));
5476
+ req.on("end", () => resolve8(Buffer.concat(chunks)));
5334
5477
  req.on("error", reject);
5335
5478
  });
5336
5479
  }
@@ -5398,7 +5541,7 @@ function errorSummary(response, fallback) {
5398
5541
  return typeof message === "string" ? message : fallback;
5399
5542
  }
5400
5543
  async function allocatePort(host) {
5401
- return new Promise((resolve7, reject) => {
5544
+ return new Promise((resolve8, reject) => {
5402
5545
  const server = createNetServer();
5403
5546
  server.on("error", reject);
5404
5547
  server.listen(0, host, () => {
@@ -5408,7 +5551,7 @@ async function allocatePort(host) {
5408
5551
  return;
5409
5552
  }
5410
5553
  const port = address.port;
5411
- server.close(() => resolve7(port));
5554
+ server.close(() => resolve8(port));
5412
5555
  });
5413
5556
  });
5414
5557
  }
@@ -5448,11 +5591,11 @@ var ManagedModelServer = class {
5448
5591
  sendJson(res, 500, { error: { message: err instanceof Error ? err.message : String(err) } });
5449
5592
  });
5450
5593
  });
5451
- await new Promise((resolve7, reject) => {
5594
+ await new Promise((resolve8, reject) => {
5452
5595
  this.server?.once("error", reject);
5453
5596
  this.server?.listen(this.options.publicPort, this.options.publicHost, () => {
5454
5597
  this.server?.off("error", reject);
5455
- resolve7();
5598
+ resolve8();
5456
5599
  });
5457
5600
  });
5458
5601
  }
@@ -5462,15 +5605,15 @@ var ManagedModelServer = class {
5462
5605
  if (!this.server) return;
5463
5606
  const server = this.server;
5464
5607
  this.server = null;
5465
- await new Promise((resolve7, reject) => {
5466
- server.close((err) => err ? reject(err) : resolve7());
5608
+ await new Promise((resolve8, reject) => {
5609
+ server.close((err) => err ? reject(err) : resolve8());
5467
5610
  });
5468
5611
  }
5469
5612
  async run() {
5470
5613
  await this.start();
5471
- await new Promise((resolve7, reject) => {
5614
+ await new Promise((resolve8, reject) => {
5472
5615
  this.server?.once("error", reject);
5473
- this.server?.once("close", resolve7);
5616
+ this.server?.once("close", resolve8);
5474
5617
  });
5475
5618
  }
5476
5619
  async handle(req, res) {
@@ -5644,7 +5787,7 @@ var ManagedModelServer = class {
5644
5787
  try {
5645
5788
  child.kill("SIGTERM");
5646
5789
  await Promise.race([
5647
- new Promise((resolve7) => child.once("exit", () => resolve7())),
5790
+ new Promise((resolve8) => child.once("exit", () => resolve8())),
5648
5791
  sleep2(5e3).then(() => {
5649
5792
  if (child.exitCode == null && child.signalCode == null) child.kill("SIGKILL");
5650
5793
  })
@@ -5722,7 +5865,7 @@ var ManagedModelServer = class {
5722
5865
  const line = `${JSON.stringify(record4)}
5723
5866
  `;
5724
5867
  if (this.options.logFile) {
5725
- mkdirSync2(dirname3(this.options.logFile), { recursive: true });
5868
+ mkdirSync3(dirname4(this.options.logFile), { recursive: true });
5726
5869
  appendFileSync(this.options.logFile, line, "utf8");
5727
5870
  return;
5728
5871
  }
@@ -6269,7 +6412,7 @@ if __name__ == "__main__":
6269
6412
  `;
6270
6413
  function resolveOutputPath(output, filename) {
6271
6414
  if (!output) return filename;
6272
- if (existsSync5(output) && statSync4(output).isDirectory()) {
6415
+ if (existsSync7(output) && statSync4(output).isDirectory()) {
6273
6416
  return join6(output, filename);
6274
6417
  }
6275
6418
  return output;
@@ -6346,7 +6489,7 @@ async function downloadUrlToFile(url, outputPath) {
6346
6489
  if (!res.body) {
6347
6490
  throw new Error("Download failed: response body was empty");
6348
6491
  }
6349
- mkdirSync3(dirname4(outputPath), { recursive: true });
6492
+ mkdirSync4(dirname5(outputPath), { recursive: true });
6350
6493
  const file = createWriteStream(outputPath);
6351
6494
  const contentLength = parseContentLength(res.headers.get("content-length"));
6352
6495
  const progress = createDownloadProgress(
@@ -6390,7 +6533,7 @@ function runtimePythonPath(cacheDir) {
6390
6533
  function resolveServePython(cacheDir, explicitPython) {
6391
6534
  if (explicitPython) return explicitPython;
6392
6535
  const managedPython = runtimePythonPath(cacheDir);
6393
- return existsSync5(managedPython) ? managedPython : "python3";
6536
+ return existsSync7(managedPython) ? managedPython : "python3";
6394
6537
  }
6395
6538
  function commandExists(command) {
6396
6539
  try {
@@ -6469,7 +6612,7 @@ function safeSegment(value) {
6469
6612
  return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "model";
6470
6613
  }
6471
6614
  function directoryHasFiles(path) {
6472
- return existsSync5(path) && statSync4(path).isDirectory() && readdirSync(path).length > 0;
6615
+ return existsSync7(path) && statSync4(path).isDirectory() && readdirSync(path).length > 0;
6473
6616
  }
6474
6617
  function validateArchiveEntryPath(entry) {
6475
6618
  const normalized = normalize(entry).replace(/^[\\/]+/, "");
@@ -6490,8 +6633,8 @@ function validateArchiveEntries(archivePath) {
6490
6633
  function extractArchive(archivePath, targetDir, force) {
6491
6634
  if (directoryHasFiles(targetDir) && !force) return targetDir;
6492
6635
  validateArchiveEntries(archivePath);
6493
- if (existsSync5(targetDir)) rmSync(targetDir, { recursive: true, force: true });
6494
- mkdirSync3(targetDir, { recursive: true });
6636
+ if (existsSync7(targetDir)) rmSync(targetDir, { recursive: true, force: true });
6637
+ mkdirSync4(targetDir, { recursive: true });
6495
6638
  execFileSync("tar", ["-xzf", archivePath, "-C", targetDir], { stdio: "inherit" });
6496
6639
  return targetDir;
6497
6640
  }
@@ -6517,21 +6660,21 @@ function findSpecPath(explicitPath, modelPath) {
6517
6660
  const candidates = explicitPath ? [explicitPath] : [join6(process.cwd(), DEFAULT_SPEC_FILE), join6(modelPath, DEFAULT_SPEC_FILE)];
6518
6661
  for (const candidate of candidates) {
6519
6662
  const resolved = resolve5(candidate);
6520
- if (existsSync5(resolved) && statSync4(resolved).isFile()) return resolved;
6663
+ if (existsSync7(resolved) && statSync4(resolved).isFile()) return resolved;
6521
6664
  }
6522
6665
  return null;
6523
6666
  }
6524
6667
  function loadSystemPromptFromSpec(specPath) {
6525
- const spec = JSON.parse(readFileSync7(specPath, "utf8"));
6668
+ const spec = JSON.parse(readFileSync8(specPath, "utf8"));
6526
6669
  return buildSystemPrompt(spec);
6527
6670
  }
6528
6671
  function loadJsonSchemaForServe(schemaPath) {
6529
6672
  const resolved = resolve5(schemaPath);
6530
- if (!existsSync5(resolved) || !statSync4(resolved).isFile()) {
6673
+ if (!existsSync7(resolved) || !statSync4(resolved).isFile()) {
6531
6674
  throw new Error(`JSON schema file not found: ${schemaPath}`);
6532
6675
  }
6533
6676
  try {
6534
- const schema = JSON.parse(readFileSync7(resolved, "utf8"));
6677
+ const schema = JSON.parse(readFileSync8(resolved, "utf8"));
6535
6678
  return JSON.stringify(schema);
6536
6679
  } catch (err) {
6537
6680
  throw new Error(`JSON schema file is not valid JSON: ${schemaPath}`);
@@ -6539,13 +6682,13 @@ function loadJsonSchemaForServe(schemaPath) {
6539
6682
  }
6540
6683
  function writeReferenceServerScript(cacheDir) {
6541
6684
  const scriptDir = join6(cacheDir, "_server");
6542
- mkdirSync3(scriptDir, { recursive: true });
6685
+ mkdirSync4(scriptDir, { recursive: true });
6543
6686
  const scriptPath = join6(scriptDir, "openai_reference_server.py");
6544
- writeFileSync3(scriptPath, REFERENCE_SERVER_SCRIPT, "utf8");
6687
+ writeFileSync4(scriptPath, REFERENCE_SERVER_SCRIPT, "utf8");
6545
6688
  return scriptPath;
6546
6689
  }
6547
6690
  async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
6548
- if (existsSync5(target)) {
6691
+ if (existsSync7(target)) {
6549
6692
  const resolved = resolve5(target);
6550
6693
  const stats = statSync4(resolved);
6551
6694
  if (stats.isDirectory()) {
@@ -6571,7 +6714,7 @@ async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
6571
6714
  const modelCacheDir = join6(cacheDir, fullId);
6572
6715
  const archivePath = join6(modelCacheDir, data3.filename);
6573
6716
  const extractDir = join6(modelCacheDir, "model");
6574
- if (!existsSync5(archivePath) || forceDownload) {
6717
+ if (!existsSync7(archivePath) || forceDownload) {
6575
6718
  await downloadUrlToFile(data3.url, archivePath);
6576
6719
  }
6577
6720
  extractArchive(archivePath, extractDir, forceDownload);
@@ -6675,7 +6818,7 @@ function ollamaSlug(name) {
6675
6818
  }
6676
6819
  function firstExisting(candidates) {
6677
6820
  for (const candidate of candidates) {
6678
- if (candidate && existsSync5(candidate) && statSync4(candidate).isFile()) {
6821
+ if (candidate && existsSync7(candidate) && statSync4(candidate).isFile()) {
6679
6822
  return resolve5(candidate);
6680
6823
  }
6681
6824
  }
@@ -6687,7 +6830,7 @@ function llamaCppDir(explicit) {
6687
6830
  function resolveConvertScript(opts, required) {
6688
6831
  if (opts.convertScript) {
6689
6832
  const resolved = resolve5(opts.convertScript);
6690
- if (required && !existsSync5(resolved)) {
6833
+ if (required && !existsSync7(resolved)) {
6691
6834
  throw new Error(`Conversion script not found: ${opts.convertScript}`);
6692
6835
  }
6693
6836
  return resolved;
@@ -6706,7 +6849,7 @@ function resolveConvertScript(opts, required) {
6706
6849
  function resolveQuantizeBin(opts, required) {
6707
6850
  if (opts.quantizeBin) {
6708
6851
  const resolved = resolve5(opts.quantizeBin);
6709
- if (required && !existsSync5(resolved)) {
6852
+ if (required && !existsSync7(resolved)) {
6710
6853
  throw new Error(`llama-quantize binary not found: ${opts.quantizeBin}`);
6711
6854
  }
6712
6855
  return resolved;
@@ -6841,7 +6984,7 @@ function registerModelsCommands(parent) {
6841
6984
  opts
6842
6985
  );
6843
6986
  const outputPath = resolveOutputPath(cmdOpts.output, data3.filename);
6844
- if (existsSync5(outputPath) && !cmdOpts.force) {
6987
+ if (existsSync7(outputPath) && !cmdOpts.force) {
6845
6988
  throw new Error(`Output file already exists: ${outputPath}. Use --force to overwrite.`);
6846
6989
  }
6847
6990
  const bytes = await downloadUrlToFile(data3.url, outputPath);
@@ -6866,7 +7009,7 @@ function registerModelsCommands(parent) {
6866
7009
  const quantPlan = planQuant(String(cmdOpts.quant));
6867
7010
  const printOnly = Boolean(cmdOpts.printCommand);
6868
7011
  const cacheDir = resolve5(cmdOpts.cacheDir || defaultCacheDir());
6869
- mkdirSync3(cacheDir, { recursive: true });
7012
+ mkdirSync4(cacheDir, { recursive: true });
6870
7013
  const serveTarget = await resolveServeTarget(
6871
7014
  target,
6872
7015
  opts,
@@ -6950,10 +7093,10 @@ function registerModelsCommands(parent) {
6950
7093
  ollama: ollamaInfo
6951
7094
  };
6952
7095
  if (printOnly) return printExportPlan(plan);
6953
- if (existsSync5(finalPath) && !cmdOpts.force) {
7096
+ if (existsSync7(finalPath) && !cmdOpts.force) {
6954
7097
  throw new Error(`Output already exists: ${finalPath}. Use --force to overwrite.`);
6955
7098
  }
6956
- mkdirSync3(outputDir, { recursive: true });
7099
+ mkdirSync4(outputDir, { recursive: true });
6957
7100
  const runStep = (command, args2) => execFileSync(command, args2, { stdio: "inherit" });
6958
7101
  if (!isJsonMode()) printSuccess(`Converting ${serveTarget.modelName} \u2192 ${quantPlan.convertOuttype} GGUF`);
6959
7102
  runStep(cmdOpts.python, [
@@ -6971,12 +7114,12 @@ function registerModelsCommands(parent) {
6971
7114
  finalPath,
6972
7115
  quantPlan.quantizeType
6973
7116
  ]);
6974
- if (!cmdOpts.keepIntermediate && intermediatePath && existsSync5(intermediatePath)) {
7117
+ if (!cmdOpts.keepIntermediate && intermediatePath && existsSync7(intermediatePath)) {
6975
7118
  rmSync(intermediatePath, { force: true });
6976
7119
  }
6977
7120
  }
6978
7121
  if (ollamaInfo) {
6979
- writeFileSync3(modelfilePath, modelfileContent, "utf8");
7122
+ writeFileSync4(modelfilePath, modelfileContent, "utf8");
6980
7123
  if (!isJsonMode()) printSuccess(`Wrote Modelfile to ${modelfilePath}`);
6981
7124
  if (ollamaInfo.create) {
6982
7125
  if (!isJsonMode()) printSuccess(`Creating Ollama model ${ollamaName}`);
@@ -7024,11 +7167,11 @@ function registerModelsCommands(parent) {
7024
7167
  ]);
7025
7168
  return;
7026
7169
  }
7027
- if (existsSync5(venvDir) && cmdOpts.force) {
7170
+ if (existsSync7(venvDir) && cmdOpts.force) {
7028
7171
  rmSync(venvDir, { recursive: true, force: true });
7029
7172
  }
7030
- if (!existsSync5(venvPython)) {
7031
- mkdirSync3(cacheDir, { recursive: true });
7173
+ if (!existsSync7(venvPython)) {
7174
+ mkdirSync4(cacheDir, { recursive: true });
7032
7175
  execFileSync(commands[0][0], commands[0].slice(1), { stdio: "inherit" });
7033
7176
  }
7034
7177
  execFileSync(commands[1][0], commands[1].slice(1), { stdio: "inherit" });
@@ -7048,7 +7191,7 @@ function registerModelsCommands(parent) {
7048
7191
  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) => {
7049
7192
  const opts = parent.opts();
7050
7193
  const cacheDir = resolve5(cmdOpts.cacheDir || defaultCacheDir());
7051
- mkdirSync3(cacheDir, { recursive: true });
7194
+ mkdirSync4(cacheDir, { recursive: true });
7052
7195
  const python = resolveServePython(cacheDir, cmdOpts.python);
7053
7196
  if (!cmdOpts.printCommand) ensureServingRuntime(python, cacheDir);
7054
7197
  const serveTarget = await resolveServeTarget(
@@ -7143,9 +7286,9 @@ function registerModelsCommands(parent) {
7143
7286
  env: { ...process.env, ...env }
7144
7287
  });
7145
7288
  child.on("error", reject);
7146
- child.on("exit", (code, signal) => {
7147
- if (code === 0) return resolvePromise();
7148
- reject(new Error(`Model server exited with ${signal ?? `code ${code}`}`));
7289
+ child.on("exit", (code2, signal) => {
7290
+ if (code2 === 0) return resolvePromise();
7291
+ reject(new Error(`Model server exited with ${signal ?? `code ${code2}`}`));
7149
7292
  });
7150
7293
  });
7151
7294
  });
@@ -7302,7 +7445,7 @@ function registerTopupCommands(parent) {
7302
7445
  }
7303
7446
  const url = data3.checkout_url;
7304
7447
  console.log(
7305
- `${chalk7.bold("Checkout URL:")} ${chalk7.cyan(url)}
7448
+ `${chalk7.bold("Checkout URL:")} ${chalk7.hex("#A78BFA")(url)}
7306
7449
  ` + chalk7.dim("Complete the payment to credit your account.")
7307
7450
  );
7308
7451
  if (options.open !== false) {
@@ -7510,12 +7653,12 @@ function printValidation(checks) {
7510
7653
  }
7511
7654
 
7512
7655
  // src/commands/push.ts
7513
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
7656
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
7514
7657
  import { resolve as resolve6 } from "path";
7515
7658
  function persistRemoteId(filePath, id) {
7516
- const raw = JSON.parse(readFileSync8(filePath, "utf-8"));
7659
+ const raw = JSON.parse(readFileSync9(filePath, "utf-8"));
7517
7660
  raw.id = id;
7518
- writeFileSync4(filePath, JSON.stringify(raw, null, 2) + "\n");
7661
+ writeFileSync5(filePath, JSON.stringify(raw, null, 2) + "\n");
7519
7662
  }
7520
7663
  function registerPushCommand(parent) {
7521
7664
  parent.command("push").description("Push local spec to the Tuned Tensor API").option("-f, --file <path>", "Spec file path", DEFAULT_SPEC_FILE).action(async (cmdOpts) => {
@@ -7639,6 +7782,81 @@ function registerAgentCommands(parent, options) {
7639
7782
  });
7640
7783
  }
7641
7784
 
7785
+ // src/commands/pipeline.ts
7786
+ import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
7787
+ import { resolve as resolve7 } from "path";
7788
+ var DEFAULT_PIPELINE_FILE = "tunedtensor.pipeline.json";
7789
+ function parseList(value) {
7790
+ if (!value) return void 0;
7791
+ const ids = value.split(",").map((id) => id.trim()).filter(Boolean);
7792
+ if (!ids.length) throw new Error("Step selection must name at least one step.");
7793
+ return ids;
7794
+ }
7795
+ function loadPipeline(path) {
7796
+ const resolved = resolve7(path);
7797
+ if (!existsSync8(resolved)) throw new Error(`Pipeline file not found: ${path}. Run \`tt pipeline init\` to create one.`);
7798
+ try {
7799
+ return JSON.parse(readFileSync10(resolved, "utf8"));
7800
+ } catch (error) {
7801
+ throw new Error(`Pipeline file must be JSON: ${error.message}`);
7802
+ }
7803
+ }
7804
+ function outputPlan(plan) {
7805
+ if (isJsonMode()) return printJson(plan);
7806
+ const typed = plan;
7807
+ for (const step of typed.steps) {
7808
+ console.log(`${step.id.padEnd(16)} ${step.uses.padEnd(10)} ${step.target}`);
7809
+ for (const transfer of step.transfers) console.log(` transfer ${transfer.from}: ${transfer.from_target} -> ${transfer.to_target}`);
7810
+ }
7811
+ }
7812
+ function registerPipelineCommands(parent) {
7813
+ const pipeline2 = parent.command("pipeline").description("Create, validate, inspect, and safely dry-run ordered pipeline recipes");
7814
+ pipeline2.command("init").description("Write a canonical v1 pipeline recipe").option("-f, --file <path>", "Output file", DEFAULT_PIPELINE_FILE).option("--target <target>", "Default target: local or cloud", "local").action((options) => {
7815
+ if (!PIPELINE_TARGETS.includes(options.target)) throw new Error("--target must be local or cloud.");
7816
+ const path = resolve7(options.file);
7817
+ if (existsSync8(path)) throw new Error(`Pipeline file already exists: ${options.file}.`);
7818
+ const recipe = canonicalPipeline(options.target);
7819
+ writeFileSync6(path, `${JSON.stringify(recipe, null, 2)}
7820
+ `);
7821
+ if (isJsonMode()) return printJson({ created: true, path, pipeline: recipe });
7822
+ printSuccess(`Created ${options.file}`);
7823
+ });
7824
+ pipeline2.command("validate").description("Validate a pipeline without any execution or transfer").option("-f, --file <path>", "Pipeline file", DEFAULT_PIPELINE_FILE).action((options) => {
7825
+ const errors = validatePipeline(loadPipeline(options.file));
7826
+ const result2 = { valid: errors.length === 0, errors };
7827
+ if (isJsonMode()) return printJson(result2);
7828
+ if (errors.length) throw new Error(`Invalid pipeline:
7829
+ - ${errors.join("\n- ")}`);
7830
+ printSuccess("Pipeline is valid.");
7831
+ });
7832
+ pipeline2.command("plan").description("Resolve step targets and required artifact transfers").option("-f, --file <path>", "Pipeline file", DEFAULT_PIPELINE_FILE).option("--only <ids>", "Comma-separated step IDs to include").option("--skip <ids>", "Comma-separated step IDs to omit").action((options) => {
7833
+ outputPlan(createExecutionPlan(loadPipeline(options.file), { only: parseList(options.only), skip: parseList(options.skip) }));
7834
+ });
7835
+ pipeline2.command("run").description("Run an ordered local pipeline, or safely preview any pipeline").option("--dry-run", "Resolve and display only; never execute, transfer, or reserve credits").option("-f, --file <path>", "Pipeline file", DEFAULT_PIPELINE_FILE).option("--spec <path>", "Local behavior spec", "tunedtensor.json").option("--config <path>", "Local runtime config").option("--only <ids>", "Comma-separated step IDs to include").option("--skip <ids>", "Comma-separated step IDs to omit").action(async (options) => {
7836
+ const plan = createExecutionPlan(loadPipeline(options.file), { only: parseList(options.only), skip: parseList(options.skip) });
7837
+ if (options.dryRun) {
7838
+ if (isJsonMode()) return printJson({ dry_run: true, ...plan });
7839
+ console.log("Dry run only \u2014 no execution, artifact transfer, or credit reservation will occur.");
7840
+ return outputPlan(plan);
7841
+ }
7842
+ const remote = plan.steps.find((step) => step.target !== "local");
7843
+ if (remote) {
7844
+ throw new Error(`Step "${remote.id}" targets cloud execution. Hosted and mixed pipeline execution is not enabled by this CLI build; use --dry-run.`);
7845
+ }
7846
+ const input = await loadLocalRunInput(resolve7(options.spec));
7847
+ assertLocalRunInputReady(input.request);
7848
+ const config = await loadLocalRunnerConfig(options.config ? resolve7(options.config) : void 0);
7849
+ const localPipeline = {
7850
+ version: 1,
7851
+ ...plan.name ? { name: plan.name } : {},
7852
+ steps: plan.steps.map(({ transfers: _transfers, ...step }) => step)
7853
+ };
7854
+ const result2 = await runLocalPipeline({ request: input.request, config, pipeline: localPipeline });
7855
+ if (isJsonMode()) return printJson(result2);
7856
+ printSuccess(`Pipeline completed with status ${result2.status}.`);
7857
+ });
7858
+ }
7859
+
7642
7860
  // src/cli.ts
7643
7861
  async function createDefaultAgentClient(runtime, env, cloud) {
7644
7862
  const selection = getAgentSelection(env);
@@ -7681,7 +7899,16 @@ async function createDefaultAgentClient(runtime, env, cloud) {
7681
7899
  }
7682
7900
  function createLazyDefaultAgentClient(runtime, env, cloud) {
7683
7901
  let pending;
7684
- const client = () => pending ??= createDefaultAgentClient(runtime, env, cloud);
7902
+ const client = () => {
7903
+ if (!pending) {
7904
+ const attempt = createDefaultAgentClient(runtime, env, cloud);
7905
+ pending = attempt;
7906
+ attempt.catch(() => {
7907
+ if (pending === attempt) pending = void 0;
7908
+ });
7909
+ }
7910
+ return pending;
7911
+ };
7685
7912
  return {
7686
7913
  createThread: async () => await (await client()).createThread(),
7687
7914
  listThreads: async () => await (await client()).listThreads(),
@@ -7696,7 +7923,7 @@ async function runSelfCommand(args2, options = {}) {
7696
7923
  if (!entrypoint) {
7697
7924
  throw new Error("Cannot locate the tt CLI entrypoint.");
7698
7925
  }
7699
- return await new Promise((resolve7, reject) => {
7926
+ return await new Promise((resolve8, reject) => {
7700
7927
  const child = spawn4(process.execPath, [entrypoint, ...args2], {
7701
7928
  cwd: options.cwd,
7702
7929
  env: options.env ?? process.env,
@@ -7732,7 +7959,7 @@ async function runSelfCommand(args2, options = {}) {
7732
7959
  child.once("close", (exitCode, signal) => {
7733
7960
  cleanup();
7734
7961
  const signalNumber = signal ? osConstants2.signals[signal] : void 0;
7735
- resolve7({
7962
+ resolve8({
7736
7963
  exitCode: exitCode ?? (typeof signalNumber === "number" ? 128 + signalNumber : 1),
7737
7964
  signal
7738
7965
  });
@@ -7836,6 +8063,7 @@ function createProgram(version, runtime = {}) {
7836
8063
  registerInitCommand(program);
7837
8064
  registerEvalCommand(program);
7838
8065
  registerPushCommand(program);
8066
+ registerPipelineCommands(program);
7839
8067
  registerAgentCommands(program, {
7840
8068
  env,
7841
8069
  output: runtime.stdout ?? process.stdout,
@@ -7860,7 +8088,7 @@ function createProgram(version, runtime = {}) {
7860
8088
  `);
7861
8089
  return;
7862
8090
  }
7863
- output.write(`${chalk9.bold.cyan("Tuned Tensor status")}
8091
+ output.write(`${chalk9.bold.hex("#8B5CF6")("Tuned Tensor status")}
7864
8092
  `);
7865
8093
  output.write(`${formatShellStatus(context, target).join("\n")}
7866
8094
 
@@ -7993,7 +8221,7 @@ async function runCli(version, runtime = {}) {
7993
8221
  }
7994
8222
 
7995
8223
  // src/index.ts
7996
- runCli("0.9.0").catch((err) => {
8224
+ runCli("0.9.2").catch((err) => {
7997
8225
  reportError(err);
7998
8226
  process.exit(1);
7999
8227
  });