@tuned-tensor/cli 0.9.1 → 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/README.md +4 -1
- package/dist/index.js +213 -239
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -126,7 +126,8 @@ import {
|
|
|
126
126
|
getAgentDir,
|
|
127
127
|
ModelRuntime
|
|
128
128
|
} from "@earendil-works/pi-coding-agent";
|
|
129
|
-
import {
|
|
129
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
130
|
+
import { dirname, join } from "path";
|
|
130
131
|
function resolveAgentModel(runtime, selection) {
|
|
131
132
|
const resolved = resolveAgentModelDefinition(runtime, selection);
|
|
132
133
|
if (!runtime.hasConfiguredAuth(selection.provider)) {
|
|
@@ -160,12 +161,41 @@ function resolveAgentModelDefinition(runtime, selection) {
|
|
|
160
161
|
}
|
|
161
162
|
async function createPiModelRuntime() {
|
|
162
163
|
const agentDir = getAgentDir();
|
|
164
|
+
const modelsPath = join(agentDir, "models.json");
|
|
165
|
+
ensureOpenRouterAppHeaders(modelsPath);
|
|
163
166
|
return await ModelRuntime.create({
|
|
164
167
|
authPath: join(agentDir, "auth.json"),
|
|
165
|
-
modelsPath
|
|
168
|
+
modelsPath,
|
|
166
169
|
allowModelNetwork: false
|
|
167
170
|
});
|
|
168
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
|
+
}
|
|
169
199
|
|
|
170
200
|
// src/agent-tools.ts
|
|
171
201
|
import { randomUUID } from "crypto";
|
|
@@ -242,132 +272,74 @@ function canonicalizeSpecBaseModel(body) {
|
|
|
242
272
|
}
|
|
243
273
|
|
|
244
274
|
// src/pipeline.ts
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
function
|
|
264
|
-
if (step.uses === "evaluate") return
|
|
265
|
-
if (step.uses === "compare") return [
|
|
266
|
-
{ field: "before", value: step.with?.before, expected: "report" },
|
|
267
|
-
{ field: "after", value: step.with?.after, expected: "report" }
|
|
268
|
-
];
|
|
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];
|
|
269
296
|
return [];
|
|
270
297
|
}
|
|
271
|
-
function
|
|
272
|
-
return
|
|
298
|
+
function producerId(reference) {
|
|
299
|
+
return reference.from.slice(0, reference.from.lastIndexOf("."));
|
|
273
300
|
}
|
|
274
301
|
function validatePipeline(pipeline2) {
|
|
275
|
-
const
|
|
276
|
-
if (!
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
errors.push("Each pipeline step must be an object.");
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
const step = rawStep;
|
|
291
|
-
if (typeof step.id !== "string" || !/^[A-Za-z][A-Za-z0-9_-]*$/.test(step.id)) {
|
|
292
|
-
errors.push("Step id must start with a letter and contain only letters, numbers, _ or -.");
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
if (seen.has(step.id)) errors.push(`Duplicate step id: ${step.id}.`);
|
|
296
|
-
if (!PIPELINE_USES.includes(step.uses)) errors.push(`Step ${step.id} uses an unsupported component: ${String(step.uses)}.`);
|
|
297
|
-
if (step.uses === "train" && ++trainCount > 1) errors.push("Pipeline v1 supports at most one train step because local model artifacts are run-scoped.");
|
|
298
|
-
if (step.uses === "evaluate" && step.with?.evaluator !== void 0 && step.with.evaluator !== "behavior") {
|
|
299
|
-
errors.push(`Step ${step.id} evaluator must be behavior.`);
|
|
300
|
-
}
|
|
301
|
-
if (step.target !== void 0 && !PIPELINE_TARGETS.includes(step.target)) errors.push(`Step ${step.id} target must be local or cloud.`);
|
|
302
|
-
if (!resolvedTarget(step, typedPipeline)) errors.push(`Step ${step.id} needs a target or a pipeline default target.`);
|
|
303
|
-
for (const input of references(step)) {
|
|
304
|
-
if (step.uses === "evaluate" && input.value === "base") continue;
|
|
305
|
-
const source = ref(input.value);
|
|
306
|
-
if (!source) {
|
|
307
|
-
errors.push(`Step ${step.id} ${input.field} must be ${step.uses === "evaluate" ? "base or " : ""}a { from: "step.output" } reference.`);
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
const parsed = parseRef(source);
|
|
311
|
-
if (!parsed) {
|
|
312
|
-
errors.push(`Step ${step.id} has an invalid reference: ${source.from}.`);
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
const producer = seen.get(parsed.stepId);
|
|
316
|
-
if (!producer) {
|
|
317
|
-
const existsLater = pipeline2.steps.some((candidate) => isRecord(candidate) && candidate.id === parsed.stepId);
|
|
318
|
-
errors.push(`Step ${step.id} has a ${existsLater ? "forward" : "missing"} reference to ${parsed.stepId}.`);
|
|
319
|
-
} else if (!OUTPUTS[producer.uses]?.includes(parsed.output)) {
|
|
320
|
-
errors.push(`Step ${parsed.stepId} does not produce ${parsed.output} for step ${step.id}; it produces ${OUTPUTS[producer.uses]?.join(", ") ?? "no outputs"}.`);
|
|
321
|
-
} else if (parsed.output !== input.expected) {
|
|
322
|
-
errors.push(`Step ${step.id} ${input.field} requires a ${input.expected} reference, not ${source.from}.`);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
seen.set(step.id, step);
|
|
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)];
|
|
326
314
|
}
|
|
327
|
-
return errors;
|
|
328
315
|
}
|
|
329
316
|
function canonicalPipeline(target = "local") {
|
|
330
|
-
return
|
|
331
|
-
version: PIPELINE_VERSION,
|
|
332
|
-
name: `default-${target}`,
|
|
333
|
-
target,
|
|
334
|
-
steps: [
|
|
335
|
-
{ id: "baseline", uses: "evaluate", target, with: { model: "base", evaluator: "behavior" } },
|
|
336
|
-
{ id: "train", uses: "train", target },
|
|
337
|
-
{ id: "candidate", uses: "evaluate", target, with: { model: { from: "train.model" }, evaluator: "behavior" } },
|
|
338
|
-
{ id: "compare", uses: "compare", target, with: { before: { from: "baseline.report" }, after: { from: "candidate.report" } } }
|
|
339
|
-
]
|
|
340
|
-
};
|
|
317
|
+
return canonicalPortablePipeline(target);
|
|
341
318
|
}
|
|
342
319
|
function createExecutionPlan(pipeline2, selection = {}) {
|
|
343
320
|
const errors = validatePipeline(pipeline2);
|
|
344
321
|
if (errors.length) throw new Error(`Invalid pipeline:
|
|
345
322
|
- ${errors.join("\n- ")}`);
|
|
346
|
-
const
|
|
323
|
+
const normalized = parsePipeline(pipeline2);
|
|
324
|
+
const allIds = new Set(normalized.steps.map((step) => step.id));
|
|
347
325
|
for (const id of [...selection.only ?? [], ...selection.skip ?? []]) {
|
|
348
326
|
if (!allIds.has(id)) throw new Error(`Unknown pipeline step: ${id}.`);
|
|
349
327
|
}
|
|
350
328
|
const only = selection.only?.length ? new Set(selection.only) : void 0;
|
|
351
329
|
const skip = new Set(selection.skip ?? []);
|
|
352
|
-
const steps =
|
|
330
|
+
const steps = normalized.steps.filter((step) => (!only || only.has(step.id)) && !skip.has(step.id));
|
|
353
331
|
if (!steps.length) throw new Error("Selection leaves no pipeline steps to run.");
|
|
354
332
|
const retained = new Map(steps.map((step) => [step.id, step]));
|
|
355
333
|
const resolved = steps.map((step) => {
|
|
356
|
-
const target = resolvedTarget(step, pipeline2);
|
|
357
334
|
const transfers = [];
|
|
358
|
-
for (const
|
|
359
|
-
const
|
|
360
|
-
if (!
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const fromTarget = resolvedTarget(producer, pipeline2);
|
|
365
|
-
if (fromTarget !== target) transfers.push({ from: source.from, from_target: fromTarget, to_target: target });
|
|
366
|
-
}
|
|
367
|
-
const normalized = step.uses === "evaluate" ? { ...step, with: { ...step.with, evaluator: step.with?.evaluator ?? "behavior" } } : step;
|
|
368
|
-
return { ...normalized, target, 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 };
|
|
369
341
|
});
|
|
370
|
-
return { version:
|
|
342
|
+
return { version: 1, ...normalized.name ? { name: normalized.name } : {}, steps: resolved };
|
|
371
343
|
}
|
|
372
344
|
|
|
373
345
|
// src/agent-tools.ts
|
|
@@ -420,14 +392,14 @@ var BaseModel = Type.Union(
|
|
|
420
392
|
);
|
|
421
393
|
var PipelineDocument = Type.Object({
|
|
422
394
|
version: Type.Literal(1),
|
|
423
|
-
name: Type.Optional(Type.String({ minLength: 1, maxLength:
|
|
395
|
+
name: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
|
|
424
396
|
target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")])),
|
|
425
397
|
steps: Type.Array(Type.Object({
|
|
426
|
-
id: Type.String({ minLength: 1, maxLength:
|
|
398
|
+
id: Type.String({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_-]*$" }),
|
|
427
399
|
uses: Type.Union([Type.Literal("train"), Type.Literal("evaluate"), Type.Literal("compare")]),
|
|
428
400
|
target: Type.Optional(Type.Union([Type.Literal("local"), Type.Literal("cloud")])),
|
|
429
401
|
with: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
|
|
430
|
-
}, { additionalProperties: false }), { minItems: 1, maxItems:
|
|
402
|
+
}, { additionalProperties: false }), { minItems: 1, maxItems: 16 })
|
|
431
403
|
}, { additionalProperties: false });
|
|
432
404
|
var Example = Type.Object({
|
|
433
405
|
input: Type.String({ minLength: 1, maxLength: 1e5 }),
|
|
@@ -862,7 +834,7 @@ var DEFAULT_MAX_CLAIMS = 1e3;
|
|
|
862
834
|
function assertThreadId(id) {
|
|
863
835
|
if (!UUID.test(id)) throw new Error("Invalid local agent thread ID.");
|
|
864
836
|
}
|
|
865
|
-
function
|
|
837
|
+
function isRecord(value) {
|
|
866
838
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
867
839
|
}
|
|
868
840
|
function scrub(value, secrets) {
|
|
@@ -873,7 +845,7 @@ function scrub(value, secrets) {
|
|
|
873
845
|
);
|
|
874
846
|
}
|
|
875
847
|
if (Array.isArray(value)) return value.map((entry) => scrub(entry, secrets));
|
|
876
|
-
if (
|
|
848
|
+
if (isRecord(value)) {
|
|
877
849
|
return Object.fromEntries(
|
|
878
850
|
Object.entries(value).map(([key, entry]) => [key, scrub(entry, secrets)])
|
|
879
851
|
);
|
|
@@ -1022,7 +994,7 @@ var LocalAgentStore = class {
|
|
|
1022
994
|
throw new Error("Invalid local agent thread file.");
|
|
1023
995
|
}
|
|
1024
996
|
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
1025
|
-
if (!
|
|
997
|
+
if (!isRecord(parsed) || !isRecord(parsed.thread) || parsed.thread.id !== id || !Array.isArray(parsed.messages) || !Array.isArray(parsed.actions)) {
|
|
1026
998
|
throw new Error("Local agent thread file is malformed.");
|
|
1027
999
|
}
|
|
1028
1000
|
return parsed;
|
|
@@ -1046,16 +1018,16 @@ var LocalAgentStore = class {
|
|
|
1046
1018
|
};
|
|
1047
1019
|
|
|
1048
1020
|
// src/client.ts
|
|
1049
|
-
import { readFileSync as
|
|
1021
|
+
import { readFileSync as readFileSync3, statSync } from "fs";
|
|
1050
1022
|
import { basename } from "path";
|
|
1051
1023
|
|
|
1052
1024
|
// src/config.ts
|
|
1053
1025
|
import {
|
|
1054
1026
|
chmodSync,
|
|
1055
|
-
existsSync,
|
|
1056
|
-
mkdirSync,
|
|
1057
|
-
readFileSync,
|
|
1058
|
-
writeFileSync
|
|
1027
|
+
existsSync as existsSync2,
|
|
1028
|
+
mkdirSync as mkdirSync2,
|
|
1029
|
+
readFileSync as readFileSync2,
|
|
1030
|
+
writeFileSync as writeFileSync2
|
|
1059
1031
|
} from "fs";
|
|
1060
1032
|
import { homedir } from "os";
|
|
1061
1033
|
import { join as join3 } from "path";
|
|
@@ -1080,19 +1052,19 @@ function getConfigPath() {
|
|
|
1080
1052
|
}
|
|
1081
1053
|
function readConfig() {
|
|
1082
1054
|
const path = getConfigPath();
|
|
1083
|
-
if (!
|
|
1055
|
+
if (!existsSync2(path)) return {};
|
|
1084
1056
|
try {
|
|
1085
|
-
return JSON.parse(
|
|
1057
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
1086
1058
|
} catch {
|
|
1087
1059
|
return {};
|
|
1088
1060
|
}
|
|
1089
1061
|
}
|
|
1090
1062
|
function writeConfig(config) {
|
|
1091
1063
|
const dir = getConfigDir();
|
|
1092
|
-
if (!
|
|
1064
|
+
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
1093
1065
|
chmodSync(dir, 448);
|
|
1094
1066
|
const path = getConfigPath();
|
|
1095
|
-
|
|
1067
|
+
writeFileSync2(path, JSON.stringify(config, null, 2) + "\n", {
|
|
1096
1068
|
mode: 384
|
|
1097
1069
|
});
|
|
1098
1070
|
chmodSync(path, 384);
|
|
@@ -1103,7 +1075,7 @@ function updateConfig(partial) {
|
|
|
1103
1075
|
}
|
|
1104
1076
|
function clearConfig() {
|
|
1105
1077
|
const path = getConfigPath();
|
|
1106
|
-
if (
|
|
1078
|
+
if (existsSync2(path)) writeConfig({});
|
|
1107
1079
|
}
|
|
1108
1080
|
var DEFAULT_BASE_URL = "https://tunedtensor.com";
|
|
1109
1081
|
function getBaseUrl(opts) {
|
|
@@ -1133,10 +1105,10 @@ function getAgentSelection(env = process.env) {
|
|
|
1133
1105
|
|
|
1134
1106
|
// src/client.ts
|
|
1135
1107
|
var ApiError = class extends Error {
|
|
1136
|
-
constructor(status2,
|
|
1108
|
+
constructor(status2, code2, message) {
|
|
1137
1109
|
super(message);
|
|
1138
1110
|
this.status = status2;
|
|
1139
|
-
this.code =
|
|
1111
|
+
this.code = code2;
|
|
1140
1112
|
this.name = "ApiError";
|
|
1141
1113
|
}
|
|
1142
1114
|
};
|
|
@@ -1364,7 +1336,7 @@ function createCommandCompleter(getMode) {
|
|
|
1364
1336
|
// src/shell-context.ts
|
|
1365
1337
|
import { readFile as readFile2, readdir as readdir2, stat as stat2 } from "fs/promises";
|
|
1366
1338
|
import { homedir as homedir2 } from "os";
|
|
1367
|
-
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";
|
|
1368
1340
|
async function readJsonObject(path) {
|
|
1369
1341
|
try {
|
|
1370
1342
|
const parsed = JSON.parse(await readFile2(path, "utf8"));
|
|
@@ -1482,7 +1454,7 @@ async function discoverShellContext(options = {}) {
|
|
|
1482
1454
|
if (localConfigJson.invalid) {
|
|
1483
1455
|
warnings.push("local-runner.json could not be parsed.");
|
|
1484
1456
|
}
|
|
1485
|
-
const localConfigDirectory = hasAdjacentLocalConfig ?
|
|
1457
|
+
const localConfigDirectory = hasAdjacentLocalConfig ? dirname2(localConfigPath) : cwd;
|
|
1486
1458
|
const configuredArtifactRoot = stringField(localConfigJson.value, "artifactRoot");
|
|
1487
1459
|
const configuredStoreRoot = stringField(localConfigJson.value, "storeRoot");
|
|
1488
1460
|
const artifactRoot = configuredArtifactRoot ? expandPath(configuredArtifactRoot, localConfigDirectory, homeDirectory) : resolve(cwd, ".tt-local", "artifacts");
|
|
@@ -1912,9 +1884,9 @@ function renderShellBanner(snapshot) {
|
|
|
1912
1884
|
const heading = snapshot.version ? `${accent.bold("tt")} ${chalk.dim(`v${snapshot.version}`)}` : accent.bold("tt");
|
|
1913
1885
|
const lines = [
|
|
1914
1886
|
heading,
|
|
1915
|
-
chalk.dim(
|
|
1916
|
-
|
|
1917
|
-
)
|
|
1887
|
+
`${accent(snapshot.mode)}${chalk.dim(
|
|
1888
|
+
` \xB7 ${snapshot.context.projectName} \xB7 ${spec} \xB7 model ${activeModelLabel(snapshot)}`
|
|
1889
|
+
)}`,
|
|
1918
1890
|
chalk.dim("ctrl+c stop/clear \xB7 ctrl+d exit \xB7 /help commands \xB7 tab complete"),
|
|
1919
1891
|
"",
|
|
1920
1892
|
chalk.dim("Ask TT anything. Known commands run directly.")
|
|
@@ -2271,6 +2243,7 @@ function shouldStartInteractiveShell(options) {
|
|
|
2271
2243
|
import chalk2 from "chalk";
|
|
2272
2244
|
import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
|
|
2273
2245
|
var accent2 = chalk2.hex("#8B5CF6");
|
|
2246
|
+
var code = chalk2.hex("#A78BFA");
|
|
2274
2247
|
function sanitizeTerminalText(text2) {
|
|
2275
2248
|
return stripVTControlCharacters2(text2).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, "");
|
|
2276
2249
|
}
|
|
@@ -2308,7 +2281,7 @@ function renderInlineMarkdown(text2) {
|
|
|
2308
2281
|
if (text2[index] === "`") {
|
|
2309
2282
|
const close = closingDelimiter(text2, "`", index);
|
|
2310
2283
|
if (close > index + 1) {
|
|
2311
|
-
rendered +=
|
|
2284
|
+
rendered += code(text2.slice(index + 1, close));
|
|
2312
2285
|
index = close + 1;
|
|
2313
2286
|
continue;
|
|
2314
2287
|
}
|
|
@@ -2330,7 +2303,7 @@ function renderInlineMarkdown(text2) {
|
|
|
2330
2303
|
return rendered;
|
|
2331
2304
|
}
|
|
2332
2305
|
function renderMarkdownLine(line, inCodeBlock) {
|
|
2333
|
-
if (inCodeBlock) return
|
|
2306
|
+
if (inCodeBlock) return code(` ${line}`);
|
|
2334
2307
|
const heading = line.match(/^\s{0,3}#{1,6}\s+(.+)$/);
|
|
2335
2308
|
if (heading) return chalk2.bold(renderInlineMarkdown(heading[1]));
|
|
2336
2309
|
const bullet = line.match(/^(\s*)[-+*]\s+(.+)$/);
|
|
@@ -2388,7 +2361,7 @@ var StreamingTerminalMarkdown = class {
|
|
|
2388
2361
|
var accent3 = chalk3.hex("#8B5CF6");
|
|
2389
2362
|
var successMark2 = () => chalk3.green("\u2713");
|
|
2390
2363
|
var errorMark2 = () => chalk3.red("\u2717");
|
|
2391
|
-
function
|
|
2364
|
+
function isRecord2(value) {
|
|
2392
2365
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2393
2366
|
}
|
|
2394
2367
|
function stringValue(value) {
|
|
@@ -2429,7 +2402,7 @@ function formatThread(thread, activeId) {
|
|
|
2429
2402
|
return `${active} ${chalk3.dim(thread.id.slice(0, 8))} ${sanitizeTerminalText2(thread.title)} ${chalk3.dim(dateLabel)}`;
|
|
2430
2403
|
}
|
|
2431
2404
|
function actionFromPayload(payload) {
|
|
2432
|
-
const value =
|
|
2405
|
+
const value = isRecord2(payload.action) ? payload.action : isRecord2(payload.approval) ? payload.approval : payload;
|
|
2433
2406
|
const id = stringValue(value.id);
|
|
2434
2407
|
const title = stringValue(value.title);
|
|
2435
2408
|
if (!id || !title) return null;
|
|
@@ -2562,7 +2535,7 @@ ${chalk3.yellow.bold("Approval required")} ${chalk3.dim(action.id.slice(0, 8))}
|
|
|
2562
2535
|
if (event.type === "tool_call") {
|
|
2563
2536
|
this.flushResponse();
|
|
2564
2537
|
this.endOpenLine();
|
|
2565
|
-
const name = stringValue(payload.name) ?? stringValue(
|
|
2538
|
+
const name = stringValue(payload.name) ?? stringValue(isRecord2(payload.tool_call) ? payload.tool_call.name : null) ?? "tool";
|
|
2566
2539
|
this.options.io.write(chalk3.dim(` \u25CB ${name}
|
|
2567
2540
|
`));
|
|
2568
2541
|
return;
|
|
@@ -2817,7 +2790,7 @@ ${chalk3.yellow.bold("Approval required")} ${chalk3.dim(action.id.slice(0, 8))}
|
|
|
2817
2790
|
import { constants as osConstants } from "os";
|
|
2818
2791
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
2819
2792
|
import { spawn } from "child_process";
|
|
2820
|
-
import { existsSync as
|
|
2793
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2821
2794
|
import { fileURLToPath } from "url";
|
|
2822
2795
|
import {
|
|
2823
2796
|
readFile as readFile3,
|
|
@@ -2827,7 +2800,7 @@ import {
|
|
|
2827
2800
|
} from "fs/promises";
|
|
2828
2801
|
import {
|
|
2829
2802
|
basename as basename3,
|
|
2830
|
-
dirname as
|
|
2803
|
+
dirname as dirname3,
|
|
2831
2804
|
isAbsolute as isAbsolute3,
|
|
2832
2805
|
join as join5,
|
|
2833
2806
|
resolve as resolve3
|
|
@@ -2899,6 +2872,7 @@ function unknownProjectSpecKeys(raw) {
|
|
|
2899
2872
|
// src/output.ts
|
|
2900
2873
|
import chalk4 from "chalk";
|
|
2901
2874
|
import Table from "cli-table3";
|
|
2875
|
+
var labelStyle = chalk4.bold.hex("#A78BFA");
|
|
2902
2876
|
var jsonMode = false;
|
|
2903
2877
|
function setJsonMode(enabled) {
|
|
2904
2878
|
jsonMode = enabled;
|
|
@@ -2911,7 +2885,7 @@ function printJson(data3) {
|
|
|
2911
2885
|
}
|
|
2912
2886
|
function printTable(headers, rows2, meta) {
|
|
2913
2887
|
const table = new Table({
|
|
2914
|
-
head: headers.map((h) =>
|
|
2888
|
+
head: headers.map((h) => labelStyle(h)),
|
|
2915
2889
|
style: { head: [], border: [] }
|
|
2916
2890
|
});
|
|
2917
2891
|
for (const row of rows2) {
|
|
@@ -2932,7 +2906,7 @@ function printDetail(fields) {
|
|
|
2932
2906
|
const maxLabel = Math.max(...fields.map(([l]) => l.length));
|
|
2933
2907
|
for (const [label, value] of fields) {
|
|
2934
2908
|
const paddedLabel = label.padEnd(maxLabel);
|
|
2935
|
-
console.log(`${
|
|
2909
|
+
console.log(`${labelStyle(paddedLabel)} ${value ?? chalk4.dim("\u2014")}`);
|
|
2936
2910
|
}
|
|
2937
2911
|
}
|
|
2938
2912
|
function printSuccess(message) {
|
|
@@ -2968,9 +2942,9 @@ function formatDate(iso) {
|
|
|
2968
2942
|
function formatStatus(status2) {
|
|
2969
2943
|
const map = {
|
|
2970
2944
|
completed: chalk4.green,
|
|
2971
|
-
running: chalk4.
|
|
2972
|
-
training: chalk4.
|
|
2973
|
-
evaluating: chalk4.
|
|
2945
|
+
running: chalk4.hex("#A78BFA"),
|
|
2946
|
+
training: chalk4.hex("#A78BFA"),
|
|
2947
|
+
evaluating: chalk4.hex("#A78BFA"),
|
|
2974
2948
|
preparing: chalk4.yellow,
|
|
2975
2949
|
pending: chalk4.yellow,
|
|
2976
2950
|
uploading: chalk4.yellow,
|
|
@@ -2991,7 +2965,7 @@ function shortId(id) {
|
|
|
2991
2965
|
}
|
|
2992
2966
|
|
|
2993
2967
|
// src/local-output.ts
|
|
2994
|
-
function
|
|
2968
|
+
function isRecord3(value) {
|
|
2995
2969
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2996
2970
|
}
|
|
2997
2971
|
function text(value) {
|
|
@@ -3005,10 +2979,10 @@ function number(value) {
|
|
|
3005
2979
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3006
2980
|
}
|
|
3007
2981
|
function record3(value) {
|
|
3008
|
-
return
|
|
2982
|
+
return isRecord3(value) ? value : void 0;
|
|
3009
2983
|
}
|
|
3010
2984
|
function rows(value) {
|
|
3011
|
-
return Array.isArray(value) ? value.filter(
|
|
2985
|
+
return Array.isArray(value) ? value.filter(isRecord3) : [];
|
|
3012
2986
|
}
|
|
3013
2987
|
function displayId(value) {
|
|
3014
2988
|
const id = text(value);
|
|
@@ -3296,19 +3270,19 @@ function renderServePlan(value) {
|
|
|
3296
3270
|
function renderKnownJson(args2, value) {
|
|
3297
3271
|
const command = args2[0];
|
|
3298
3272
|
const subcommand = args2[1];
|
|
3299
|
-
if (command === "doctor" &&
|
|
3273
|
+
if (command === "doctor" && isRecord3(value)) {
|
|
3300
3274
|
renderDoctor(value);
|
|
3301
3275
|
return true;
|
|
3302
3276
|
}
|
|
3303
|
-
if (command === "init" &&
|
|
3277
|
+
if (command === "init" && isRecord3(value)) {
|
|
3304
3278
|
renderInit(value);
|
|
3305
3279
|
return true;
|
|
3306
3280
|
}
|
|
3307
|
-
if (command === "validate" &&
|
|
3281
|
+
if (command === "validate" && isRecord3(value)) {
|
|
3308
3282
|
renderValidate(value);
|
|
3309
3283
|
return true;
|
|
3310
3284
|
}
|
|
3311
|
-
if (command === "run" &&
|
|
3285
|
+
if (command === "run" && isRecord3(value)) {
|
|
3312
3286
|
renderRun(value);
|
|
3313
3287
|
return true;
|
|
3314
3288
|
}
|
|
@@ -3321,15 +3295,15 @@ function renderKnownJson(args2, value) {
|
|
|
3321
3295
|
renderRunEvents(value);
|
|
3322
3296
|
return true;
|
|
3323
3297
|
}
|
|
3324
|
-
if (subcommand === "get" &&
|
|
3298
|
+
if (subcommand === "get" && isRecord3(value)) {
|
|
3325
3299
|
renderRunRecord(value);
|
|
3326
3300
|
return true;
|
|
3327
3301
|
}
|
|
3328
|
-
if (subcommand === "report" &&
|
|
3302
|
+
if (subcommand === "report" && isRecord3(value)) {
|
|
3329
3303
|
renderRunReport(value);
|
|
3330
3304
|
return true;
|
|
3331
3305
|
}
|
|
3332
|
-
if (subcommand === "compare" &&
|
|
3306
|
+
if (subcommand === "compare" && isRecord3(value)) {
|
|
3333
3307
|
renderRunComparison(value);
|
|
3334
3308
|
return true;
|
|
3335
3309
|
}
|
|
@@ -3339,25 +3313,25 @@ function renderKnownJson(args2, value) {
|
|
|
3339
3313
|
renderModelsList(value);
|
|
3340
3314
|
return true;
|
|
3341
3315
|
}
|
|
3342
|
-
if ((subcommand === "get" || subcommand === "verify") &&
|
|
3316
|
+
if ((subcommand === "get" || subcommand === "verify") && isRecord3(value)) {
|
|
3343
3317
|
if (subcommand === "verify") printSuccess("Local model artifact is valid");
|
|
3344
3318
|
renderModelRecord(value);
|
|
3345
3319
|
return true;
|
|
3346
3320
|
}
|
|
3347
|
-
if ((subcommand === "prefetch" || subcommand === "verify-base") &&
|
|
3321
|
+
if ((subcommand === "prefetch" || subcommand === "verify-base") && isRecord3(value)) {
|
|
3348
3322
|
renderModelPrefetch(value);
|
|
3349
3323
|
return true;
|
|
3350
3324
|
}
|
|
3351
|
-
if (["active", "activate", "rollback"].includes(subcommand ?? "") &&
|
|
3325
|
+
if (["active", "activate", "rollback"].includes(subcommand ?? "") && isRecord3(value)) {
|
|
3352
3326
|
renderActiveModel(value);
|
|
3353
3327
|
return true;
|
|
3354
3328
|
}
|
|
3355
|
-
if (subcommand === "serve" &&
|
|
3329
|
+
if (subcommand === "serve" && isRecord3(value)) {
|
|
3356
3330
|
renderServePlan(value);
|
|
3357
3331
|
return true;
|
|
3358
3332
|
}
|
|
3359
3333
|
}
|
|
3360
|
-
if (command === "serve" &&
|
|
3334
|
+
if (command === "serve" && isRecord3(value)) {
|
|
3361
3335
|
renderServePlan(value);
|
|
3362
3336
|
return true;
|
|
3363
3337
|
}
|
|
@@ -3609,7 +3583,7 @@ async function projectSpecArguments(originalArgs, cwd) {
|
|
|
3609
3583
|
};
|
|
3610
3584
|
}
|
|
3611
3585
|
const temporaryPath = join5(
|
|
3612
|
-
|
|
3586
|
+
dirname3(sourcePath),
|
|
3613
3587
|
`.${basename3(sourcePath)}.tt-local-${process.pid}-${randomUUID4()}.json`
|
|
3614
3588
|
);
|
|
3615
3589
|
await writeFile2(
|
|
@@ -3631,7 +3605,7 @@ async function projectSpecArguments(originalArgs, cwd) {
|
|
|
3631
3605
|
}
|
|
3632
3606
|
function resolveLocalCliEntrypoint() {
|
|
3633
3607
|
const entrypoint = fileURLToPath(new URL("./local-runtime.js", import.meta.url));
|
|
3634
|
-
if (!
|
|
3608
|
+
if (!existsSync3(entrypoint)) {
|
|
3635
3609
|
throw new Error(
|
|
3636
3610
|
"The bundled local runtime is missing. Rebuild or reinstall @tuned-tensor/cli."
|
|
3637
3611
|
);
|
|
@@ -3741,10 +3715,10 @@ async function spawnLocalCli(args2) {
|
|
|
3741
3715
|
child.once("error", (error) => {
|
|
3742
3716
|
spawnError = error;
|
|
3743
3717
|
});
|
|
3744
|
-
child.once("close", (
|
|
3718
|
+
child.once("close", (code2, signal) => {
|
|
3745
3719
|
cleanup();
|
|
3746
3720
|
resolveChild({
|
|
3747
|
-
exitCode: spawnError ? 1 :
|
|
3721
|
+
exitCode: spawnError ? 1 : code2 ?? signalExitCode(signal),
|
|
3748
3722
|
signal,
|
|
3749
3723
|
stdout: stdout2,
|
|
3750
3724
|
stderr,
|
|
@@ -3864,7 +3838,7 @@ function registerAuthCommands(parent) {
|
|
|
3864
3838
|
console.log(
|
|
3865
3839
|
` To get your API key, go to ${chalk5.bold("Settings \u2192 API Keys")} in the Tuned Tensor dashboard:`
|
|
3866
3840
|
);
|
|
3867
|
-
console.log(` ${chalk5.
|
|
3841
|
+
console.log(` ${chalk5.hex("#A78BFA").underline(settingsUrl)}`);
|
|
3868
3842
|
console.log();
|
|
3869
3843
|
apiKey = await promptForApiKey();
|
|
3870
3844
|
}
|
|
@@ -3923,7 +3897,7 @@ function registerAuthCommands(parent) {
|
|
|
3923
3897
|
}
|
|
3924
3898
|
|
|
3925
3899
|
// src/commands/specs.ts
|
|
3926
|
-
import { readFileSync as
|
|
3900
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
3927
3901
|
|
|
3928
3902
|
// src/resolve.ts
|
|
3929
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;
|
|
@@ -4027,7 +4001,7 @@ var SpecBodyError = class extends Error {
|
|
|
4027
4001
|
function loadSpecBody(filePath, mode) {
|
|
4028
4002
|
let parsed;
|
|
4029
4003
|
try {
|
|
4030
|
-
parsed = JSON.parse(
|
|
4004
|
+
parsed = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
4031
4005
|
} catch (e) {
|
|
4032
4006
|
throw new SpecBodyError(
|
|
4033
4007
|
`Could not parse ${filePath}: ${e.message}`
|
|
@@ -4696,7 +4670,7 @@ Eval Results (${data3._evals.length}):`);
|
|
|
4696
4670
|
}
|
|
4697
4671
|
|
|
4698
4672
|
// src/commands/datasets.ts
|
|
4699
|
-
import { existsSync as
|
|
4673
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
4700
4674
|
var DOCUMENT_OCR_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
|
|
4701
4675
|
function formatBytes(bytes) {
|
|
4702
4676
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -4732,24 +4706,24 @@ var FORBIDDEN_CONTROL_CODEPOINTS = [
|
|
|
4732
4706
|
];
|
|
4733
4707
|
function findControlChar(value) {
|
|
4734
4708
|
for (let i = 0; i < value.length; i++) {
|
|
4735
|
-
const
|
|
4736
|
-
if (
|
|
4737
|
-
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code ===
|
|
4738
|
-
return { codepoint:
|
|
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" };
|
|
4739
4713
|
}
|
|
4740
|
-
if (
|
|
4741
|
-
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code ===
|
|
4742
|
-
return { codepoint:
|
|
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" };
|
|
4743
4717
|
}
|
|
4744
|
-
if (
|
|
4745
|
-
const named = FORBIDDEN_CONTROL_CODEPOINTS.find((entry) => entry.code ===
|
|
4746
|
-
return { codepoint:
|
|
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" };
|
|
4747
4721
|
}
|
|
4748
4722
|
}
|
|
4749
4723
|
return null;
|
|
4750
4724
|
}
|
|
4751
|
-
function formatCodepoint(
|
|
4752
|
-
return `U+${
|
|
4725
|
+
function formatCodepoint(code2) {
|
|
4726
|
+
return `U+${code2.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
4753
4727
|
}
|
|
4754
4728
|
function detectRowFormat(record4) {
|
|
4755
4729
|
const input = record4.input;
|
|
@@ -4826,7 +4800,7 @@ function parseDatasetFormat(value) {
|
|
|
4826
4800
|
throw new Error("--format must be one of: jsonl, document_ocr_jsonl");
|
|
4827
4801
|
}
|
|
4828
4802
|
function validateDatasetFile(file, requestedFormat) {
|
|
4829
|
-
const lines =
|
|
4803
|
+
const lines = readFileSync5(file, "utf8").split(/\r?\n/);
|
|
4830
4804
|
const errors = [];
|
|
4831
4805
|
let rowCount = 0;
|
|
4832
4806
|
let detectedFormat = null;
|
|
@@ -4952,13 +4926,13 @@ function registerDatasetsCommands(parent) {
|
|
|
4952
4926
|
});
|
|
4953
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) => {
|
|
4954
4928
|
const opts = parent.opts();
|
|
4955
|
-
if (!
|
|
4929
|
+
if (!existsSync4(file)) {
|
|
4956
4930
|
printError(`File not found: ${file}`);
|
|
4957
4931
|
process.exit(1);
|
|
4958
4932
|
}
|
|
4959
4933
|
const format = validateDatasetFile(file, parseDatasetFormat(cmdOpts.format));
|
|
4960
4934
|
const name = cmdOpts.name || file.split("/").pop().replace(/\.jsonl?$/, "");
|
|
4961
|
-
const fileBytes =
|
|
4935
|
+
const fileBytes = readFileSync5(file);
|
|
4962
4936
|
const uploadUrl = await post(
|
|
4963
4937
|
"/datasets/upload-url",
|
|
4964
4938
|
{
|
|
@@ -5003,7 +4977,7 @@ function registerDatasetsCommands(parent) {
|
|
|
5003
4977
|
}
|
|
5004
4978
|
|
|
5005
4979
|
// src/commands/label.ts
|
|
5006
|
-
import { existsSync as
|
|
4980
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
5007
4981
|
function formatCents2(cents) {
|
|
5008
4982
|
return `$${(cents / 100).toFixed(2)}`;
|
|
5009
4983
|
}
|
|
@@ -5047,7 +5021,7 @@ function validateUnlabeledFile(file, inputColumn) {
|
|
|
5047
5021
|
"CSV uploads need --input-column <name> to say which column holds the input text."
|
|
5048
5022
|
);
|
|
5049
5023
|
}
|
|
5050
|
-
const firstLine =
|
|
5024
|
+
const firstLine = readFileSync6(file, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
|
5051
5025
|
const columns = parseCsvHeader(firstLine);
|
|
5052
5026
|
if (!columns.includes(inputColumn)) {
|
|
5053
5027
|
throw new Error(
|
|
@@ -5059,7 +5033,7 @@ function validateUnlabeledFile(file, inputColumn) {
|
|
|
5059
5033
|
if (!lower.endsWith(".jsonl") && !lower.endsWith(".json")) {
|
|
5060
5034
|
throw new Error("Labeling source file must be .jsonl or .csv");
|
|
5061
5035
|
}
|
|
5062
|
-
const lines =
|
|
5036
|
+
const lines = readFileSync6(file, "utf8").split(/\r?\n/);
|
|
5063
5037
|
const errors = [];
|
|
5064
5038
|
let rowCount = 0;
|
|
5065
5039
|
for (const [index, rawLine] of lines.entries()) {
|
|
@@ -5175,14 +5149,14 @@ function registerLabelCommands(parent) {
|
|
|
5175
5149
|
const label = parent.command("label").description("Teacher-label real data into training datasets");
|
|
5176
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) => {
|
|
5177
5151
|
const opts = parent.opts();
|
|
5178
|
-
if (!
|
|
5152
|
+
if (!existsSync5(file)) {
|
|
5179
5153
|
printError(`File not found: ${file}`);
|
|
5180
5154
|
process.exit(1);
|
|
5181
5155
|
}
|
|
5182
5156
|
const { format } = validateUnlabeledFile(file, cmdOpts.inputColumn);
|
|
5183
5157
|
const specId = await resolveSpecId(cmdOpts.spec, opts);
|
|
5184
5158
|
const name = cmdOpts.name || file.split("/").pop().replace(/\.(jsonl|json|csv)$/, "");
|
|
5185
|
-
const fileBytes =
|
|
5159
|
+
const fileBytes = readFileSync6(file);
|
|
5186
5160
|
const contentType = format === "csv" ? "text/csv" : "application/jsonl";
|
|
5187
5161
|
const { data: uploadUrl } = await post(
|
|
5188
5162
|
"/labeling-jobs/upload-url",
|
|
@@ -5355,7 +5329,7 @@ function registerLabelCommands(parent) {
|
|
|
5355
5329
|
printError("Provide --output <text> or --file <path>.");
|
|
5356
5330
|
process.exit(1);
|
|
5357
5331
|
}
|
|
5358
|
-
const output = cmdOpts.output ??
|
|
5332
|
+
const output = cmdOpts.output ?? readFileSync6(cmdOpts.file, "utf8");
|
|
5359
5333
|
const jobId = await resolveLabelingJobId(id, opts);
|
|
5360
5334
|
const indexes = parseIndexList(cmdOpts.row);
|
|
5361
5335
|
const rowIds = await resolveRowIds(jobId, indexes, opts);
|
|
@@ -5404,23 +5378,23 @@ function registerLabelCommands(parent) {
|
|
|
5404
5378
|
import { spawn as spawn3, execFileSync } from "child_process";
|
|
5405
5379
|
import { createHash } from "crypto";
|
|
5406
5380
|
import {
|
|
5407
|
-
existsSync as
|
|
5408
|
-
mkdirSync as
|
|
5381
|
+
existsSync as existsSync7,
|
|
5382
|
+
mkdirSync as mkdirSync4,
|
|
5409
5383
|
statSync as statSync4,
|
|
5410
5384
|
createWriteStream,
|
|
5411
5385
|
unlinkSync,
|
|
5412
|
-
readFileSync as
|
|
5413
|
-
writeFileSync as
|
|
5386
|
+
readFileSync as readFileSync8,
|
|
5387
|
+
writeFileSync as writeFileSync4,
|
|
5414
5388
|
readdirSync,
|
|
5415
5389
|
rmSync
|
|
5416
5390
|
} from "fs";
|
|
5417
5391
|
import { homedir as homedir4 } from "os";
|
|
5418
|
-
import { dirname as
|
|
5392
|
+
import { dirname as dirname5, join as join6, resolve as resolve5, basename as basename4, normalize, isAbsolute as isAbsolute4 } from "path";
|
|
5419
5393
|
import { Readable, Transform } from "stream";
|
|
5420
5394
|
import { pipeline } from "stream/promises";
|
|
5421
5395
|
|
|
5422
5396
|
// src/commands/init.ts
|
|
5423
|
-
import { existsSync as
|
|
5397
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
5424
5398
|
import { resolve as resolve4 } from "path";
|
|
5425
5399
|
var DEFAULT_SPEC_FILE = "tunedtensor.json";
|
|
5426
5400
|
var SCAFFOLD = {
|
|
@@ -5441,7 +5415,7 @@ var SCAFFOLD = {
|
|
|
5441
5415
|
function registerInitCommand(parent) {
|
|
5442
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) => {
|
|
5443
5417
|
const filePath = resolve4(cmdOpts.file);
|
|
5444
|
-
if (
|
|
5418
|
+
if (existsSync6(filePath)) {
|
|
5445
5419
|
if (isJsonMode()) {
|
|
5446
5420
|
printJson({ created: false, path: filePath });
|
|
5447
5421
|
return;
|
|
@@ -5455,7 +5429,7 @@ function registerInitCommand(parent) {
|
|
|
5455
5429
|
};
|
|
5456
5430
|
if (cmdOpts.name) spec.name = cmdOpts.name;
|
|
5457
5431
|
if (cmdOpts.model) spec.base_model = canonicalizeBaseModel(cmdOpts.model);
|
|
5458
|
-
|
|
5432
|
+
writeFileSync3(filePath, JSON.stringify(spec, null, 2) + "\n");
|
|
5459
5433
|
if (isJsonMode()) {
|
|
5460
5434
|
printJson({ created: true, path: filePath, spec });
|
|
5461
5435
|
return;
|
|
@@ -5470,24 +5444,24 @@ function registerInitCommand(parent) {
|
|
|
5470
5444
|
}
|
|
5471
5445
|
function loadSpec(filePath) {
|
|
5472
5446
|
const resolved = resolve4(filePath || DEFAULT_SPEC_FILE);
|
|
5473
|
-
if (!
|
|
5447
|
+
if (!existsSync6(resolved)) {
|
|
5474
5448
|
printError(
|
|
5475
5449
|
`Spec file not found: ${filePath || DEFAULT_SPEC_FILE}
|
|
5476
5450
|
Run \`tt init\` to create one.`
|
|
5477
5451
|
);
|
|
5478
5452
|
process.exit(1);
|
|
5479
5453
|
}
|
|
5480
|
-
const raw = JSON.parse(
|
|
5454
|
+
const raw = JSON.parse(readFileSync7(resolved, "utf-8"));
|
|
5481
5455
|
return raw;
|
|
5482
5456
|
}
|
|
5483
5457
|
|
|
5484
5458
|
// src/serve-manager.ts
|
|
5485
5459
|
import { spawn as spawn2 } from "child_process";
|
|
5486
5460
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5487
|
-
import { appendFileSync, mkdirSync as
|
|
5461
|
+
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
5488
5462
|
import { createServer } from "http";
|
|
5489
5463
|
import { createServer as createNetServer } from "net";
|
|
5490
|
-
import { dirname as
|
|
5464
|
+
import { dirname as dirname4 } from "path";
|
|
5491
5465
|
var COMPLETION_ROUTES = /* @__PURE__ */ new Set(["/v1/chat/completions", "/chat/completions"]);
|
|
5492
5466
|
function parsePositiveInteger(value, fallback) {
|
|
5493
5467
|
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
@@ -5891,7 +5865,7 @@ var ManagedModelServer = class {
|
|
|
5891
5865
|
const line = `${JSON.stringify(record4)}
|
|
5892
5866
|
`;
|
|
5893
5867
|
if (this.options.logFile) {
|
|
5894
|
-
|
|
5868
|
+
mkdirSync3(dirname4(this.options.logFile), { recursive: true });
|
|
5895
5869
|
appendFileSync(this.options.logFile, line, "utf8");
|
|
5896
5870
|
return;
|
|
5897
5871
|
}
|
|
@@ -6438,7 +6412,7 @@ if __name__ == "__main__":
|
|
|
6438
6412
|
`;
|
|
6439
6413
|
function resolveOutputPath(output, filename) {
|
|
6440
6414
|
if (!output) return filename;
|
|
6441
|
-
if (
|
|
6415
|
+
if (existsSync7(output) && statSync4(output).isDirectory()) {
|
|
6442
6416
|
return join6(output, filename);
|
|
6443
6417
|
}
|
|
6444
6418
|
return output;
|
|
@@ -6515,7 +6489,7 @@ async function downloadUrlToFile(url, outputPath) {
|
|
|
6515
6489
|
if (!res.body) {
|
|
6516
6490
|
throw new Error("Download failed: response body was empty");
|
|
6517
6491
|
}
|
|
6518
|
-
|
|
6492
|
+
mkdirSync4(dirname5(outputPath), { recursive: true });
|
|
6519
6493
|
const file = createWriteStream(outputPath);
|
|
6520
6494
|
const contentLength = parseContentLength(res.headers.get("content-length"));
|
|
6521
6495
|
const progress = createDownloadProgress(
|
|
@@ -6559,7 +6533,7 @@ function runtimePythonPath(cacheDir) {
|
|
|
6559
6533
|
function resolveServePython(cacheDir, explicitPython) {
|
|
6560
6534
|
if (explicitPython) return explicitPython;
|
|
6561
6535
|
const managedPython = runtimePythonPath(cacheDir);
|
|
6562
|
-
return
|
|
6536
|
+
return existsSync7(managedPython) ? managedPython : "python3";
|
|
6563
6537
|
}
|
|
6564
6538
|
function commandExists(command) {
|
|
6565
6539
|
try {
|
|
@@ -6638,7 +6612,7 @@ function safeSegment(value) {
|
|
|
6638
6612
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "model";
|
|
6639
6613
|
}
|
|
6640
6614
|
function directoryHasFiles(path) {
|
|
6641
|
-
return
|
|
6615
|
+
return existsSync7(path) && statSync4(path).isDirectory() && readdirSync(path).length > 0;
|
|
6642
6616
|
}
|
|
6643
6617
|
function validateArchiveEntryPath(entry) {
|
|
6644
6618
|
const normalized = normalize(entry).replace(/^[\\/]+/, "");
|
|
@@ -6659,8 +6633,8 @@ function validateArchiveEntries(archivePath) {
|
|
|
6659
6633
|
function extractArchive(archivePath, targetDir, force) {
|
|
6660
6634
|
if (directoryHasFiles(targetDir) && !force) return targetDir;
|
|
6661
6635
|
validateArchiveEntries(archivePath);
|
|
6662
|
-
if (
|
|
6663
|
-
|
|
6636
|
+
if (existsSync7(targetDir)) rmSync(targetDir, { recursive: true, force: true });
|
|
6637
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
6664
6638
|
execFileSync("tar", ["-xzf", archivePath, "-C", targetDir], { stdio: "inherit" });
|
|
6665
6639
|
return targetDir;
|
|
6666
6640
|
}
|
|
@@ -6686,21 +6660,21 @@ function findSpecPath(explicitPath, modelPath) {
|
|
|
6686
6660
|
const candidates = explicitPath ? [explicitPath] : [join6(process.cwd(), DEFAULT_SPEC_FILE), join6(modelPath, DEFAULT_SPEC_FILE)];
|
|
6687
6661
|
for (const candidate of candidates) {
|
|
6688
6662
|
const resolved = resolve5(candidate);
|
|
6689
|
-
if (
|
|
6663
|
+
if (existsSync7(resolved) && statSync4(resolved).isFile()) return resolved;
|
|
6690
6664
|
}
|
|
6691
6665
|
return null;
|
|
6692
6666
|
}
|
|
6693
6667
|
function loadSystemPromptFromSpec(specPath) {
|
|
6694
|
-
const spec = JSON.parse(
|
|
6668
|
+
const spec = JSON.parse(readFileSync8(specPath, "utf8"));
|
|
6695
6669
|
return buildSystemPrompt(spec);
|
|
6696
6670
|
}
|
|
6697
6671
|
function loadJsonSchemaForServe(schemaPath) {
|
|
6698
6672
|
const resolved = resolve5(schemaPath);
|
|
6699
|
-
if (!
|
|
6673
|
+
if (!existsSync7(resolved) || !statSync4(resolved).isFile()) {
|
|
6700
6674
|
throw new Error(`JSON schema file not found: ${schemaPath}`);
|
|
6701
6675
|
}
|
|
6702
6676
|
try {
|
|
6703
|
-
const schema = JSON.parse(
|
|
6677
|
+
const schema = JSON.parse(readFileSync8(resolved, "utf8"));
|
|
6704
6678
|
return JSON.stringify(schema);
|
|
6705
6679
|
} catch (err) {
|
|
6706
6680
|
throw new Error(`JSON schema file is not valid JSON: ${schemaPath}`);
|
|
@@ -6708,13 +6682,13 @@ function loadJsonSchemaForServe(schemaPath) {
|
|
|
6708
6682
|
}
|
|
6709
6683
|
function writeReferenceServerScript(cacheDir) {
|
|
6710
6684
|
const scriptDir = join6(cacheDir, "_server");
|
|
6711
|
-
|
|
6685
|
+
mkdirSync4(scriptDir, { recursive: true });
|
|
6712
6686
|
const scriptPath = join6(scriptDir, "openai_reference_server.py");
|
|
6713
|
-
|
|
6687
|
+
writeFileSync4(scriptPath, REFERENCE_SERVER_SCRIPT, "utf8");
|
|
6714
6688
|
return scriptPath;
|
|
6715
6689
|
}
|
|
6716
6690
|
async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
6717
|
-
if (
|
|
6691
|
+
if (existsSync7(target)) {
|
|
6718
6692
|
const resolved = resolve5(target);
|
|
6719
6693
|
const stats = statSync4(resolved);
|
|
6720
6694
|
if (stats.isDirectory()) {
|
|
@@ -6740,7 +6714,7 @@ async function resolveServeTarget(target, opts, cacheDir, forceDownload) {
|
|
|
6740
6714
|
const modelCacheDir = join6(cacheDir, fullId);
|
|
6741
6715
|
const archivePath = join6(modelCacheDir, data3.filename);
|
|
6742
6716
|
const extractDir = join6(modelCacheDir, "model");
|
|
6743
|
-
if (!
|
|
6717
|
+
if (!existsSync7(archivePath) || forceDownload) {
|
|
6744
6718
|
await downloadUrlToFile(data3.url, archivePath);
|
|
6745
6719
|
}
|
|
6746
6720
|
extractArchive(archivePath, extractDir, forceDownload);
|
|
@@ -6844,7 +6818,7 @@ function ollamaSlug(name) {
|
|
|
6844
6818
|
}
|
|
6845
6819
|
function firstExisting(candidates) {
|
|
6846
6820
|
for (const candidate of candidates) {
|
|
6847
|
-
if (candidate &&
|
|
6821
|
+
if (candidate && existsSync7(candidate) && statSync4(candidate).isFile()) {
|
|
6848
6822
|
return resolve5(candidate);
|
|
6849
6823
|
}
|
|
6850
6824
|
}
|
|
@@ -6856,7 +6830,7 @@ function llamaCppDir(explicit) {
|
|
|
6856
6830
|
function resolveConvertScript(opts, required) {
|
|
6857
6831
|
if (opts.convertScript) {
|
|
6858
6832
|
const resolved = resolve5(opts.convertScript);
|
|
6859
|
-
if (required && !
|
|
6833
|
+
if (required && !existsSync7(resolved)) {
|
|
6860
6834
|
throw new Error(`Conversion script not found: ${opts.convertScript}`);
|
|
6861
6835
|
}
|
|
6862
6836
|
return resolved;
|
|
@@ -6875,7 +6849,7 @@ function resolveConvertScript(opts, required) {
|
|
|
6875
6849
|
function resolveQuantizeBin(opts, required) {
|
|
6876
6850
|
if (opts.quantizeBin) {
|
|
6877
6851
|
const resolved = resolve5(opts.quantizeBin);
|
|
6878
|
-
if (required && !
|
|
6852
|
+
if (required && !existsSync7(resolved)) {
|
|
6879
6853
|
throw new Error(`llama-quantize binary not found: ${opts.quantizeBin}`);
|
|
6880
6854
|
}
|
|
6881
6855
|
return resolved;
|
|
@@ -7010,7 +6984,7 @@ function registerModelsCommands(parent) {
|
|
|
7010
6984
|
opts
|
|
7011
6985
|
);
|
|
7012
6986
|
const outputPath = resolveOutputPath(cmdOpts.output, data3.filename);
|
|
7013
|
-
if (
|
|
6987
|
+
if (existsSync7(outputPath) && !cmdOpts.force) {
|
|
7014
6988
|
throw new Error(`Output file already exists: ${outputPath}. Use --force to overwrite.`);
|
|
7015
6989
|
}
|
|
7016
6990
|
const bytes = await downloadUrlToFile(data3.url, outputPath);
|
|
@@ -7035,7 +7009,7 @@ function registerModelsCommands(parent) {
|
|
|
7035
7009
|
const quantPlan = planQuant(String(cmdOpts.quant));
|
|
7036
7010
|
const printOnly = Boolean(cmdOpts.printCommand);
|
|
7037
7011
|
const cacheDir = resolve5(cmdOpts.cacheDir || defaultCacheDir());
|
|
7038
|
-
|
|
7012
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
7039
7013
|
const serveTarget = await resolveServeTarget(
|
|
7040
7014
|
target,
|
|
7041
7015
|
opts,
|
|
@@ -7119,10 +7093,10 @@ function registerModelsCommands(parent) {
|
|
|
7119
7093
|
ollama: ollamaInfo
|
|
7120
7094
|
};
|
|
7121
7095
|
if (printOnly) return printExportPlan(plan);
|
|
7122
|
-
if (
|
|
7096
|
+
if (existsSync7(finalPath) && !cmdOpts.force) {
|
|
7123
7097
|
throw new Error(`Output already exists: ${finalPath}. Use --force to overwrite.`);
|
|
7124
7098
|
}
|
|
7125
|
-
|
|
7099
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
7126
7100
|
const runStep = (command, args2) => execFileSync(command, args2, { stdio: "inherit" });
|
|
7127
7101
|
if (!isJsonMode()) printSuccess(`Converting ${serveTarget.modelName} \u2192 ${quantPlan.convertOuttype} GGUF`);
|
|
7128
7102
|
runStep(cmdOpts.python, [
|
|
@@ -7140,12 +7114,12 @@ function registerModelsCommands(parent) {
|
|
|
7140
7114
|
finalPath,
|
|
7141
7115
|
quantPlan.quantizeType
|
|
7142
7116
|
]);
|
|
7143
|
-
if (!cmdOpts.keepIntermediate && intermediatePath &&
|
|
7117
|
+
if (!cmdOpts.keepIntermediate && intermediatePath && existsSync7(intermediatePath)) {
|
|
7144
7118
|
rmSync(intermediatePath, { force: true });
|
|
7145
7119
|
}
|
|
7146
7120
|
}
|
|
7147
7121
|
if (ollamaInfo) {
|
|
7148
|
-
|
|
7122
|
+
writeFileSync4(modelfilePath, modelfileContent, "utf8");
|
|
7149
7123
|
if (!isJsonMode()) printSuccess(`Wrote Modelfile to ${modelfilePath}`);
|
|
7150
7124
|
if (ollamaInfo.create) {
|
|
7151
7125
|
if (!isJsonMode()) printSuccess(`Creating Ollama model ${ollamaName}`);
|
|
@@ -7193,11 +7167,11 @@ function registerModelsCommands(parent) {
|
|
|
7193
7167
|
]);
|
|
7194
7168
|
return;
|
|
7195
7169
|
}
|
|
7196
|
-
if (
|
|
7170
|
+
if (existsSync7(venvDir) && cmdOpts.force) {
|
|
7197
7171
|
rmSync(venvDir, { recursive: true, force: true });
|
|
7198
7172
|
}
|
|
7199
|
-
if (!
|
|
7200
|
-
|
|
7173
|
+
if (!existsSync7(venvPython)) {
|
|
7174
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
7201
7175
|
execFileSync(commands[0][0], commands[0].slice(1), { stdio: "inherit" });
|
|
7202
7176
|
}
|
|
7203
7177
|
execFileSync(commands[1][0], commands[1].slice(1), { stdio: "inherit" });
|
|
@@ -7217,7 +7191,7 @@ function registerModelsCommands(parent) {
|
|
|
7217
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) => {
|
|
7218
7192
|
const opts = parent.opts();
|
|
7219
7193
|
const cacheDir = resolve5(cmdOpts.cacheDir || defaultCacheDir());
|
|
7220
|
-
|
|
7194
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
7221
7195
|
const python = resolveServePython(cacheDir, cmdOpts.python);
|
|
7222
7196
|
if (!cmdOpts.printCommand) ensureServingRuntime(python, cacheDir);
|
|
7223
7197
|
const serveTarget = await resolveServeTarget(
|
|
@@ -7312,9 +7286,9 @@ function registerModelsCommands(parent) {
|
|
|
7312
7286
|
env: { ...process.env, ...env }
|
|
7313
7287
|
});
|
|
7314
7288
|
child.on("error", reject);
|
|
7315
|
-
child.on("exit", (
|
|
7316
|
-
if (
|
|
7317
|
-
reject(new Error(`Model server exited with ${signal ?? `code ${
|
|
7289
|
+
child.on("exit", (code2, signal) => {
|
|
7290
|
+
if (code2 === 0) return resolvePromise();
|
|
7291
|
+
reject(new Error(`Model server exited with ${signal ?? `code ${code2}`}`));
|
|
7318
7292
|
});
|
|
7319
7293
|
});
|
|
7320
7294
|
});
|
|
@@ -7471,7 +7445,7 @@ function registerTopupCommands(parent) {
|
|
|
7471
7445
|
}
|
|
7472
7446
|
const url = data3.checkout_url;
|
|
7473
7447
|
console.log(
|
|
7474
|
-
`${chalk7.bold("Checkout URL:")} ${chalk7.
|
|
7448
|
+
`${chalk7.bold("Checkout URL:")} ${chalk7.hex("#A78BFA")(url)}
|
|
7475
7449
|
` + chalk7.dim("Complete the payment to credit your account.")
|
|
7476
7450
|
);
|
|
7477
7451
|
if (options.open !== false) {
|
|
@@ -7679,12 +7653,12 @@ function printValidation(checks) {
|
|
|
7679
7653
|
}
|
|
7680
7654
|
|
|
7681
7655
|
// src/commands/push.ts
|
|
7682
|
-
import { readFileSync as
|
|
7656
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
7683
7657
|
import { resolve as resolve6 } from "path";
|
|
7684
7658
|
function persistRemoteId(filePath, id) {
|
|
7685
|
-
const raw = JSON.parse(
|
|
7659
|
+
const raw = JSON.parse(readFileSync9(filePath, "utf-8"));
|
|
7686
7660
|
raw.id = id;
|
|
7687
|
-
|
|
7661
|
+
writeFileSync5(filePath, JSON.stringify(raw, null, 2) + "\n");
|
|
7688
7662
|
}
|
|
7689
7663
|
function registerPushCommand(parent) {
|
|
7690
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) => {
|
|
@@ -7809,7 +7783,7 @@ function registerAgentCommands(parent, options) {
|
|
|
7809
7783
|
}
|
|
7810
7784
|
|
|
7811
7785
|
// src/commands/pipeline.ts
|
|
7812
|
-
import { existsSync as
|
|
7786
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
7813
7787
|
import { resolve as resolve7 } from "path";
|
|
7814
7788
|
var DEFAULT_PIPELINE_FILE = "tunedtensor.pipeline.json";
|
|
7815
7789
|
function parseList(value) {
|
|
@@ -7820,9 +7794,9 @@ function parseList(value) {
|
|
|
7820
7794
|
}
|
|
7821
7795
|
function loadPipeline(path) {
|
|
7822
7796
|
const resolved = resolve7(path);
|
|
7823
|
-
if (!
|
|
7797
|
+
if (!existsSync8(resolved)) throw new Error(`Pipeline file not found: ${path}. Run \`tt pipeline init\` to create one.`);
|
|
7824
7798
|
try {
|
|
7825
|
-
return JSON.parse(
|
|
7799
|
+
return JSON.parse(readFileSync10(resolved, "utf8"));
|
|
7826
7800
|
} catch (error) {
|
|
7827
7801
|
throw new Error(`Pipeline file must be JSON: ${error.message}`);
|
|
7828
7802
|
}
|
|
@@ -7840,9 +7814,9 @@ function registerPipelineCommands(parent) {
|
|
|
7840
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) => {
|
|
7841
7815
|
if (!PIPELINE_TARGETS.includes(options.target)) throw new Error("--target must be local or cloud.");
|
|
7842
7816
|
const path = resolve7(options.file);
|
|
7843
|
-
if (
|
|
7817
|
+
if (existsSync8(path)) throw new Error(`Pipeline file already exists: ${options.file}.`);
|
|
7844
7818
|
const recipe = canonicalPipeline(options.target);
|
|
7845
|
-
|
|
7819
|
+
writeFileSync6(path, `${JSON.stringify(recipe, null, 2)}
|
|
7846
7820
|
`);
|
|
7847
7821
|
if (isJsonMode()) return printJson({ created: true, path, pipeline: recipe });
|
|
7848
7822
|
printSuccess(`Created ${options.file}`);
|
|
@@ -8114,7 +8088,7 @@ function createProgram(version, runtime = {}) {
|
|
|
8114
8088
|
`);
|
|
8115
8089
|
return;
|
|
8116
8090
|
}
|
|
8117
|
-
output.write(`${chalk9.bold.
|
|
8091
|
+
output.write(`${chalk9.bold.hex("#8B5CF6")("Tuned Tensor status")}
|
|
8118
8092
|
`);
|
|
8119
8093
|
output.write(`${formatShellStatus(context, target).join("\n")}
|
|
8120
8094
|
|
|
@@ -8247,7 +8221,7 @@ async function runCli(version, runtime = {}) {
|
|
|
8247
8221
|
}
|
|
8248
8222
|
|
|
8249
8223
|
// src/index.ts
|
|
8250
|
-
runCli("0.9.
|
|
8224
|
+
runCli("0.9.2").catch((err) => {
|
|
8251
8225
|
reportError(err);
|
|
8252
8226
|
process.exit(1);
|
|
8253
8227
|
});
|