@tuned-tensor/cli 0.13.1-beta.5 → 0.13.1-beta.7
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 +24 -6
- package/dist/{chunk-AVMRHDFY.js → chunk-AKJ5WZ2S.js} +75 -52
- package/dist/chunk-AKJ5WZ2S.js.map +1 -0
- package/dist/index.js +142 -22
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +71 -6
- package/dist/local-runtime.js.map +1 -1
- package/docs/local-runtime/architecture.md +24 -6
- package/docs/local-runtime/foundation-long-runs.md +108 -0
- package/package.json +1 -1
- package/training/foundation/src/checkpoint.py +235 -0
- package/training/foundation/src/common.py +30 -2
- package/training/foundation/src/data.py +154 -6
- package/training/foundation/src/evaluate.py +43 -9
- package/training/foundation/src/pretrain.py +439 -27
- package/training/foundation/src/rl.py +11 -3
- package/training/foundation/src/train_tokenizer.py +38 -5
- package/dist/chunk-AVMRHDFY.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
assertLocalRunInputReady,
|
|
8
8
|
assessHardware,
|
|
9
9
|
buildFoundationPythonCommand,
|
|
10
|
+
buildSystemMessage,
|
|
10
11
|
defaultStoreRoot,
|
|
11
12
|
expandUserPath,
|
|
12
13
|
formatAgentHostBlock,
|
|
@@ -16,12 +17,13 @@ import {
|
|
|
16
17
|
hardenExistingLocalStore,
|
|
17
18
|
loadLocalRunInput,
|
|
18
19
|
loadLocalRunnerConfig,
|
|
20
|
+
localPathsOverlap,
|
|
19
21
|
readHardwareSnapshot,
|
|
20
22
|
runLocalPipeline,
|
|
21
23
|
runLoggedProcess,
|
|
22
24
|
warningsFromSnapshot,
|
|
23
25
|
withFoundationPythonEnvironment
|
|
24
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-AKJ5WZ2S.js";
|
|
25
27
|
|
|
26
28
|
// src/cli.ts
|
|
27
29
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -1067,6 +1069,7 @@ var TRAINING_SOURCE_FILES = {
|
|
|
1067
1069
|
foundation: {
|
|
1068
1070
|
tokenizer: "training/foundation/src/train_tokenizer.py",
|
|
1069
1071
|
pretrain: "training/foundation/src/pretrain.py",
|
|
1072
|
+
checkpoint: "training/foundation/src/checkpoint.py",
|
|
1070
1073
|
model: "training/foundation/src/model.py",
|
|
1071
1074
|
data: "training/foundation/src/data.py",
|
|
1072
1075
|
finetune: "training/foundation/src/finetune.py",
|
|
@@ -1522,6 +1525,7 @@ function createTunedTensorTools(api, options = {}) {
|
|
|
1522
1525
|
component: Type2.Union([
|
|
1523
1526
|
Type2.Literal("tokenizer"),
|
|
1524
1527
|
Type2.Literal("pretrain"),
|
|
1528
|
+
Type2.Literal("checkpoint"),
|
|
1525
1529
|
Type2.Literal("model"),
|
|
1526
1530
|
Type2.Literal("data"),
|
|
1527
1531
|
Type2.Literal("finetune"),
|
|
@@ -5134,11 +5138,22 @@ import { resolve as resolve5 } from "path";
|
|
|
5134
5138
|
// src/local-runtime/foundation-runner.ts
|
|
5135
5139
|
import { createHash as createHash3, randomUUID as randomUUID5 } from "crypto";
|
|
5136
5140
|
import { createReadStream } from "fs";
|
|
5137
|
-
import { chmod as chmod2, lstat as lstat3, mkdir as mkdir3, open as open2, readdir as readdir3, readFile as readFile4 } from "fs/promises";
|
|
5138
|
-
import { dirname as dirname4, join as join7, resolve as resolve4 } from "path";
|
|
5141
|
+
import { chmod as chmod2, lstat as lstat3, mkdir as mkdir3, open as open2, readdir as readdir3, readFile as readFile4, rename as rename2, rm as rm2 } from "fs/promises";
|
|
5142
|
+
import { basename as basename4, dirname as dirname4, join as join7, resolve as resolve4 } from "path";
|
|
5143
|
+
var INSTRUCTION_CORPUS_VERSION = 1;
|
|
5139
5144
|
function isRef(value) {
|
|
5140
5145
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && typeof value.from === "string";
|
|
5141
5146
|
}
|
|
5147
|
+
function resumeConfigMatches(previous, current, legacySystemPrompt) {
|
|
5148
|
+
if (JSON.stringify(previous) === JSON.stringify(current)) return true;
|
|
5149
|
+
if (!previous || typeof previous !== "object" || Array.isArray(previous)) return false;
|
|
5150
|
+
const legacyInstruction = legacySystemPrompt.trim();
|
|
5151
|
+
if (!legacyInstruction || current.system_prompt !== legacyInstruction) return false;
|
|
5152
|
+
const migrated = { ...previous };
|
|
5153
|
+
if (migrated.system_prompt !== legacySystemPrompt) return false;
|
|
5154
|
+
migrated.system_prompt = legacyInstruction;
|
|
5155
|
+
return JSON.stringify(migrated) === JSON.stringify(current);
|
|
5156
|
+
}
|
|
5142
5157
|
function parseRef(value) {
|
|
5143
5158
|
const index = value.from.lastIndexOf(".");
|
|
5144
5159
|
if (index <= 0) throw new Error(`Invalid artifact reference: ${value.from}`);
|
|
@@ -5204,13 +5219,20 @@ async function readRequiredJsonObject(path, description) {
|
|
|
5204
5219
|
}
|
|
5205
5220
|
return parsed;
|
|
5206
5221
|
}
|
|
5207
|
-
async function
|
|
5208
|
-
const
|
|
5222
|
+
async function writePrivateTextAtomic(path, content) {
|
|
5223
|
+
const temporary = join7(dirname4(path), `.${basename4(path)}.${randomUUID5()}.tmp`);
|
|
5224
|
+
const file = await open2(temporary, "wx", 384);
|
|
5225
|
+
let closed = false;
|
|
5209
5226
|
try {
|
|
5210
5227
|
await file.chmod(384);
|
|
5211
5228
|
await file.writeFile(content, "utf8");
|
|
5212
|
-
|
|
5229
|
+
await file.sync();
|
|
5213
5230
|
await file.close();
|
|
5231
|
+
closed = true;
|
|
5232
|
+
await rename2(temporary, path);
|
|
5233
|
+
} finally {
|
|
5234
|
+
if (!closed) await file.close().catch(() => void 0);
|
|
5235
|
+
await rm2(temporary, { force: true }).catch(() => void 0);
|
|
5214
5236
|
}
|
|
5215
5237
|
}
|
|
5216
5238
|
async function artifactFor(path) {
|
|
@@ -5247,6 +5269,11 @@ function assertFoundationPlanSupported(spec, plan) {
|
|
|
5247
5269
|
`Foundation runner does not implement ${unsupported.uses} (step ${unsupported.id}).`
|
|
5248
5270
|
);
|
|
5249
5271
|
}
|
|
5272
|
+
if (spec.foundation.corpus_path && spec.foundation.validation_path && localPathsOverlap(spec.foundation.corpus_path, spec.foundation.validation_path)) {
|
|
5273
|
+
throw new Error(
|
|
5274
|
+
"Foundation training and validation paths overlap; use disjoint corpora for held-out evaluation."
|
|
5275
|
+
);
|
|
5276
|
+
}
|
|
5250
5277
|
if (plan.steps.some((step) => step.uses === "rl")) {
|
|
5251
5278
|
const invalidReward = spec.examples.findIndex(
|
|
5252
5279
|
(example) => !/-?\d+(?:\.\d+)?/.test(example.output.replaceAll(",", ""))
|
|
@@ -5274,7 +5301,9 @@ async function defaultFoundationSpawn(args2) {
|
|
|
5274
5301
|
commandArgs: launched.commandArgs,
|
|
5275
5302
|
env: withFoundationPythonEnvironment(process.env),
|
|
5276
5303
|
logPath: args2.logPath,
|
|
5277
|
-
stage: args2.stepId
|
|
5304
|
+
stage: args2.stepId,
|
|
5305
|
+
shutdownGraceMs: 12e4,
|
|
5306
|
+
appendLog: true
|
|
5278
5307
|
});
|
|
5279
5308
|
if (result2.exitCode !== 0) {
|
|
5280
5309
|
throw new Error(
|
|
@@ -5288,15 +5317,35 @@ async function runFoundationPipeline(args2) {
|
|
|
5288
5317
|
const outputDir = resolve4(
|
|
5289
5318
|
args2.outputDir ?? join7(dirname4(resolve4(args2.specPath)), DEFAULT_FOUNDATION_RUNS_DIR, randomUUID5())
|
|
5290
5319
|
);
|
|
5291
|
-
|
|
5292
|
-
|
|
5320
|
+
let outputExists = false;
|
|
5321
|
+
try {
|
|
5322
|
+
const outputInfo = await lstat3(outputDir);
|
|
5323
|
+
if (!args2.resume) {
|
|
5324
|
+
throw new Error(`Foundation output directory already exists; pass --resume ${outputDir} to recover it.`);
|
|
5325
|
+
}
|
|
5326
|
+
if (outputInfo.isSymbolicLink()) {
|
|
5327
|
+
throw new Error(`Foundation resume directory must not be a symbolic link: ${outputDir}`);
|
|
5328
|
+
}
|
|
5329
|
+
if (!outputInfo.isDirectory()) {
|
|
5330
|
+
throw new Error(`Foundation resume path must be a directory: ${outputDir}`);
|
|
5331
|
+
}
|
|
5332
|
+
outputExists = true;
|
|
5333
|
+
} catch (error) {
|
|
5334
|
+
if (error.code !== "ENOENT") throw error;
|
|
5335
|
+
}
|
|
5336
|
+
if (!outputExists) {
|
|
5337
|
+
await mkdir3(outputDir, { recursive: true, mode: 448 });
|
|
5338
|
+
}
|
|
5339
|
+
await makePrivateTree(outputDir);
|
|
5293
5340
|
const spawnStep = args2.spawnStep ?? defaultFoundationSpawn;
|
|
5294
5341
|
const produced = /* @__PURE__ */ new Map();
|
|
5295
5342
|
const steps = [];
|
|
5296
5343
|
const examples = args2.spec.examples.map((example) => ({ input: example.input, output: example.output }));
|
|
5344
|
+
const systemInstruction = buildSystemMessage(args2.spec);
|
|
5297
5345
|
const hp = args2.spec.foundation;
|
|
5298
5346
|
let tokenizerDir;
|
|
5299
5347
|
let modelDir;
|
|
5348
|
+
let upstreamExecuted = false;
|
|
5300
5349
|
const resolveKind = (stepId, kind) => {
|
|
5301
5350
|
const path = produced.get(stepId)?.[kind];
|
|
5302
5351
|
if (!path) throw new Error(`Step ${stepId} did not produce ${kind}.`);
|
|
@@ -5316,6 +5365,8 @@ async function runFoundationPipeline(args2) {
|
|
|
5316
5365
|
await chmod2(output, 448);
|
|
5317
5366
|
const configPath2 = join7(stepDir, "config.json");
|
|
5318
5367
|
const logPath = join7(stepDir, "step.log");
|
|
5368
|
+
const metricsPath = join7(output, "metrics.json");
|
|
5369
|
+
const completionPath = join7(stepDir, "completion.json");
|
|
5319
5370
|
const fields = stepConfig(step);
|
|
5320
5371
|
let entrypoint;
|
|
5321
5372
|
let config;
|
|
@@ -5324,8 +5375,10 @@ async function runFoundationPipeline(args2) {
|
|
|
5324
5375
|
config = {
|
|
5325
5376
|
output_dir: output,
|
|
5326
5377
|
vocab_size: fields.vocabSize ?? hp.vocab_size,
|
|
5327
|
-
max_chars: fields.maxChars ?? hp.max_chars,
|
|
5328
|
-
|
|
5378
|
+
max_chars: hp.tokenizer_max_chars ?? fields.maxChars ?? hp.max_chars,
|
|
5379
|
+
corpus_path: hp.corpus_path,
|
|
5380
|
+
...hp.corpus_path ? { instruction_corpus_version: INSTRUCTION_CORPUS_VERSION } : {},
|
|
5381
|
+
system_prompt: systemInstruction,
|
|
5329
5382
|
examples
|
|
5330
5383
|
};
|
|
5331
5384
|
} else if (step.uses === "pretrain") {
|
|
@@ -5334,13 +5387,30 @@ async function runFoundationPipeline(args2) {
|
|
|
5334
5387
|
config = {
|
|
5335
5388
|
tokenizer_dir: tokenizerDir,
|
|
5336
5389
|
output_dir: output,
|
|
5390
|
+
work_dir: join7(stepDir, "recovery"),
|
|
5337
5391
|
depth: fields.depth ?? hp.depth,
|
|
5338
5392
|
steps: fields.steps ?? hp.pretrain_steps,
|
|
5339
5393
|
batch_size: fields.batchSize ?? hp.batch_size,
|
|
5340
5394
|
sequence_length: fields.sequenceLength ?? hp.sequence_length,
|
|
5341
5395
|
nproc_per_node: fields.nprocPerNode ?? hp.nproc_per_node,
|
|
5342
5396
|
max_chars: hp.max_chars,
|
|
5343
|
-
|
|
5397
|
+
corpus_path: hp.corpus_path,
|
|
5398
|
+
...hp.corpus_path ? { instruction_corpus_version: INSTRUCTION_CORPUS_VERSION } : {},
|
|
5399
|
+
seed: hp.seed,
|
|
5400
|
+
learning_rate: hp.learning_rate,
|
|
5401
|
+
weight_decay: hp.weight_decay,
|
|
5402
|
+
warmup_steps: hp.warmup_steps,
|
|
5403
|
+
min_lr_ratio: hp.min_lr_ratio,
|
|
5404
|
+
gradient_accumulation_steps: hp.gradient_accumulation_steps,
|
|
5405
|
+
gradient_clip: hp.gradient_clip,
|
|
5406
|
+
bf16: hp.bf16,
|
|
5407
|
+
checkpoint_interval_steps: hp.checkpoint_interval_steps,
|
|
5408
|
+
checkpoint_interval_seconds: hp.checkpoint_interval_seconds,
|
|
5409
|
+
keep_checkpoints: hp.keep_checkpoints,
|
|
5410
|
+
log_interval_steps: hp.log_interval_steps,
|
|
5411
|
+
checkpoint_backup_dir: hp.checkpoint_backup_dir,
|
|
5412
|
+
resume: true,
|
|
5413
|
+
system_prompt: systemInstruction,
|
|
5344
5414
|
examples
|
|
5345
5415
|
};
|
|
5346
5416
|
} else if (step.uses === "finetune") {
|
|
@@ -5353,7 +5423,7 @@ async function runFoundationPipeline(args2) {
|
|
|
5353
5423
|
steps: fields.steps ?? hp.finetune_steps,
|
|
5354
5424
|
batch_size: fields.batchSize ?? hp.batch_size,
|
|
5355
5425
|
sequence_length: hp.sequence_length,
|
|
5356
|
-
system_prompt:
|
|
5426
|
+
system_prompt: systemInstruction,
|
|
5357
5427
|
examples
|
|
5358
5428
|
};
|
|
5359
5429
|
} else if (step.uses === "rl") {
|
|
@@ -5364,7 +5434,7 @@ async function runFoundationPipeline(args2) {
|
|
|
5364
5434
|
tokenizer_dir: tokenizerDir,
|
|
5365
5435
|
output_dir: output,
|
|
5366
5436
|
steps: fields.steps ?? hp.rl_steps,
|
|
5367
|
-
system_prompt:
|
|
5437
|
+
system_prompt: systemInstruction,
|
|
5368
5438
|
examples
|
|
5369
5439
|
};
|
|
5370
5440
|
} else if (step.uses === "evaluate") {
|
|
@@ -5377,7 +5447,8 @@ async function runFoundationPipeline(args2) {
|
|
|
5377
5447
|
output_dir: output,
|
|
5378
5448
|
sequence_length: hp.sequence_length,
|
|
5379
5449
|
max_chars: hp.max_chars,
|
|
5380
|
-
|
|
5450
|
+
validation_path: hp.validation_path,
|
|
5451
|
+
system_prompt: systemInstruction,
|
|
5381
5452
|
examples
|
|
5382
5453
|
};
|
|
5383
5454
|
} else {
|
|
@@ -5386,12 +5457,33 @@ async function runFoundationPipeline(args2) {
|
|
|
5386
5457
|
if ((step.uses === "finetune" || step.uses === "rl" || step.uses === "evaluate") && !tokenizerDir) {
|
|
5387
5458
|
throw new Error(`Step ${step.id} needs a tokenizer from an earlier tokenize step.`);
|
|
5388
5459
|
}
|
|
5389
|
-
|
|
5460
|
+
let completedStep = false;
|
|
5461
|
+
if (args2.resume) {
|
|
5462
|
+
try {
|
|
5463
|
+
const previousConfig = JSON.parse(await readFile4(configPath2, "utf8"));
|
|
5464
|
+
if (!resumeConfigMatches(previousConfig, config, args2.spec.system_prompt)) {
|
|
5465
|
+
throw new Error(
|
|
5466
|
+
`Foundation step "${step.id}" configuration changed; resume requires the original spec and pipeline.`
|
|
5467
|
+
);
|
|
5468
|
+
}
|
|
5469
|
+
if (!upstreamExecuted) {
|
|
5470
|
+
await lstat3(metricsPath);
|
|
5471
|
+
await lstat3(completionPath);
|
|
5472
|
+
completedStep = true;
|
|
5473
|
+
}
|
|
5474
|
+
} catch (error) {
|
|
5475
|
+
if (error.code !== "ENOENT") throw error;
|
|
5476
|
+
}
|
|
5477
|
+
}
|
|
5478
|
+
if (!completedStep) {
|
|
5479
|
+
await writePrivateTextAtomic(configPath2, `${JSON.stringify(config, null, 2)}
|
|
5390
5480
|
`);
|
|
5391
|
-
|
|
5481
|
+
await spawnStep({ entrypoint, configPath: configPath2, logPath, stepId: step.id });
|
|
5482
|
+
upstreamExecuted = true;
|
|
5483
|
+
}
|
|
5392
5484
|
await makePrivateTree(stepDir);
|
|
5393
5485
|
const metrics = await readRequiredJsonObject(
|
|
5394
|
-
|
|
5486
|
+
metricsPath,
|
|
5395
5487
|
`Foundation step "${step.id}" metrics`
|
|
5396
5488
|
);
|
|
5397
5489
|
if (metrics.ok !== true) {
|
|
@@ -5434,6 +5526,26 @@ async function runFoundationPipeline(args2) {
|
|
|
5434
5526
|
record4.report = reportPath2;
|
|
5435
5527
|
artifacts.report = await artifactFor(reportPath2);
|
|
5436
5528
|
}
|
|
5529
|
+
const completion = {
|
|
5530
|
+
version: 1,
|
|
5531
|
+
config_sha256: await hashPath(configPath2),
|
|
5532
|
+
metrics_sha256: await hashPath(metricsPath),
|
|
5533
|
+
artifacts
|
|
5534
|
+
};
|
|
5535
|
+
if (completedStep) {
|
|
5536
|
+
const previousCompletion = await readRequiredJsonObject(
|
|
5537
|
+
completionPath,
|
|
5538
|
+
`Foundation step "${step.id}" completion manifest`
|
|
5539
|
+
);
|
|
5540
|
+
if (JSON.stringify(previousCompletion) !== JSON.stringify(completion)) {
|
|
5541
|
+
throw new Error(
|
|
5542
|
+
`Foundation step "${step.id}" integrity changed after completion; use a new run directory.`
|
|
5543
|
+
);
|
|
5544
|
+
}
|
|
5545
|
+
} else {
|
|
5546
|
+
await writePrivateTextAtomic(completionPath, `${JSON.stringify(completion, null, 2)}
|
|
5547
|
+
`);
|
|
5548
|
+
}
|
|
5437
5549
|
produced.set(step.id, record4);
|
|
5438
5550
|
steps.push({ id: step.id, uses: step.uses, metrics, artifacts });
|
|
5439
5551
|
}
|
|
@@ -5444,7 +5556,7 @@ async function runFoundationPipeline(args2) {
|
|
|
5444
5556
|
steps
|
|
5445
5557
|
};
|
|
5446
5558
|
const reportPath = join7(outputDir, "report.json");
|
|
5447
|
-
await
|
|
5559
|
+
await writePrivateTextAtomic(reportPath, `${JSON.stringify(report, null, 2)}
|
|
5448
5560
|
`);
|
|
5449
5561
|
return {
|
|
5450
5562
|
status: "succeeded",
|
|
@@ -5592,7 +5704,10 @@ function registerPipelineCommands(parent) {
|
|
|
5592
5704
|
const plan = createExecutionPlan(document, { only: parseList(options.only), skip: parseList(options.skip) });
|
|
5593
5705
|
outputPlan(plan, await hostWarningsForPipeline(document, options.spec));
|
|
5594
5706
|
});
|
|
5595
|
-
pipeline.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", DEFAULT_SPEC_FILE).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) => {
|
|
5707
|
+
pipeline.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", DEFAULT_SPEC_FILE).option("--config <path>", "Local runtime config").option("--output <path>", "Foundation run directory (must not already exist)").option("--resume <path>", "Resume a foundation run directory").option("--only <ids>", "Comma-separated step IDs to include").option("--skip <ids>", "Comma-separated step IDs to omit").action(async (options) => {
|
|
5708
|
+
if (options.output && options.resume) {
|
|
5709
|
+
throw new Error("--output and --resume are mutually exclusive.");
|
|
5710
|
+
}
|
|
5596
5711
|
const document = await resolvePipelineDocument(options);
|
|
5597
5712
|
const plan = createExecutionPlan(document, { only: parseList(options.only), skip: parseList(options.skip) });
|
|
5598
5713
|
const hostWarnings = await hostWarningsForPipeline(document, options.spec);
|
|
@@ -5621,12 +5736,17 @@ function registerPipelineCommands(parent) {
|
|
|
5621
5736
|
const result3 = await runFoundationPipeline({
|
|
5622
5737
|
spec: input.spec,
|
|
5623
5738
|
plan,
|
|
5624
|
-
specPath: resolve5(options.spec)
|
|
5739
|
+
specPath: resolve5(options.spec),
|
|
5740
|
+
...options.output || options.resume ? { outputDir: resolve5(options.resume ?? options.output) } : {},
|
|
5741
|
+
resume: Boolean(options.resume)
|
|
5625
5742
|
});
|
|
5626
5743
|
if (isJsonMode()) return printJson(result3);
|
|
5627
5744
|
printSuccess(`Foundation pipeline completed. Report: ${result3.report_path}`);
|
|
5628
5745
|
return;
|
|
5629
5746
|
}
|
|
5747
|
+
if (options.output || options.resume) {
|
|
5748
|
+
throw new Error("--output and --resume are only valid for foundation pipelines.");
|
|
5749
|
+
}
|
|
5630
5750
|
assertLocalRunInputReady(input.request);
|
|
5631
5751
|
const config = await loadLocalRunnerConfig(options.config ? resolve5(options.config) : void 0);
|
|
5632
5752
|
const localPipeline = {
|
|
@@ -6036,7 +6156,7 @@ async function runCli(version, runtime = {}) {
|
|
|
6036
6156
|
}
|
|
6037
6157
|
|
|
6038
6158
|
// src/index.ts
|
|
6039
|
-
runCli("0.13.1-beta.
|
|
6159
|
+
runCli("0.13.1-beta.7").catch((err) => {
|
|
6040
6160
|
reportError(err);
|
|
6041
6161
|
process.exit(1);
|
|
6042
6162
|
});
|