@penvhq/launcher 0.11.0 → 0.13.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/dist/bin.cjs +106 -45
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-USYQEKPW.js → chunk-QOQVOYJC.js} +117 -55
- package/dist/chunk-QOQVOYJC.js.map +1 -0
- package/dist/index.cjs +108 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -20
- package/dist/index.d.ts +28 -20
- package/dist/index.js +3 -3
- package/package.json +9 -3
- package/dist/chunk-USYQEKPW.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -160,7 +160,7 @@ var AddFlagError = class extends import_core.PenvError {
|
|
|
160
160
|
super(
|
|
161
161
|
"PENV_ADD_FLAG",
|
|
162
162
|
`\`penv add\` does not understand \`${flag}\``,
|
|
163
|
-
`Run \`penv add <package>\` with \`${TRUST_YOUNG_FLAG}\`, \`--registry <url>\`, or \`${
|
|
163
|
+
`Run \`penv add <package>\` with \`${TRUST_YOUNG_FLAG}\`, \`--registry <url>\`, \`${LOCAL_FLAG}\`, or \`${YES_FLAG}\` \u2014 those are the four it takes.`
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
166
|
};
|
|
@@ -306,13 +306,13 @@ var AddNoDownloadError = class extends import_core.PenvError {
|
|
|
306
306
|
);
|
|
307
307
|
}
|
|
308
308
|
};
|
|
309
|
-
var
|
|
310
|
-
name = "
|
|
311
|
-
constructor(name) {
|
|
309
|
+
var AddTrustUnattendedError = class extends import_core.PenvError {
|
|
310
|
+
name = "AddTrustUnattendedError";
|
|
311
|
+
constructor(name, ceremony) {
|
|
312
312
|
super(
|
|
313
|
-
"
|
|
314
|
-
`Adding ${name}
|
|
315
|
-
`Run \`${addCommand(name)}\` from a terminal
|
|
313
|
+
"PENV_ADD_TRUST_UNATTENDED",
|
|
314
|
+
`Adding ${name} records ${ceremony}, and this run has nobody to write it`,
|
|
315
|
+
`Run \`${addCommand(name)}\` from a terminal, without \`${YES_FLAG}\` \u2014 the trust block is a line only a person can write. In CI, run \`${INSTALL_COMMAND}\`: it installs the versions the committed manifest already pins.`
|
|
316
316
|
);
|
|
317
317
|
}
|
|
318
318
|
};
|
|
@@ -438,11 +438,11 @@ var UpgradeDeclinedError = class extends import_core.PenvError {
|
|
|
438
438
|
};
|
|
439
439
|
var UpgradeInstallFailedError = class extends import_core.PenvError {
|
|
440
440
|
name = "UpgradeInstallFailedError";
|
|
441
|
-
constructor(
|
|
441
|
+
constructor(manager, version) {
|
|
442
442
|
super(
|
|
443
443
|
"PENV_UPGRADE_INSTALL_FAILED",
|
|
444
|
-
`${
|
|
445
|
-
`
|
|
444
|
+
`${manager} did not finish moving this project to ${import_core.ENGINE_PACKAGE} ${version}, so ${import_core.MANIFEST_PATH} still pins the engine it pinned before`,
|
|
445
|
+
`Read what ${manager} printed above \u2014 it names what it refused. Fix that and run \`${UPGRADE_COMMAND} ${version}\` again; the pin and the dependency move together or not at all.`
|
|
446
446
|
);
|
|
447
447
|
}
|
|
448
448
|
};
|
|
@@ -1100,12 +1100,17 @@ function parseRequest(argv) {
|
|
|
1100
1100
|
let registry;
|
|
1101
1101
|
let trustYoung = false;
|
|
1102
1102
|
let local = false;
|
|
1103
|
+
let yes = false;
|
|
1103
1104
|
for (let index = 0; index < argv.length; index += 1) {
|
|
1104
1105
|
const token = argv[index] ?? "";
|
|
1105
1106
|
if (token === LOCAL_FLAG) {
|
|
1106
1107
|
local = true;
|
|
1107
1108
|
continue;
|
|
1108
1109
|
}
|
|
1110
|
+
if (token === YES_FLAG) {
|
|
1111
|
+
yes = true;
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1109
1114
|
if (token === TRUST_YOUNG_FLAG) {
|
|
1110
1115
|
trustYoung = true;
|
|
1111
1116
|
continue;
|
|
@@ -1145,7 +1150,10 @@ function parseRequest(argv) {
|
|
|
1145
1150
|
throw new AddLocalFlagError(`\`${TRUST_YOUNG_FLAG}\``);
|
|
1146
1151
|
}
|
|
1147
1152
|
}
|
|
1148
|
-
return { name, version, registry, trustYoung, local };
|
|
1153
|
+
return { name, version, registry, trustYoung, local, yes };
|
|
1154
|
+
}
|
|
1155
|
+
function ceremonyFor(tier) {
|
|
1156
|
+
return tier === "official" ? void 0 : "who publishes it and why you trust it";
|
|
1149
1157
|
}
|
|
1150
1158
|
function tierOf(request) {
|
|
1151
1159
|
if (request.name.startsWith(import_core6.OFFICIAL_SCOPE)) {
|
|
@@ -1224,46 +1232,84 @@ function recordExtension(manifestFile, name, entry) {
|
|
|
1224
1232
|
};
|
|
1225
1233
|
return (0, import_core6.serializeManifest)(next);
|
|
1226
1234
|
}
|
|
1227
|
-
|
|
1235
|
+
var NONE = /* @__PURE__ */ new Set(["", "none", "no", "n"]);
|
|
1236
|
+
var ALL = /* @__PURE__ */ new Set(["all", "a", "yes", "y"]);
|
|
1237
|
+
function chooseEnvironments(answer, offered) {
|
|
1238
|
+
const normalized = answer.trim().toLowerCase();
|
|
1239
|
+
if (NONE.has(normalized)) {
|
|
1240
|
+
return { chosen: [], unknown: [] };
|
|
1241
|
+
}
|
|
1242
|
+
if (ALL.has(normalized)) {
|
|
1243
|
+
return { chosen: offered, unknown: [] };
|
|
1244
|
+
}
|
|
1245
|
+
const chosen = [];
|
|
1246
|
+
const unknown = [];
|
|
1247
|
+
for (const token of normalized.split(/[\s,]+/).filter((part) => part !== "")) {
|
|
1248
|
+
const match = offered.find((environment) => environment.toLowerCase() === token);
|
|
1249
|
+
if (match === void 0) {
|
|
1250
|
+
unknown.push(token);
|
|
1251
|
+
} else {
|
|
1252
|
+
chosen.push(match);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
return { chosen, unknown };
|
|
1256
|
+
}
|
|
1257
|
+
function quoted(environments) {
|
|
1258
|
+
return environments.map((environment) => `\`${environment}\``).join(", ");
|
|
1259
|
+
}
|
|
1260
|
+
function configAdvice(name, pointing, unpointed) {
|
|
1261
|
+
const add2 = `Add \`type: ${JSON.stringify(name)}\``;
|
|
1262
|
+
if (pointing.length === 0) {
|
|
1263
|
+
return `${add2} to an environment in penv.config.ts.`;
|
|
1264
|
+
}
|
|
1265
|
+
return `${quoted(pointing)} already ${pointing.length === 1 ? "points" : "point"} at ${name}. ${add2} to ${quoted(unpointed)} in penv.config.ts if ${unpointed.length === 1 ? "it" : "they"} should too.`;
|
|
1266
|
+
}
|
|
1267
|
+
async function offerConfigEdit(options, name, ask) {
|
|
1228
1268
|
const { io: io2, root } = options;
|
|
1229
1269
|
const configFile = (0, import_core6.findConfigFile)(root);
|
|
1230
|
-
const
|
|
1270
|
+
const blind = `Add \`type: ${JSON.stringify(name)}\` to an environment in penv.config.ts.`;
|
|
1231
1271
|
if (configFile === void 0) {
|
|
1232
|
-
io2.out(
|
|
1272
|
+
io2.out(blind);
|
|
1233
1273
|
return;
|
|
1234
1274
|
}
|
|
1235
1275
|
const shown = (0, import_node_path5.relative)(root, configFile).split(import_node_path5.sep).join("/");
|
|
1236
1276
|
let current = (0, import_node_fs5.readFileSync)(configFile, "utf8");
|
|
1237
1277
|
const entries = readProviderEntries(current);
|
|
1238
1278
|
if (entries === void 0 || entries.length === 0) {
|
|
1239
|
-
io2.out(
|
|
1279
|
+
io2.out(blind);
|
|
1240
1280
|
return;
|
|
1241
1281
|
}
|
|
1242
|
-
|
|
1282
|
+
const pointing = entries.filter((entry) => entry.type === name).map((entry) => entry.environment);
|
|
1283
|
+
const offered = entries.filter((entry) => entry.type !== name).map((entry) => entry.environment);
|
|
1284
|
+
if (offered.length === 0) {
|
|
1243
1285
|
return;
|
|
1244
1286
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1287
|
+
const advice = configAdvice(name, pointing, offered);
|
|
1288
|
+
if (!ask) {
|
|
1289
|
+
io2.out(advice);
|
|
1247
1290
|
return;
|
|
1248
1291
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1292
|
+
const { chosen, unknown } = chooseEnvironments(
|
|
1293
|
+
await io2.ask(`Point which of ${offered.join(", ")} at ${name} in ${shown}? all / none / names`),
|
|
1294
|
+
offered
|
|
1295
|
+
);
|
|
1296
|
+
if (unknown.length > 0) {
|
|
1297
|
+
io2.out(`${shown} declares no ${unknown.join(", ")}, so nothing was repointed.`);
|
|
1298
|
+
io2.out(advice);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
for (const environment of chosen) {
|
|
1302
|
+
const next = setProviderType(current, environment, name);
|
|
1257
1303
|
if (next === void 0) {
|
|
1258
|
-
io2.out(`Add \`type: ${JSON.stringify(name)}\` to \`${
|
|
1304
|
+
io2.out(`Add \`type: ${JSON.stringify(name)}\` to \`${environment}\` in ${shown}.`);
|
|
1259
1305
|
continue;
|
|
1260
1306
|
}
|
|
1261
1307
|
current = next;
|
|
1262
1308
|
(0, import_node_fs5.writeFileSync)(configFile, current);
|
|
1263
|
-
io2.out(`\u2713 ${shown} points \`${
|
|
1309
|
+
io2.out(`\u2713 ${shown} points \`${environment}\` at ${name}`);
|
|
1264
1310
|
}
|
|
1265
1311
|
}
|
|
1266
|
-
async function offerOnboarding(io2, name, onboard) {
|
|
1312
|
+
async function offerOnboarding(io2, name, onboard, ask) {
|
|
1267
1313
|
if (onboard === void 0) {
|
|
1268
1314
|
return void 0;
|
|
1269
1315
|
}
|
|
@@ -1272,7 +1318,7 @@ async function offerOnboarding(io2, name, onboard) {
|
|
|
1272
1318
|
return void 0;
|
|
1273
1319
|
}
|
|
1274
1320
|
const command = `penv ${args.join(" ")}`;
|
|
1275
|
-
if (
|
|
1321
|
+
if (ask && await io2.confirm(`Run \`${command}\` now?`)) {
|
|
1276
1322
|
return args;
|
|
1277
1323
|
}
|
|
1278
1324
|
io2.out(`Run \`${command}\` to finish setting ${name} up.`);
|
|
@@ -1353,8 +1399,9 @@ async function addLocal(options, request) {
|
|
|
1353
1399
|
io2.out(`\u2713 ${request.name} resolves from this project and imports \u2014 nothing is pinned`);
|
|
1354
1400
|
io2.out(`\u2713 ${import_core6.LOCAL_EXTENSIONS_PATH} records it`);
|
|
1355
1401
|
io2.out(`\u2713 ${declaration} declares its config type`);
|
|
1356
|
-
|
|
1357
|
-
|
|
1402
|
+
const ask = io2.interactive && !request.yes;
|
|
1403
|
+
await offerConfigEdit(options, request.name, ask);
|
|
1404
|
+
return { onboard: await offerOnboarding(io2, request.name, installed.onboard, ask) };
|
|
1358
1405
|
}
|
|
1359
1406
|
async function add(options) {
|
|
1360
1407
|
const { io: io2, fetcher, home, root, manifestFile } = options;
|
|
@@ -1364,11 +1411,13 @@ async function add(options) {
|
|
|
1364
1411
|
}
|
|
1365
1412
|
const tier = tierOf(request);
|
|
1366
1413
|
const now = (options.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
1414
|
+
const ask = io2.interactive && !request.yes;
|
|
1367
1415
|
if (options.noDownload === true) {
|
|
1368
1416
|
throw new AddNoDownloadError(request.name);
|
|
1369
1417
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1418
|
+
const ceremony = ceremonyFor(tier);
|
|
1419
|
+
if (ceremony !== void 0 && (options.ci === true || !ask)) {
|
|
1420
|
+
throw new AddTrustUnattendedError(request.name, ceremony);
|
|
1372
1421
|
}
|
|
1373
1422
|
const release = await fetchRelease({
|
|
1374
1423
|
name: request.name,
|
|
@@ -1410,8 +1459,8 @@ async function add(options) {
|
|
|
1410
1459
|
io2.out(`\u2713 ${release.name} ${release.version} installed \u2014 ${provenance}`);
|
|
1411
1460
|
io2.out(`\u2713 ${import_core6.MANIFEST_PATH} pins it`);
|
|
1412
1461
|
io2.out(`\u2713 ${declaration} declares its config type`);
|
|
1413
|
-
await offerConfigEdit(options, release.name);
|
|
1414
|
-
return { onboard: await offerOnboarding(io2, release.name, installed.onboard) };
|
|
1462
|
+
await offerConfigEdit(options, release.name, ask);
|
|
1463
|
+
return { onboard: await offerOnboarding(io2, release.name, installed.onboard, ask) };
|
|
1415
1464
|
}
|
|
1416
1465
|
|
|
1417
1466
|
// src/help.ts
|
|
@@ -1442,10 +1491,15 @@ function printAddHelp(io2) {
|
|
|
1442
1491
|
io2.out(
|
|
1443
1492
|
` ${TRUST_YOUNG_FLAG} Add a release published less than ${MIN_PACKAGE_AGE_DAYS} days ago`
|
|
1444
1493
|
);
|
|
1494
|
+
io2.out(` ${YES_FLAG} Ask nothing \u2014 the config and onboarding offers print instead`);
|
|
1445
1495
|
io2.out("");
|
|
1446
1496
|
io2.out(`Pins the release in ${import_core7.MANIFEST_PATH} and writes its type declaration to`);
|
|
1447
1497
|
io2.out(`${import_core7.EXTENSIONS_PATH}/. Both are committed, so \`${INSTALL_COMMAND}\` gives every machine`);
|
|
1448
1498
|
io2.out(`the bytes you reviewed. \`${LOCAL_FLAG}\` pins nothing and touches no manifest.`);
|
|
1499
|
+
io2.out("");
|
|
1500
|
+
io2.out(`An \`${import_core7.OFFICIAL_SCOPE}*\` package asks nothing, so it adds unattended. Anything else`);
|
|
1501
|
+
io2.out("records who publishes it and why you trust it, which needs a person at a terminal \u2014");
|
|
1502
|
+
io2.out(`\`${YES_FLAG}\` cannot write that line for you.`);
|
|
1449
1503
|
}
|
|
1450
1504
|
function printUpgradeHelp(io2) {
|
|
1451
1505
|
io2.out("penv upgrade [version]");
|
|
@@ -1465,8 +1519,8 @@ var DEV_PIN_INTEGRITY = "sha512-development-build-not-a-published-release";
|
|
|
1465
1519
|
var DEV_PIN_VERSION = "0.0.0-dev";
|
|
1466
1520
|
var BUNDLED_ENGINE_PIN = {
|
|
1467
1521
|
package: import_core8.ENGINE_PACKAGE,
|
|
1468
|
-
version: "0.
|
|
1469
|
-
integrity: "sha512-
|
|
1522
|
+
version: "0.13.0",
|
|
1523
|
+
integrity: "sha512-gZ2AlzxmQ4c83OvWSRrBdVMAQdwcGqAoENSv4ZNyZuer0fpIEqiT/xUl2b1+t5JSW8EZto5JpilmBSfiNoWFWA=="
|
|
1470
1524
|
};
|
|
1471
1525
|
function assertReleasePin(pin) {
|
|
1472
1526
|
if (pin.integrity === DEV_PIN_INTEGRITY || pin.version === DEV_PIN_VERSION) {
|
|
@@ -1594,9 +1648,14 @@ async function upgrade(options) {
|
|
|
1594
1648
|
try {
|
|
1595
1649
|
await (options.install ?? import_install2.installWithPackageManager)(plan);
|
|
1596
1650
|
} catch {
|
|
1597
|
-
throw new UpgradeInstallFailedError(plan.
|
|
1651
|
+
throw new UpgradeInstallFailedError(plan.manager, release.version);
|
|
1652
|
+
}
|
|
1653
|
+
const moved = plan.steps.filter(
|
|
1654
|
+
(entry) => !entry.satisfied && entry.packages.some((one) => one.name === import_install2.RUNTIME_PACKAGE)
|
|
1655
|
+
);
|
|
1656
|
+
for (const step of moved) {
|
|
1657
|
+
io2.out(`\u2713 ${step.manifest} depends on ${import_install2.RUNTIME_PACKAGE} ${release.version}`);
|
|
1598
1658
|
}
|
|
1599
|
-
io2.out(`\u2713 package.json depends on ${import_install2.RUNTIME_PACKAGE} ${release.version}`);
|
|
1600
1659
|
}
|
|
1601
1660
|
(0, import_node_fs7.writeFileSync)(manifestFile, manifestText);
|
|
1602
1661
|
io2.out(`\u2713 ${import_core10.MANIFEST_PATH} pins ${import_core10.ENGINE_PACKAGE} ${release.version}`);
|
|
@@ -1825,12 +1884,14 @@ async function install(options, pins, home, broken) {
|
|
|
1825
1884
|
if (state === "corrupt") {
|
|
1826
1885
|
throw new PackageCorruptError(pin.name, pin.version, dir);
|
|
1827
1886
|
}
|
|
1828
|
-
if (state === "
|
|
1829
|
-
|
|
1830
|
-
|
|
1887
|
+
if (state === "absent") {
|
|
1888
|
+
await installPin({ home, kind, pin, fetcher: options.fetcher });
|
|
1889
|
+
}
|
|
1890
|
+
if (kind === "extensions") {
|
|
1891
|
+
await assertLoadable(pin.name, (0, import_core11.packageEntry)(dir), false);
|
|
1831
1892
|
}
|
|
1832
|
-
|
|
1833
|
-
options.io.out(`\u2713 ${pin.name} ${pin.version}
|
|
1893
|
+
const verb = state === "absent" ? "installed" : "already installed";
|
|
1894
|
+
options.io.out(`\u2713 ${pin.name} ${pin.version} ${verb}`);
|
|
1834
1895
|
}
|
|
1835
1896
|
if (broken.length > 0) {
|
|
1836
1897
|
report(new ManifestEntriesUnreadableError(broken), options.io);
|