@valbuild/cli 0.97.7 → 0.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/dist/valbuild-cli-cli.cjs.dev.js +73 -172
- package/cli/dist/valbuild-cli-cli.cjs.prod.js +73 -172
- package/cli/dist/valbuild-cli-cli.esm.js +72 -169
- package/package.json +3 -2
- package/src/cli.ts +11 -5
- package/src/connect.ts +2 -4
- package/src/debug/context.ts +2 -4
- package/src/listUnusedFiles.ts +2 -4
- package/src/login.ts +29 -94
- package/src/lsp.ts +19 -0
- package/src/utils/evalValConfigFile.ts +6 -100
- package/src/validate.ts +2 -4
|
@@ -4,16 +4,13 @@ var meow = require('meow');
|
|
|
4
4
|
var chalk = require('chalk');
|
|
5
5
|
var path = require('path');
|
|
6
6
|
var pc = require('picocolors');
|
|
7
|
-
var fs = require('fs/promises');
|
|
7
|
+
var fs$1 = require('fs/promises');
|
|
8
8
|
var fastGlob = require('fast-glob');
|
|
9
9
|
var core = require('@valbuild/core');
|
|
10
10
|
var server = require('@valbuild/server');
|
|
11
|
-
var vm = require('node:vm');
|
|
12
|
-
var ts = require('typescript');
|
|
13
|
-
var z = require('zod');
|
|
14
|
-
var node_module = require('node:module');
|
|
15
11
|
var internal = require('@valbuild/shared/internal');
|
|
16
|
-
var
|
|
12
|
+
var ts = require('typescript');
|
|
13
|
+
var fs = require('fs');
|
|
17
14
|
var JSZip = require('jszip');
|
|
18
15
|
var readline = require('readline');
|
|
19
16
|
|
|
@@ -41,11 +38,9 @@ var meow__default = /*#__PURE__*/_interopDefault(meow);
|
|
|
41
38
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
42
39
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
43
40
|
var pc__default = /*#__PURE__*/_interopDefault(pc);
|
|
44
|
-
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
45
|
-
var vm__default = /*#__PURE__*/_interopDefault(vm);
|
|
46
|
-
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
|
47
|
-
var z__default = /*#__PURE__*/_interopDefault(z);
|
|
48
41
|
var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
|
|
42
|
+
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
|
43
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
49
44
|
var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
|
|
50
45
|
var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
51
46
|
|
|
@@ -64,76 +59,6 @@ function info(message, opts = {}) {
|
|
|
64
59
|
console.log(chalk__default["default"].blue("️ℹ️ : ") + message);
|
|
65
60
|
}
|
|
66
61
|
|
|
67
|
-
const ValConfigSchema = z__default["default"].object({
|
|
68
|
-
project: z__default["default"].string().optional(),
|
|
69
|
-
root: z__default["default"].string().optional(),
|
|
70
|
-
files: z__default["default"].object({
|
|
71
|
-
directory: z__default["default"].string().refine(val => (val === "/public" || val.startsWith("/public/") && !val.endsWith("/")) &&
|
|
72
|
-
// Reject path traversal so the directory cannot escape /public
|
|
73
|
-
!val.split("/").some(segment => segment === "." || segment === ".."), {
|
|
74
|
-
message: "files.directory must start with '/public', must not end with '/' and must not contain '.' or '..' segments"
|
|
75
|
-
})
|
|
76
|
-
}).optional(),
|
|
77
|
-
gitCommit: z__default["default"].string().optional(),
|
|
78
|
-
gitBranch: z__default["default"].string().optional(),
|
|
79
|
-
defaultTheme: z__default["default"].union([z__default["default"].literal("light"), z__default["default"].literal("dark")]).optional(),
|
|
80
|
-
ai: z__default["default"].object({
|
|
81
|
-
commitMessages: z__default["default"].object({
|
|
82
|
-
disabled: z__default["default"].boolean().optional()
|
|
83
|
-
}).optional()
|
|
84
|
-
}).optional()
|
|
85
|
-
});
|
|
86
|
-
async function evalValConfigFile(projectRoot, configFileName) {
|
|
87
|
-
const valConfigPath = path__default["default"].join(projectRoot, configFileName);
|
|
88
|
-
let code = null;
|
|
89
|
-
try {
|
|
90
|
-
code = await fs__default["default"].readFile(valConfigPath, "utf-8");
|
|
91
|
-
} catch {
|
|
92
|
-
//
|
|
93
|
-
}
|
|
94
|
-
if (!code) {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
const transpiled = ts__default["default"].transpileModule(code, {
|
|
98
|
-
compilerOptions: {
|
|
99
|
-
target: ts__default["default"].ScriptTarget.ES2020,
|
|
100
|
-
module: ts__default["default"].ModuleKind.CommonJS,
|
|
101
|
-
esModuleInterop: true
|
|
102
|
-
},
|
|
103
|
-
fileName: valConfigPath
|
|
104
|
-
});
|
|
105
|
-
const projectRootRequire = node_module.createRequire(valConfigPath);
|
|
106
|
-
const exportsObj = {};
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
|
-
const sandbox = {
|
|
109
|
-
exports: exportsObj,
|
|
110
|
-
module: {
|
|
111
|
-
exports: exportsObj
|
|
112
|
-
},
|
|
113
|
-
require: projectRootRequire,
|
|
114
|
-
// NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
|
|
115
|
-
__filename: valConfigPath,
|
|
116
|
-
__dirname: projectRoot,
|
|
117
|
-
console,
|
|
118
|
-
process
|
|
119
|
-
};
|
|
120
|
-
sandbox.global = sandbox;
|
|
121
|
-
const context = vm__default["default"].createContext(sandbox);
|
|
122
|
-
const script = new vm__default["default"].Script(transpiled.outputText, {
|
|
123
|
-
filename: valConfigPath
|
|
124
|
-
});
|
|
125
|
-
script.runInContext(context);
|
|
126
|
-
const valConfig = sandbox.module.exports.config;
|
|
127
|
-
if (!valConfig) {
|
|
128
|
-
throw Error(`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`);
|
|
129
|
-
}
|
|
130
|
-
const result = ValConfigSchema.safeParse(valConfig);
|
|
131
|
-
if (!result.success) {
|
|
132
|
-
throw Error(`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`);
|
|
133
|
-
}
|
|
134
|
-
return result.data;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
62
|
function getFileExt(filePath) {
|
|
138
63
|
// NOTE: We do not import the path module. This code is copied in different projects. We want the same implementation and which means that this might running in browser where path is not available).
|
|
139
64
|
return filePath.split(".").pop() || "";
|
|
@@ -511,15 +436,15 @@ function createDefaultValFSHost() {
|
|
|
511
436
|
return {
|
|
512
437
|
...ts__default["default"].sys,
|
|
513
438
|
writeFile: (fileName, data, encoding) => {
|
|
514
|
-
fs__default
|
|
439
|
+
fs__default["default"].mkdirSync(path__default["default"].dirname(fileName), {
|
|
515
440
|
recursive: true
|
|
516
441
|
});
|
|
517
|
-
fs__default
|
|
442
|
+
fs__default["default"].writeFileSync(fileName, typeof data === "string" ? data : new Uint8Array(data), encoding);
|
|
518
443
|
},
|
|
519
|
-
rmFile: fs__default
|
|
444
|
+
rmFile: fs__default["default"].rmSync,
|
|
520
445
|
readBuffer: fileName => {
|
|
521
446
|
try {
|
|
522
|
-
return fs__default
|
|
447
|
+
return fs__default["default"].readFileSync(fileName);
|
|
523
448
|
} catch {
|
|
524
449
|
return undefined;
|
|
525
450
|
}
|
|
@@ -860,7 +785,7 @@ function getCachedFile(moduleFilePath, projectRoot, cache) {
|
|
|
860
785
|
const filePath = path__default["default"].join(projectRoot, moduleFilePath);
|
|
861
786
|
let fileContent;
|
|
862
787
|
try {
|
|
863
|
-
fileContent = fs__default
|
|
788
|
+
fileContent = fs__default["default"].readFileSync(filePath, "utf-8");
|
|
864
789
|
} catch {
|
|
865
790
|
cache.set(moduleFilePath, null);
|
|
866
791
|
return null;
|
|
@@ -891,7 +816,7 @@ async function validate({
|
|
|
891
816
|
// errors found. Re-reads config and val files each call so it always reflects
|
|
892
817
|
// the latest state on disk (used both for one-shot and watch mode).
|
|
893
818
|
async function runOnce() {
|
|
894
|
-
const valConfigFile =
|
|
819
|
+
const valConfigFile = await server.findAndEvalValConfigFile(projectRoot);
|
|
895
820
|
const resolvedValConfigFile = valConfigFile ? {
|
|
896
821
|
...valConfigFile,
|
|
897
822
|
project: process.env.VAL_PROJECT || valConfigFile.project
|
|
@@ -1071,11 +996,11 @@ async function validate({
|
|
|
1071
996
|
if (prettier) {
|
|
1072
997
|
for (const file of fixedFiles) {
|
|
1073
998
|
const filePath = path__default["default"].join(projectRoot, file);
|
|
1074
|
-
const fileContent = await fs__default["default"].readFile(filePath, "utf-8");
|
|
999
|
+
const fileContent = await fs__default$1["default"].readFile(filePath, "utf-8");
|
|
1075
1000
|
const formattedContent = await prettier.format(fileContent, {
|
|
1076
1001
|
filepath: filePath
|
|
1077
1002
|
});
|
|
1078
|
-
await fs__default["default"].writeFile(filePath, formattedContent);
|
|
1003
|
+
await fs__default$1["default"].writeFile(filePath, formattedContent);
|
|
1079
1004
|
}
|
|
1080
1005
|
}
|
|
1081
1006
|
|
|
@@ -1196,7 +1121,7 @@ async function listUnusedFiles({
|
|
|
1196
1121
|
}) {
|
|
1197
1122
|
var _valConfigFile$files;
|
|
1198
1123
|
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
|
1199
|
-
const valConfigFile =
|
|
1124
|
+
const valConfigFile = await server.findAndEvalValConfigFile(projectRoot);
|
|
1200
1125
|
// Strip the leading "/" so it is relative to the project root (e.g. "public/val").
|
|
1201
1126
|
const managedDir = ((valConfigFile === null || valConfigFile === void 0 || (_valConfigFile$files = valConfigFile.files) === null || _valConfigFile$files === void 0 ? void 0 : _valConfigFile$files.directory) ?? "/public/val").replace(/^\//, "");
|
|
1202
1127
|
const service = await server.createService(projectRoot);
|
|
@@ -1285,7 +1210,7 @@ const getVersions = () => {
|
|
|
1285
1210
|
};
|
|
1286
1211
|
};
|
|
1287
1212
|
|
|
1288
|
-
const host
|
|
1213
|
+
const host = process.env.VAL_BUILD_URL || "https://admin.val.build";
|
|
1289
1214
|
async function connect(options) {
|
|
1290
1215
|
const {
|
|
1291
1216
|
root
|
|
@@ -1303,11 +1228,11 @@ async function connect(options) {
|
|
|
1303
1228
|
if (maybeGitOwnerAndRepo) {
|
|
1304
1229
|
params.set("github_repo", [maybeGitOwnerAndRepo.owner, maybeGitOwnerAndRepo.repo].join("/"));
|
|
1305
1230
|
}
|
|
1306
|
-
const url = `${host
|
|
1231
|
+
const url = `${host}/connect?${params.toString()}`;
|
|
1307
1232
|
console.log(pc__default["default"].dim(`\nFollow the instructions in your browser to complete the setup:\n${pc__default["default"].cyan(url)}\n`));
|
|
1308
1233
|
}
|
|
1309
1234
|
async function tryGetProject(projectRoot) {
|
|
1310
|
-
const valConfigFile =
|
|
1235
|
+
const valConfigFile = await server.findAndEvalValConfigFile(projectRoot);
|
|
1311
1236
|
if (valConfigFile && valConfigFile.project) {
|
|
1312
1237
|
const parts = valConfigFile.project.split("/");
|
|
1313
1238
|
if (parts.length === 2) {
|
|
@@ -1360,8 +1285,8 @@ function tryGetGitConfig(root) {
|
|
|
1360
1285
|
let lastDir = null;
|
|
1361
1286
|
while (currentDir !== lastDir) {
|
|
1362
1287
|
const gitConfigPath = path__default["default"].join(currentDir, ".git", "config");
|
|
1363
|
-
if (fs__default
|
|
1364
|
-
return fs__default
|
|
1288
|
+
if (fs__default["default"].existsSync(gitConfigPath)) {
|
|
1289
|
+
return fs__default["default"].readFileSync(gitConfigPath, "utf-8");
|
|
1365
1290
|
}
|
|
1366
1291
|
lastDir = currentDir;
|
|
1367
1292
|
currentDir = path__default["default"].dirname(currentDir);
|
|
@@ -1372,83 +1297,54 @@ function tryGetGitConfig(root) {
|
|
|
1372
1297
|
return null;
|
|
1373
1298
|
}
|
|
1374
1299
|
|
|
1375
|
-
|
|
1300
|
+
/**
|
|
1301
|
+
* Terminal wrapper around the login device flow in `@valbuild/server`.
|
|
1302
|
+
* The flow itself (polling, token persistence) is shared with
|
|
1303
|
+
* `@valbuild/language-server`.
|
|
1304
|
+
*/
|
|
1376
1305
|
async function login(options) {
|
|
1377
1306
|
try {
|
|
1378
|
-
var _response$headers$get;
|
|
1379
1307
|
console.log(pc__default["default"].cyan("\nStarting login process...\n"));
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
headers: {
|
|
1385
|
-
"Content-Type": "application/json"
|
|
1386
|
-
}
|
|
1387
|
-
});
|
|
1388
|
-
let token;
|
|
1389
|
-
let url;
|
|
1390
|
-
if (!((_response$headers$get = response.headers.get("content-type")) !== null && _response$headers$get !== void 0 && _response$headers$get.includes("application/json"))) {
|
|
1391
|
-
const text = await response.text();
|
|
1392
|
-
console.error(pc__default["default"].red("Unexpected failure while trying to login (content type was not JSON). "), text ? `Server response: ${text} (status: ${response.status})` : `Status: ${response.status}`);
|
|
1393
|
-
process.exit(1);
|
|
1394
|
-
}
|
|
1395
|
-
const json = await response.json();
|
|
1396
|
-
if (json) {
|
|
1397
|
-
token = json.nonce;
|
|
1398
|
-
url = json.url;
|
|
1399
|
-
}
|
|
1400
|
-
if (!token || !url) {
|
|
1401
|
-
console.error(pc__default["default"].red("Unexpected response from the server."), json);
|
|
1402
|
-
process.exit(1);
|
|
1403
|
-
}
|
|
1308
|
+
const {
|
|
1309
|
+
nonce,
|
|
1310
|
+
url
|
|
1311
|
+
} = await server.startValLogin();
|
|
1404
1312
|
console.log(pc__default["default"].green("Open the following URL in your browser to log in:"));
|
|
1405
1313
|
console.log(pc__default["default"].underline(pc__default["default"].blue(url)));
|
|
1406
1314
|
console.log(pc__default["default"].dim("\nWaiting for login confirmation...\n"));
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
// Step 3: Save the token
|
|
1412
|
-
const filePath = server.getPersonalAccessTokenPath(options.root || process.cwd());
|
|
1413
|
-
saveToken(result, filePath);
|
|
1315
|
+
const result = await server.awaitValLoginConfirmation(nonce);
|
|
1316
|
+
const filePath = server.persistPersonalAccessToken(options.root || process.cwd(), result);
|
|
1317
|
+
console.log(pc__default["default"].green(`Token for ${pc__default["default"].cyan(result.profile.email)} saved to ${pc__default["default"].cyan(filePath)}`));
|
|
1414
1318
|
} catch (error) {
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
const MAX_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
1420
|
-
async function pollForConfirmation(token) {
|
|
1421
|
-
const start = Date.now();
|
|
1422
|
-
while (Date.now() - start < MAX_DURATION) {
|
|
1423
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
1424
|
-
const response = await fetch(`${host}/api/login?token=${token}&consume=true`, {
|
|
1425
|
-
method: "POST"
|
|
1426
|
-
});
|
|
1427
|
-
if (response.status === 500) {
|
|
1428
|
-
console.error(pc__default["default"].red("An error occurred on the server."));
|
|
1319
|
+
if (error instanceof server.ValLoginError) {
|
|
1320
|
+
console.error(pc__default["default"].red(error.message), error.details ?? "");
|
|
1429
1321
|
process.exit(1);
|
|
1430
1322
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
if (json) {
|
|
1434
|
-
if (typeof json.profile.email === "string" && typeof json.pat === "string") {
|
|
1435
|
-
return json;
|
|
1436
|
-
} else {
|
|
1437
|
-
console.error(pc__default["default"].red("Unexpected response from the server."));
|
|
1438
|
-
process.exit(1);
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1323
|
+
console.error(pc__default["default"].red("An error occurred during the login process. Check your internet connection. Details:"), error instanceof Error ? error.message : JSON.stringify(error, null, 2));
|
|
1324
|
+
process.exit(1);
|
|
1442
1325
|
}
|
|
1443
|
-
console.error(pc__default["default"].red("Login confirmation timed out."));
|
|
1444
|
-
process.exit(1);
|
|
1445
1326
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1327
|
+
|
|
1328
|
+
/**
|
|
1329
|
+
* Start the Val language server.
|
|
1330
|
+
*
|
|
1331
|
+
* Editors normally resolve `@valbuild/language-server` from the project's
|
|
1332
|
+
* `node_modules` and launch its `val-language-server` binary directly. This
|
|
1333
|
+
* subcommand exists so the server is discoverable from the CLI and easy to
|
|
1334
|
+
* start by hand when debugging an editor integration:
|
|
1335
|
+
*
|
|
1336
|
+
* npx val lsp --stdio
|
|
1337
|
+
*
|
|
1338
|
+
* The import is dynamic so that `vscode-languageserver` is not loaded on every
|
|
1339
|
+
* `val` invocation.
|
|
1340
|
+
*/
|
|
1341
|
+
async function lsp() {
|
|
1342
|
+
const {
|
|
1343
|
+
main
|
|
1344
|
+
} = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('@valbuild/language-server')); });
|
|
1345
|
+
// Transport (`--stdio`, `--node-ipc`, `--socket=`) is read from argv by the
|
|
1346
|
+
// server itself, so the flags pass straight through.
|
|
1347
|
+
main();
|
|
1452
1348
|
}
|
|
1453
1349
|
|
|
1454
1350
|
/**
|
|
@@ -1465,10 +1361,10 @@ class DebugContextError extends Error {}
|
|
|
1465
1361
|
async function createDebugContext(options) {
|
|
1466
1362
|
var _config$files;
|
|
1467
1363
|
const projectRoot = options.root ? path__default["default"].resolve(options.root) : process.cwd();
|
|
1468
|
-
if (!fs__default
|
|
1364
|
+
if (!fs__default["default"].existsSync(projectRoot)) {
|
|
1469
1365
|
throw new DebugContextError(`Project root does not exist: ${projectRoot}`);
|
|
1470
1366
|
}
|
|
1471
|
-
const config =
|
|
1367
|
+
const config = await server.findAndEvalValConfigFile(projectRoot);
|
|
1472
1368
|
if (!config) {
|
|
1473
1369
|
throw new DebugContextError(`Could not find val.config.ts nor val.config.js in: ${projectRoot}`);
|
|
1474
1370
|
}
|
|
@@ -1535,8 +1431,8 @@ async function createDebugContext(options) {
|
|
|
1535
1431
|
*/
|
|
1536
1432
|
function readAuth(projectRoot) {
|
|
1537
1433
|
const patFile = server.getPersonalAccessTokenPath(projectRoot);
|
|
1538
|
-
if (fs__default
|
|
1539
|
-
const contents = fs__default
|
|
1434
|
+
if (fs__default["default"].existsSync(patFile)) {
|
|
1435
|
+
const contents = fs__default["default"].readFileSync(patFile, "utf-8");
|
|
1540
1436
|
const parsed = server.parsePersonalAccessTokenFile(contents);
|
|
1541
1437
|
if (parsed.success) {
|
|
1542
1438
|
return {
|
|
@@ -2083,7 +1979,7 @@ function readProjectValVersions(projectRoot) {
|
|
|
2083
1979
|
function readLocalFile(projectRoot, projectRelativePath) {
|
|
2084
1980
|
const absPath = path__default["default"].join(projectRoot, projectRelativePath);
|
|
2085
1981
|
try {
|
|
2086
|
-
return fs__default
|
|
1982
|
+
return fs__default["default"].readFileSync(absPath, "utf-8");
|
|
2087
1983
|
} catch {
|
|
2088
1984
|
return null;
|
|
2089
1985
|
}
|
|
@@ -2225,10 +2121,10 @@ async function writeZip(outPath, entries) {
|
|
|
2225
2121
|
type: "nodebuffer",
|
|
2226
2122
|
compression: "DEFLATE"
|
|
2227
2123
|
});
|
|
2228
|
-
fs__default
|
|
2124
|
+
fs__default["default"].mkdirSync(path__default["default"].dirname(outPath), {
|
|
2229
2125
|
recursive: true
|
|
2230
2126
|
});
|
|
2231
|
-
fs__default
|
|
2127
|
+
fs__default["default"].writeFileSync(outPath, buffer);
|
|
2232
2128
|
}
|
|
2233
2129
|
function timestamp() {
|
|
2234
2130
|
return new Date().toISOString().replace(/[:.]/g, "-").replace(/Z$/, "");
|
|
@@ -2365,6 +2261,7 @@ async function main() {
|
|
|
2365
2261
|
files
|
|
2366
2262
|
connect
|
|
2367
2263
|
versions
|
|
2264
|
+
lsp
|
|
2368
2265
|
debug
|
|
2369
2266
|
delete-unappliable-patches
|
|
2370
2267
|
|
|
@@ -2394,6 +2291,13 @@ async function main() {
|
|
|
2394
2291
|
Options:
|
|
2395
2292
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
|
2396
2293
|
|
|
2294
|
+
Command: lsp
|
|
2295
|
+
Description: start the Val language server (used by editor integrations)
|
|
2296
|
+
Options:
|
|
2297
|
+
--stdio Communicate over stdin/stdout
|
|
2298
|
+
--node-ipc Communicate over Node IPC
|
|
2299
|
+
--socket=[port] Communicate over a socket
|
|
2300
|
+
|
|
2397
2301
|
Command: debug
|
|
2398
2302
|
Description: Create a self-contained snapshot (the pending patches plus the modules they
|
|
2399
2303
|
touch or reference) that Val developers can replay to reproduce validation and save
|
|
@@ -2423,11 +2327,6 @@ async function main() {
|
|
|
2423
2327
|
--verbose List every pending patch, not just the failing ones
|
|
2424
2328
|
`, {
|
|
2425
2329
|
flags: {
|
|
2426
|
-
port: {
|
|
2427
|
-
type: "number",
|
|
2428
|
-
alias: "p",
|
|
2429
|
-
default: 4123
|
|
2430
|
-
},
|
|
2431
2330
|
root: {
|
|
2432
2331
|
type: "string",
|
|
2433
2332
|
alias: "r"
|
|
@@ -2489,6 +2388,8 @@ async function main() {
|
|
|
2489
2388
|
});
|
|
2490
2389
|
case "versions":
|
|
2491
2390
|
return versions();
|
|
2391
|
+
case "lsp":
|
|
2392
|
+
return lsp();
|
|
2492
2393
|
case "debug":
|
|
2493
2394
|
return debug({
|
|
2494
2395
|
root: flags.root,
|