@socketsecurity/cli 0.14.6 → 0.14.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/dist/cli.js +134 -86
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -12,9 +12,9 @@ var sdk = require('./sdk.js');
|
|
|
12
12
|
var require$$1$2 = require('@inquirer/prompts');
|
|
13
13
|
var require$$3$2 = require('@npmcli/package-json');
|
|
14
14
|
var require$$4 = require('@socketsecurity/registry');
|
|
15
|
+
var require$$3$1 = require('semver');
|
|
15
16
|
var require$$1$3 = require('@socketregistry/hyrious__bun.lockb');
|
|
16
17
|
var require$$3 = require('browserslist');
|
|
17
|
-
var require$$3$1 = require('semver');
|
|
18
18
|
var require$$5$1 = require('which');
|
|
19
19
|
var require$$2 = require('@apideck/better-ajv-errors');
|
|
20
20
|
var require$$3$3 = require('@socketsecurity/config');
|
|
@@ -937,12 +937,13 @@ var _nodePath$3 = require$$1;
|
|
|
937
937
|
var _hyrious__bun = require$$1$3;
|
|
938
938
|
var _promiseSpawn$3 = require$$1$1;
|
|
939
939
|
var _browserslist = require$$3;
|
|
940
|
-
var _semver = require$$3$1;
|
|
940
|
+
var _semver$1 = require$$3$1;
|
|
941
941
|
var _which = require$$5$1;
|
|
942
942
|
var _fs = fs;
|
|
943
943
|
var _json = json;
|
|
944
944
|
var _objects$1 = objects;
|
|
945
945
|
var _strings = strings;
|
|
946
|
+
const PNPM_WORKSPACE = 'pnpm-workspace';
|
|
946
947
|
const AGENTS = packageManagerDetector.AGENTS = ['bun', 'npm', 'pnpm', 'yarn'];
|
|
947
948
|
const LOCKS = packageManagerDetector.LOCKS = {
|
|
948
949
|
'bun.lockb': 'bun',
|
|
@@ -993,17 +994,16 @@ const readLockFileByAgent = (() => {
|
|
|
993
994
|
};
|
|
994
995
|
})();
|
|
995
996
|
async function detect({
|
|
996
|
-
cwd,
|
|
997
|
+
cwd = process.cwd(),
|
|
997
998
|
onUnknown
|
|
998
999
|
} = {}) {
|
|
999
|
-
|
|
1000
|
+
let lockPath = await (0, _fs.findUp)(Object.keys(LOCKS), {
|
|
1000
1001
|
cwd
|
|
1001
1002
|
});
|
|
1002
1003
|
const isHiddenLockFile = lockPath?.endsWith('.package-lock.json') ?? false;
|
|
1003
1004
|
const pkgJsonPath = lockPath ? _nodePath$3.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await (0, _fs.findUp)('package.json', {
|
|
1004
1005
|
cwd
|
|
1005
1006
|
});
|
|
1006
|
-
|
|
1007
1007
|
// Read Corepack `packageManager` field in package.json:
|
|
1008
1008
|
// https://nodejs.org/api/packages.html#packagemanager
|
|
1009
1009
|
const pkgJsonStr = (0, _fs.existsSync)(pkgJsonPath) ? await (0, _fs.readFileUtf8)(pkgJsonPath) : undefined;
|
|
@@ -1022,7 +1022,7 @@ async function detect({
|
|
|
1022
1022
|
}
|
|
1023
1023
|
}
|
|
1024
1024
|
}
|
|
1025
|
-
if (agent === undefined && !isHiddenLockFile && typeof lockPath === 'string') {
|
|
1025
|
+
if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockPath === 'string') {
|
|
1026
1026
|
agent = LOCKS[_nodePath$3.basename(lockPath)];
|
|
1027
1027
|
}
|
|
1028
1028
|
if (agent === undefined) {
|
|
@@ -1042,7 +1042,7 @@ async function detect({
|
|
|
1042
1042
|
if (pkgJson) {
|
|
1043
1043
|
const pkgPath = _nodePath$3.dirname(pkgJsonPath);
|
|
1044
1044
|
isPrivate = !!pkgJson['private'];
|
|
1045
|
-
isWorkspace = !!pkgJson['workspaces'] ||
|
|
1045
|
+
isWorkspace = !!pkgJson['workspaces'] || (0, _fs.existsSync)(_nodePath$3.join(pkgPath, `${PNPM_WORKSPACE}.yaml`)) || (0, _fs.existsSync)(_nodePath$3.join(pkgPath, `${PNPM_WORKSPACE}.yml`));
|
|
1046
1046
|
let browser;
|
|
1047
1047
|
let node;
|
|
1048
1048
|
const browserField = (0, _objects$1.getOwn)(pkgJson, 'browser');
|
|
@@ -1051,7 +1051,7 @@ async function detect({
|
|
|
1051
1051
|
}
|
|
1052
1052
|
const nodeRange = (0, _objects$1.getOwn)(pkgJson['engines'], 'node');
|
|
1053
1053
|
if ((0, _strings.isNonEmptyString)(nodeRange)) {
|
|
1054
|
-
node = MAINTAINED_NODE_VERSIONS.some(v => _semver.satisfies(v, nodeRange));
|
|
1054
|
+
node = MAINTAINED_NODE_VERSIONS.some(v => _semver$1.satisfies(v, nodeRange));
|
|
1055
1055
|
}
|
|
1056
1056
|
const browserslistQuery = (0, _objects$1.getOwn)(pkgJson, 'browserslist');
|
|
1057
1057
|
if (Array.isArray(browserslistQuery)) {
|
|
@@ -1061,7 +1061,7 @@ async function detect({
|
|
|
1061
1061
|
browser = browserslistTargets.length !== browserslistNodeTargets.length;
|
|
1062
1062
|
}
|
|
1063
1063
|
if (node === undefined && browserslistNodeTargets.length) {
|
|
1064
|
-
node = MAINTAINED_NODE_VERSIONS.some(r => browserslistNodeTargets.some(v => _semver.satisfies(v, `^${r}`)));
|
|
1064
|
+
node = MAINTAINED_NODE_VERSIONS.some(r => browserslistNodeTargets.some(v => _semver$1.satisfies(v, `^${r}`)));
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|
|
1067
1067
|
if (browser !== undefined) {
|
|
@@ -1071,6 +1071,8 @@ async function detect({
|
|
|
1071
1071
|
targets.node = node;
|
|
1072
1072
|
}
|
|
1073
1073
|
lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
|
|
1074
|
+
} else {
|
|
1075
|
+
lockPath = undefined;
|
|
1074
1076
|
}
|
|
1075
1077
|
return {
|
|
1076
1078
|
agent,
|
|
@@ -1130,31 +1132,47 @@ var _packageJson = require$$3$2;
|
|
|
1130
1132
|
var _registry = require$$4;
|
|
1131
1133
|
var _meow$m = _interopRequireDefault$n(vendor.build);
|
|
1132
1134
|
var _ora$i = _interopRequireDefault$n(vendor.ora);
|
|
1135
|
+
var _semver = require$$3$1;
|
|
1133
1136
|
var _formatting$k = formatting;
|
|
1134
1137
|
var _objects = objects;
|
|
1135
1138
|
var _packageManagerDetector = packageManagerDetector;
|
|
1136
1139
|
var _regexps = regexps;
|
|
1137
1140
|
var _sorts$1 = sorts;
|
|
1138
1141
|
const distPath$1 = __dirname;
|
|
1142
|
+
const COMMAND_TITLE = 'Socket Optimize';
|
|
1139
1143
|
const OVERRIDES_FIELD_NAME = 'overrides';
|
|
1140
1144
|
const RESOLUTIONS_FIELD_NAME = 'resolutions';
|
|
1141
|
-
const
|
|
1142
|
-
const SOCKET_REGISTRY_MAJOR_VERSION = '^1';
|
|
1143
|
-
const allPackages = (0, _registry.getManifestData)('npm').filter(({
|
|
1144
|
-
1: d
|
|
1145
|
-
}) => d.engines?.node?.startsWith('>=18')).map(({
|
|
1145
|
+
const availableOverrides = (0, _registry.getManifestData)('npm').filter(({
|
|
1146
1146
|
1: d
|
|
1147
|
-
}) => d.
|
|
1148
|
-
const
|
|
1147
|
+
}) => d.engines?.node?.startsWith('>=18'));
|
|
1148
|
+
const getOverridesDataByAgent = {
|
|
1149
1149
|
// npm overrides documentation:
|
|
1150
1150
|
// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides
|
|
1151
|
-
npm: pkgJson =>
|
|
1151
|
+
npm: pkgJson => {
|
|
1152
|
+
const overrides = pkgJson?.overrides ?? {};
|
|
1153
|
+
return {
|
|
1154
|
+
type: 'npm',
|
|
1155
|
+
overrides
|
|
1156
|
+
};
|
|
1157
|
+
},
|
|
1152
1158
|
// pnpm overrides documentation:
|
|
1153
1159
|
// https://pnpm.io/package_json#pnpmoverrides
|
|
1154
|
-
pnpm: pkgJson =>
|
|
1160
|
+
pnpm: pkgJson => {
|
|
1161
|
+
const overrides = pkgJson?.pnpm?.overrides ?? undefined;
|
|
1162
|
+
return overrides ? {
|
|
1163
|
+
type: 'pnpm',
|
|
1164
|
+
overrides
|
|
1165
|
+
} : undefined;
|
|
1166
|
+
},
|
|
1155
1167
|
// Yarn resolutions documentation:
|
|
1156
1168
|
// https://yarnpkg.com/configuration/manifest#resolutions
|
|
1157
|
-
yarn: pkgJson =>
|
|
1169
|
+
yarn: pkgJson => {
|
|
1170
|
+
const overrides = pkgJson?.resolutions ?? {};
|
|
1171
|
+
return {
|
|
1172
|
+
type: 'yarn',
|
|
1173
|
+
overrides
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1158
1176
|
};
|
|
1159
1177
|
const lockIncludesByAgent = {
|
|
1160
1178
|
npm: (lockSrc, name) => {
|
|
@@ -1186,16 +1204,22 @@ const updateManifestByAgent = {
|
|
|
1186
1204
|
__proto__: null,
|
|
1187
1205
|
npm(editablePkgJson, overrides) {
|
|
1188
1206
|
editablePkgJson.update({
|
|
1207
|
+
__proto__: null,
|
|
1189
1208
|
[OVERRIDES_FIELD_NAME]: overrides
|
|
1190
1209
|
});
|
|
1191
1210
|
},
|
|
1192
1211
|
pnpm(editablePkgJson, overrides) {
|
|
1193
1212
|
editablePkgJson.update({
|
|
1194
|
-
|
|
1213
|
+
pnpm: {
|
|
1214
|
+
__proto__: null,
|
|
1215
|
+
...editablePkgJson.content['pnpm'],
|
|
1216
|
+
[OVERRIDES_FIELD_NAME]: overrides
|
|
1217
|
+
}
|
|
1195
1218
|
});
|
|
1196
1219
|
},
|
|
1197
1220
|
yarn(editablePkgJson, overrides) {
|
|
1198
1221
|
editablePkgJson.update({
|
|
1222
|
+
__proto__: null,
|
|
1199
1223
|
[RESOLUTIONS_FIELD_NAME]: overrides
|
|
1200
1224
|
});
|
|
1201
1225
|
}
|
|
@@ -1206,48 +1230,74 @@ async function addOverrides({
|
|
|
1206
1230
|
isWorkspace,
|
|
1207
1231
|
lockSrc,
|
|
1208
1232
|
lockIncludes,
|
|
1209
|
-
pkgJsonPath
|
|
1210
|
-
overrides
|
|
1233
|
+
pkgJsonPath
|
|
1211
1234
|
}, aoState) {
|
|
1212
1235
|
const {
|
|
1213
1236
|
packageNames
|
|
1214
1237
|
} = aoState;
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1238
|
+
const editablePkgJson = await _packageJson.load(_nodePath$2.dirname(pkgJsonPath));
|
|
1239
|
+
const {
|
|
1240
|
+
dependencies,
|
|
1241
|
+
devDependencies,
|
|
1242
|
+
peerDependencies,
|
|
1243
|
+
optionalDependencies
|
|
1244
|
+
} = editablePkgJson.content;
|
|
1245
|
+
const depEntries = [['dependencies', dependencies ? {
|
|
1246
|
+
__proto__: null,
|
|
1247
|
+
...dependencies
|
|
1248
|
+
} : undefined], ['devDependencies', devDependencies ? {
|
|
1249
|
+
__proto__: null,
|
|
1250
|
+
...devDependencies
|
|
1251
|
+
} : undefined], ['peerDependencies', peerDependencies ? {
|
|
1252
|
+
__proto__: null,
|
|
1253
|
+
...peerDependencies
|
|
1254
|
+
} : undefined], ['optionalDependencies', optionalDependencies ? {
|
|
1255
|
+
__proto__: null,
|
|
1256
|
+
...optionalDependencies
|
|
1257
|
+
} : undefined]].filter(({
|
|
1258
|
+
1: o
|
|
1259
|
+
}) => o);
|
|
1260
|
+
const overridesDataObjects = [getOverridesDataByAgent['npm'](editablePkgJson.content)];
|
|
1261
|
+
const isApp = isPrivate || isWorkspace;
|
|
1262
|
+
const overridesData = !isApp || agent !== 'npm' ? getOverridesDataByAgent[isApp ? agent : 'yarn'](editablePkgJson.content) : undefined;
|
|
1263
|
+
if (overridesData) {
|
|
1264
|
+
overridesDataObjects.push(overridesData);
|
|
1265
|
+
}
|
|
1266
|
+
for (const {
|
|
1267
|
+
1: data
|
|
1268
|
+
} of availableOverrides) {
|
|
1269
|
+
const {
|
|
1270
|
+
name: regPkgName,
|
|
1271
|
+
package: origPkgName,
|
|
1272
|
+
version
|
|
1273
|
+
} = data;
|
|
1274
|
+
for (const {
|
|
1275
|
+
1: depObj
|
|
1276
|
+
} of depEntries) {
|
|
1277
|
+
const pkgSpec = depObj[origPkgName];
|
|
1278
|
+
if (pkgSpec) {
|
|
1279
|
+
if (!pkgSpec.startsWith(`npm:${regPkgName}@`)) {
|
|
1280
|
+
packageNames.add(regPkgName);
|
|
1281
|
+
depObj[origPkgName] = `npm:${regPkgName}@^${version}`;
|
|
1282
|
+
}
|
|
1224
1283
|
}
|
|
1225
|
-
addedCount += 1;
|
|
1226
|
-
packageNames.add(name);
|
|
1227
|
-
clonedOverrides[name] = `npm:${SOCKET_REGISTRY_NAME}/${name}@${SOCKET_REGISTRY_MAJOR_VERSION}`;
|
|
1228
1284
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
if ((0, _objects.hasOwn)(editablePkgJson.content, 'pnpm') && (0, _objects.isObjectObject)(editablePkgJson.content['pnpm'])) {
|
|
1236
|
-
const pnpmKeys = Object.keys(editablePkgJson.content['pnpm']);
|
|
1237
|
-
editablePkgJson.update(pnpmKeys.length === 1 && pnpmKeys[0] === 'overrides' ?
|
|
1238
|
-
// Properties with undefined values are omitted when saved as JSON.
|
|
1239
|
-
{
|
|
1240
|
-
pnpm: undefined
|
|
1241
|
-
} : {
|
|
1242
|
-
pnpm: {
|
|
1243
|
-
__proto__: null,
|
|
1244
|
-
...editablePkgJson.content['pnpm'],
|
|
1245
|
-
overrides: undefined
|
|
1246
|
-
}
|
|
1247
|
-
});
|
|
1285
|
+
for (const {
|
|
1286
|
+
overrides
|
|
1287
|
+
} of overridesDataObjects) {
|
|
1288
|
+
if (overrides && !(0, _objects.hasOwn)(overrides, origPkgName) && lockIncludes(lockSrc, origPkgName)) {
|
|
1289
|
+
packageNames.add(regPkgName);
|
|
1290
|
+
overrides[origPkgName] = `npm:${regPkgName}@^${_semver.major(version)}`;
|
|
1248
1291
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
if (packageNames.size) {
|
|
1295
|
+
editablePkgJson.update(Object.fromEntries(depEntries));
|
|
1296
|
+
for (const {
|
|
1297
|
+
type,
|
|
1298
|
+
overrides
|
|
1299
|
+
} of overridesDataObjects) {
|
|
1300
|
+
updateManifestByAgent[type](editablePkgJson, (0, _sorts$1.toSortedObject)(overrides));
|
|
1251
1301
|
}
|
|
1252
1302
|
await editablePkgJson.save();
|
|
1253
1303
|
}
|
|
@@ -1260,6 +1310,7 @@ const optimize = optimize$1.optimize = {
|
|
|
1260
1310
|
}) {
|
|
1261
1311
|
const commandContext = setupCommand$l(`${parentName} dependency optimize`, optimize.description, argv, importMeta);
|
|
1262
1312
|
if (commandContext) {
|
|
1313
|
+
const cwd = process.cwd();
|
|
1263
1314
|
const {
|
|
1264
1315
|
agent,
|
|
1265
1316
|
agentExecPath,
|
|
@@ -1272,49 +1323,44 @@ const optimize = optimize$1.optimize = {
|
|
|
1272
1323
|
pkgJson,
|
|
1273
1324
|
supported
|
|
1274
1325
|
} = await (0, _packageManagerDetector.detect)({
|
|
1275
|
-
cwd
|
|
1326
|
+
cwd,
|
|
1276
1327
|
onUnknown(pkgManager) {
|
|
1277
|
-
console.log(`⚠️ Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}
|
|
1328
|
+
console.log(`⚠️ ${COMMAND_TITLE}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
|
|
1278
1329
|
}
|
|
1279
1330
|
});
|
|
1280
1331
|
if (!supported) {
|
|
1281
|
-
console.log(
|
|
1332
|
+
console.log(`✘ ${COMMAND_TITLE}: Package engines.node range is not supported`);
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
const lockName = lockPath ? _nodePath$2.basename(lockPath) : 'lock file';
|
|
1336
|
+
if (lockSrc === undefined) {
|
|
1337
|
+
console.log(`✘ ${COMMAND_TITLE}: No ${lockName} found`);
|
|
1282
1338
|
return;
|
|
1283
1339
|
}
|
|
1284
1340
|
if (pkgJson === undefined) {
|
|
1285
|
-
console.log(
|
|
1341
|
+
console.log(`✘ ${COMMAND_TITLE}: No package.json found`);
|
|
1286
1342
|
return;
|
|
1287
1343
|
}
|
|
1344
|
+
if (lockPath && _nodePath$2.relative(cwd, lockPath).startsWith('.')) {
|
|
1345
|
+
console.log(`⚠️ ${COMMAND_TITLE}: Package ${lockName} found at ${lockPath}`);
|
|
1346
|
+
}
|
|
1288
1347
|
const aoState = {
|
|
1289
1348
|
output: pkgJsonStr,
|
|
1290
1349
|
packageNames: new Set()
|
|
1291
1350
|
};
|
|
1292
1351
|
if (lockSrc) {
|
|
1293
|
-
const
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
lockIncludes
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
}];
|
|
1306
|
-
for (const config of configs) {
|
|
1307
|
-
await addOverrides({
|
|
1308
|
-
__proto__: null,
|
|
1309
|
-
isPrivate,
|
|
1310
|
-
isWorkspace,
|
|
1311
|
-
lockSrc,
|
|
1312
|
-
pkgJsonPath,
|
|
1313
|
-
pkgJsonStr,
|
|
1314
|
-
pkgJson,
|
|
1315
|
-
...config
|
|
1316
|
-
}, aoState);
|
|
1317
|
-
}
|
|
1352
|
+
const lockIncludes = agent === 'bun' ? lockIncludesByAgent.yarn : lockIncludesByAgent[agent];
|
|
1353
|
+
await addOverrides({
|
|
1354
|
+
__proto__: null,
|
|
1355
|
+
agent: agent === 'bun' ? 'yarn' : agent,
|
|
1356
|
+
isPrivate,
|
|
1357
|
+
isWorkspace,
|
|
1358
|
+
lockIncludes,
|
|
1359
|
+
lockSrc,
|
|
1360
|
+
pkgJsonPath,
|
|
1361
|
+
pkgJsonStr,
|
|
1362
|
+
pkgJson
|
|
1363
|
+
}, aoState);
|
|
1318
1364
|
}
|
|
1319
1365
|
const {
|
|
1320
1366
|
size: count
|
|
@@ -1324,7 +1370,6 @@ const optimize = optimize$1.optimize = {
|
|
|
1324
1370
|
} else {
|
|
1325
1371
|
console.log('Congratulations! Already Socket.dev optimized 🎉');
|
|
1326
1372
|
}
|
|
1327
|
-
const lockName = lockPath ? _nodePath$2.basename(lockPath) : 'lock file';
|
|
1328
1373
|
const isNpm = agent === 'npm';
|
|
1329
1374
|
if (isNpm || count) {
|
|
1330
1375
|
// Always update package-lock.json until the npm overrides PR lands:
|
|
@@ -1347,9 +1392,12 @@ const optimize = optimize$1.optimize = {
|
|
|
1347
1392
|
});
|
|
1348
1393
|
}
|
|
1349
1394
|
spinner.stop();
|
|
1395
|
+
if (isNpm) {
|
|
1396
|
+
console.log(`💡 Re-run ${COMMAND_TITLE} whenever ${lockName} changes.\n This can be skipped once npm ships https://github.com/npm/cli/pull/7025.`);
|
|
1397
|
+
}
|
|
1350
1398
|
} catch {
|
|
1351
1399
|
spinner.stop();
|
|
1352
|
-
console.log(`✘
|
|
1400
|
+
console.log(`✘ ${COMMAND_TITLE}: ${agent} install failed to update ${lockName}`);
|
|
1353
1401
|
}
|
|
1354
1402
|
}
|
|
1355
1403
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/cli",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.7",
|
|
4
4
|
"description": "CLI tool for Socket.dev",
|
|
5
5
|
"homepage": "http://github.com/SocketDev/socket-cli-js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@npmcli/promise-spawn": "^8.0.1",
|
|
48
48
|
"@socketregistry/hyrious__bun.lockb": "1.0.0",
|
|
49
49
|
"@socketsecurity/config": "^2.1.3",
|
|
50
|
-
"@socketsecurity/registry": "^1.0.
|
|
50
|
+
"@socketsecurity/registry": "^1.0.8",
|
|
51
51
|
"@socketsecurity/sdk": "^1.3.0",
|
|
52
52
|
"ansi-align": "^3.0.1",
|
|
53
53
|
"blessed": "^0.1.81",
|