@penvhq/launcher 0.10.0 → 0.12.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 +298 -56
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-BNUZ52VN.js → chunk-A5LJQPYS.js} +319 -62
- package/dist/chunk-A5LJQPYS.js.map +1 -0
- package/dist/index.cjs +318 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +128 -18
- package/dist/index.d.ts +128 -18
- package/dist/index.js +21 -3
- package/package.json +9 -3
- package/dist/chunk-BNUZ52VN.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -53,6 +53,8 @@ var import_core2 = require("@penvhq/core");
|
|
|
53
53
|
// src/errors.ts
|
|
54
54
|
var import_core = require("@penvhq/core");
|
|
55
55
|
var INSTALL_COMMAND = "penv install";
|
|
56
|
+
var UPGRADE_COMMAND = "penv upgrade";
|
|
57
|
+
var YES_FLAG = "--yes";
|
|
56
58
|
var MIN_PACKAGE_AGE_DAYS = 7;
|
|
57
59
|
var TRUST_YOUNG_FLAG = "--trust-young";
|
|
58
60
|
function addCommand(name, version, extra) {
|
|
@@ -158,7 +160,7 @@ var AddFlagError = class extends import_core.PenvError {
|
|
|
158
160
|
super(
|
|
159
161
|
"PENV_ADD_FLAG",
|
|
160
162
|
`\`penv add\` does not understand \`${flag}\``,
|
|
161
|
-
`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.`
|
|
162
164
|
);
|
|
163
165
|
}
|
|
164
166
|
};
|
|
@@ -235,11 +237,11 @@ var OfficialRegistryError = class extends import_core.PenvError {
|
|
|
235
237
|
};
|
|
236
238
|
var RegistryUnreadableError = class extends import_core.PenvError {
|
|
237
239
|
name = "RegistryUnreadableError";
|
|
238
|
-
constructor(name, url, detail) {
|
|
240
|
+
constructor(name, url, detail, retry = addCommand(name)) {
|
|
239
241
|
super(
|
|
240
242
|
"PENV_REGISTRY_UNREADABLE",
|
|
241
243
|
`Reading ${name} from ${url} failed: ${detail}`,
|
|
242
|
-
`Run \`${
|
|
244
|
+
`Run \`${retry}\` again when the registry is reachable.`
|
|
243
245
|
);
|
|
244
246
|
}
|
|
245
247
|
};
|
|
@@ -255,11 +257,11 @@ var PackageUnknownError = class extends import_core.PenvError {
|
|
|
255
257
|
};
|
|
256
258
|
var VersionUnknownError = class extends import_core.PenvError {
|
|
257
259
|
name = "VersionUnknownError";
|
|
258
|
-
constructor(name, version, url) {
|
|
260
|
+
constructor(name, version, url, retry = addCommand(name)) {
|
|
259
261
|
super(
|
|
260
262
|
"PENV_VERSION_UNKNOWN",
|
|
261
263
|
`${url} publishes no ${version} of ${name}`,
|
|
262
|
-
`Run \`${
|
|
264
|
+
`Run \`${retry}\` to take the version \`latest\` points at.`
|
|
263
265
|
);
|
|
264
266
|
}
|
|
265
267
|
};
|
|
@@ -304,13 +306,13 @@ var AddNoDownloadError = class extends import_core.PenvError {
|
|
|
304
306
|
);
|
|
305
307
|
}
|
|
306
308
|
};
|
|
307
|
-
var
|
|
308
|
-
name = "
|
|
309
|
-
constructor(name) {
|
|
309
|
+
var AddTrustUnattendedError = class extends import_core.PenvError {
|
|
310
|
+
name = "AddTrustUnattendedError";
|
|
311
|
+
constructor(name, ceremony) {
|
|
310
312
|
super(
|
|
311
|
-
"
|
|
312
|
-
`Adding ${name}
|
|
313
|
-
`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.`
|
|
314
316
|
);
|
|
315
317
|
}
|
|
316
318
|
};
|
|
@@ -384,6 +386,66 @@ var EnginePinMismatchError = class extends import_core.PenvError {
|
|
|
384
386
|
);
|
|
385
387
|
}
|
|
386
388
|
};
|
|
389
|
+
var UpgradeSubjectError = class extends import_core.PenvError {
|
|
390
|
+
name = "UpgradeSubjectError";
|
|
391
|
+
constructor() {
|
|
392
|
+
super(
|
|
393
|
+
"PENV_UPGRADE_SUBJECT",
|
|
394
|
+
"`penv upgrade` takes one version, or none",
|
|
395
|
+
`Run \`${UPGRADE_COMMAND}\` to move to whatever \`latest\` points at, or \`${UPGRADE_COMMAND} 0.9.6\` to move to an exact release.`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
var UpgradeFlagError = class extends import_core.PenvError {
|
|
400
|
+
name = "UpgradeFlagError";
|
|
401
|
+
constructor(flag) {
|
|
402
|
+
super(
|
|
403
|
+
"PENV_UPGRADE_FLAG",
|
|
404
|
+
`\`${UPGRADE_COMMAND}\` does not understand \`${flag}\``,
|
|
405
|
+
`Run \`${UPGRADE_COMMAND} [version]\` with \`${YES_FLAG}\` \u2014 that is the one flag it takes.`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
var UpgradeNoDownloadError = class extends import_core.PenvError {
|
|
410
|
+
name = "UpgradeNoDownloadError";
|
|
411
|
+
constructor() {
|
|
412
|
+
super(
|
|
413
|
+
"PENV_UPGRADE_NO_DOWNLOAD",
|
|
414
|
+
`Upgrading means reading the registry for the version and integrity to pin, and \`--no-download\` says this run does not`,
|
|
415
|
+
`Run \`${UPGRADE_COMMAND}\` without \`--no-download\`. Nothing was fetched or written.`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
var UpgradeUnattendedError = class extends import_core.PenvError {
|
|
420
|
+
name = "UpgradeUnattendedError";
|
|
421
|
+
constructor() {
|
|
422
|
+
super(
|
|
423
|
+
"PENV_UPGRADE_UNATTENDED",
|
|
424
|
+
`Upgrading rewrites ${import_core.MANIFEST_PATH} and package.json, and this run has nobody to decide that`,
|
|
425
|
+
`Run \`${UPGRADE_COMMAND} <version> ${YES_FLAG}\` \u2014 unattended, penv moves the pin only to a version you named. In CI, run \`${INSTALL_COMMAND}\`: it installs what the committed manifest already pins.`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
var UpgradeDeclinedError = class extends import_core.PenvError {
|
|
430
|
+
name = "UpgradeDeclinedError";
|
|
431
|
+
constructor(version) {
|
|
432
|
+
super(
|
|
433
|
+
"PENV_UPGRADE_DECLINED",
|
|
434
|
+
`${import_core.ENGINE_PACKAGE} ${version} was not installed, so ${import_core.MANIFEST_PATH} and package.json are unchanged`,
|
|
435
|
+
`Run \`${UPGRADE_COMMAND} ${version}\` again when you want both of them to move.`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
var UpgradeInstallFailedError = class extends import_core.PenvError {
|
|
440
|
+
name = "UpgradeInstallFailedError";
|
|
441
|
+
constructor(manager, version) {
|
|
442
|
+
super(
|
|
443
|
+
"PENV_UPGRADE_INSTALL_FAILED",
|
|
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
|
+
);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
387
449
|
var EngineEntryError = class extends import_core.PenvError {
|
|
388
450
|
name = "EngineEntryError";
|
|
389
451
|
constructor(name, version, dir) {
|
|
@@ -460,9 +522,9 @@ function httpFetcher() {
|
|
|
460
522
|
}
|
|
461
523
|
|
|
462
524
|
// src/launcher.ts
|
|
463
|
-
var
|
|
525
|
+
var import_node_fs8 = require("fs");
|
|
464
526
|
var import_node_path7 = require("path");
|
|
465
|
-
var
|
|
527
|
+
var import_core11 = require("@penvhq/core");
|
|
466
528
|
|
|
467
529
|
// src/add.ts
|
|
468
530
|
var import_node_fs5 = require("fs");
|
|
@@ -926,7 +988,8 @@ async function fetchRelease(query) {
|
|
|
926
988
|
throw new RegistryUnreadableError(
|
|
927
989
|
query.name,
|
|
928
990
|
url,
|
|
929
|
-
cause instanceof Error ? cause.message : String(cause)
|
|
991
|
+
cause instanceof Error ? cause.message : String(cause),
|
|
992
|
+
query.retry
|
|
930
993
|
);
|
|
931
994
|
}
|
|
932
995
|
let parsed;
|
|
@@ -936,7 +999,8 @@ async function fetchRelease(query) {
|
|
|
936
999
|
throw new RegistryUnreadableError(
|
|
937
1000
|
query.name,
|
|
938
1001
|
url,
|
|
939
|
-
cause instanceof Error ? cause.message : String(cause)
|
|
1002
|
+
cause instanceof Error ? cause.message : String(cause),
|
|
1003
|
+
query.retry
|
|
940
1004
|
);
|
|
941
1005
|
}
|
|
942
1006
|
const packument = record(parsed);
|
|
@@ -952,7 +1016,7 @@ async function fetchRelease(query) {
|
|
|
952
1016
|
const version = record(at(versions, asked)) === void 0 ? text3(at(tags, asked)) ?? asked : asked;
|
|
953
1017
|
const release = record(at(versions, version));
|
|
954
1018
|
if (release === void 0) {
|
|
955
|
-
throw new VersionUnknownError(query.name, asked, url);
|
|
1019
|
+
throw new VersionUnknownError(query.name, asked, url, query.retry);
|
|
956
1020
|
}
|
|
957
1021
|
const dist = record(at(release, "dist"));
|
|
958
1022
|
const integrity = text3(at(dist, "integrity"));
|
|
@@ -1036,12 +1100,17 @@ function parseRequest(argv) {
|
|
|
1036
1100
|
let registry;
|
|
1037
1101
|
let trustYoung = false;
|
|
1038
1102
|
let local = false;
|
|
1103
|
+
let yes = false;
|
|
1039
1104
|
for (let index = 0; index < argv.length; index += 1) {
|
|
1040
1105
|
const token = argv[index] ?? "";
|
|
1041
1106
|
if (token === LOCAL_FLAG) {
|
|
1042
1107
|
local = true;
|
|
1043
1108
|
continue;
|
|
1044
1109
|
}
|
|
1110
|
+
if (token === YES_FLAG) {
|
|
1111
|
+
yes = true;
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1045
1114
|
if (token === TRUST_YOUNG_FLAG) {
|
|
1046
1115
|
trustYoung = true;
|
|
1047
1116
|
continue;
|
|
@@ -1081,7 +1150,10 @@ function parseRequest(argv) {
|
|
|
1081
1150
|
throw new AddLocalFlagError(`\`${TRUST_YOUNG_FLAG}\``);
|
|
1082
1151
|
}
|
|
1083
1152
|
}
|
|
1084
|
-
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";
|
|
1085
1157
|
}
|
|
1086
1158
|
function tierOf(request) {
|
|
1087
1159
|
if (request.name.startsWith(import_core6.OFFICIAL_SCOPE)) {
|
|
@@ -1160,7 +1232,29 @@ function recordExtension(manifestFile, name, entry) {
|
|
|
1160
1232
|
};
|
|
1161
1233
|
return (0, import_core6.serializeManifest)(next);
|
|
1162
1234
|
}
|
|
1163
|
-
|
|
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
|
+
async function offerConfigEdit(options, name, ask) {
|
|
1164
1258
|
const { io: io2, root } = options;
|
|
1165
1259
|
const configFile = (0, import_core6.findConfigFile)(root);
|
|
1166
1260
|
const line = `Add \`type: ${JSON.stringify(name)}\` to an environment in penv.config.ts.`;
|
|
@@ -1175,31 +1269,35 @@ async function offerConfigEdit(options, name) {
|
|
|
1175
1269
|
io2.out(line);
|
|
1176
1270
|
return;
|
|
1177
1271
|
}
|
|
1178
|
-
|
|
1272
|
+
const offered = entries.filter((entry) => entry.type !== name).map((entry) => entry.environment);
|
|
1273
|
+
if (offered.length === 0) {
|
|
1179
1274
|
return;
|
|
1180
1275
|
}
|
|
1181
|
-
if (!
|
|
1276
|
+
if (!ask) {
|
|
1182
1277
|
io2.out(line);
|
|
1183
1278
|
return;
|
|
1184
1279
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1280
|
+
const { chosen, unknown } = chooseEnvironments(
|
|
1281
|
+
await io2.ask(`Point which of ${offered.join(", ")} at ${name} in ${shown}? all / none / names`),
|
|
1282
|
+
offered
|
|
1283
|
+
);
|
|
1284
|
+
if (unknown.length > 0) {
|
|
1285
|
+
io2.out(`${shown} declares no ${unknown.join(", ")}, so nothing was repointed.`);
|
|
1286
|
+
io2.out(line);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
for (const environment of chosen) {
|
|
1290
|
+
const next = setProviderType(current, environment, name);
|
|
1193
1291
|
if (next === void 0) {
|
|
1194
|
-
io2.out(`Add \`type: ${JSON.stringify(name)}\` to \`${
|
|
1292
|
+
io2.out(`Add \`type: ${JSON.stringify(name)}\` to \`${environment}\` in ${shown}.`);
|
|
1195
1293
|
continue;
|
|
1196
1294
|
}
|
|
1197
1295
|
current = next;
|
|
1198
1296
|
(0, import_node_fs5.writeFileSync)(configFile, current);
|
|
1199
|
-
io2.out(`\u2713 ${shown} points \`${
|
|
1297
|
+
io2.out(`\u2713 ${shown} points \`${environment}\` at ${name}`);
|
|
1200
1298
|
}
|
|
1201
1299
|
}
|
|
1202
|
-
async function offerOnboarding(io2, name, onboard) {
|
|
1300
|
+
async function offerOnboarding(io2, name, onboard, ask) {
|
|
1203
1301
|
if (onboard === void 0) {
|
|
1204
1302
|
return void 0;
|
|
1205
1303
|
}
|
|
@@ -1208,7 +1306,7 @@ async function offerOnboarding(io2, name, onboard) {
|
|
|
1208
1306
|
return void 0;
|
|
1209
1307
|
}
|
|
1210
1308
|
const command = `penv ${args.join(" ")}`;
|
|
1211
|
-
if (
|
|
1309
|
+
if (ask && await io2.confirm(`Run \`${command}\` now?`)) {
|
|
1212
1310
|
return args;
|
|
1213
1311
|
}
|
|
1214
1312
|
io2.out(`Run \`${command}\` to finish setting ${name} up.`);
|
|
@@ -1289,8 +1387,9 @@ async function addLocal(options, request) {
|
|
|
1289
1387
|
io2.out(`\u2713 ${request.name} resolves from this project and imports \u2014 nothing is pinned`);
|
|
1290
1388
|
io2.out(`\u2713 ${import_core6.LOCAL_EXTENSIONS_PATH} records it`);
|
|
1291
1389
|
io2.out(`\u2713 ${declaration} declares its config type`);
|
|
1292
|
-
|
|
1293
|
-
|
|
1390
|
+
const ask = io2.interactive && !request.yes;
|
|
1391
|
+
await offerConfigEdit(options, request.name, ask);
|
|
1392
|
+
return { onboard: await offerOnboarding(io2, request.name, installed.onboard, ask) };
|
|
1294
1393
|
}
|
|
1295
1394
|
async function add(options) {
|
|
1296
1395
|
const { io: io2, fetcher, home, root, manifestFile } = options;
|
|
@@ -1300,11 +1399,13 @@ async function add(options) {
|
|
|
1300
1399
|
}
|
|
1301
1400
|
const tier = tierOf(request);
|
|
1302
1401
|
const now = (options.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
1402
|
+
const ask = io2.interactive && !request.yes;
|
|
1303
1403
|
if (options.noDownload === true) {
|
|
1304
1404
|
throw new AddNoDownloadError(request.name);
|
|
1305
1405
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1406
|
+
const ceremony = ceremonyFor(tier);
|
|
1407
|
+
if (ceremony !== void 0 && (options.ci === true || !ask)) {
|
|
1408
|
+
throw new AddTrustUnattendedError(request.name, ceremony);
|
|
1308
1409
|
}
|
|
1309
1410
|
const release = await fetchRelease({
|
|
1310
1411
|
name: request.name,
|
|
@@ -1346,11 +1447,12 @@ async function add(options) {
|
|
|
1346
1447
|
io2.out(`\u2713 ${release.name} ${release.version} installed \u2014 ${provenance}`);
|
|
1347
1448
|
io2.out(`\u2713 ${import_core6.MANIFEST_PATH} pins it`);
|
|
1348
1449
|
io2.out(`\u2713 ${declaration} declares its config type`);
|
|
1349
|
-
await offerConfigEdit(options, release.name);
|
|
1350
|
-
return { onboard: await offerOnboarding(io2, release.name, installed.onboard) };
|
|
1450
|
+
await offerConfigEdit(options, release.name, ask);
|
|
1451
|
+
return { onboard: await offerOnboarding(io2, release.name, installed.onboard, ask) };
|
|
1351
1452
|
}
|
|
1352
1453
|
|
|
1353
1454
|
// src/help.ts
|
|
1455
|
+
var import_install = require("@penvhq/cli/install");
|
|
1354
1456
|
var import_core7 = require("@penvhq/core");
|
|
1355
1457
|
function printLauncherCommands(io2) {
|
|
1356
1458
|
io2.out("");
|
|
@@ -1359,6 +1461,7 @@ function printLauncherCommands(io2) {
|
|
|
1359
1461
|
io2.out(` install Installs everything ${import_core7.MANIFEST_PATH} pins`);
|
|
1360
1462
|
io2.out(" add <package> Pins a provider extension, and commits the decision");
|
|
1361
1463
|
io2.out(` add ${LOCAL_FLAG} <package> Adds the one this repository builds \u2014 nothing is pinned`);
|
|
1464
|
+
io2.out(` upgrade [version] Moves the engine pin and ${import_install.RUNTIME_PACKAGE} together`);
|
|
1362
1465
|
io2.out("");
|
|
1363
1466
|
}
|
|
1364
1467
|
function printInstallHelp(io2) {
|
|
@@ -1376,10 +1479,26 @@ function printAddHelp(io2) {
|
|
|
1376
1479
|
io2.out(
|
|
1377
1480
|
` ${TRUST_YOUNG_FLAG} Add a release published less than ${MIN_PACKAGE_AGE_DAYS} days ago`
|
|
1378
1481
|
);
|
|
1482
|
+
io2.out(` ${YES_FLAG} Ask nothing \u2014 the config and onboarding offers print instead`);
|
|
1379
1483
|
io2.out("");
|
|
1380
1484
|
io2.out(`Pins the release in ${import_core7.MANIFEST_PATH} and writes its type declaration to`);
|
|
1381
1485
|
io2.out(`${import_core7.EXTENSIONS_PATH}/. Both are committed, so \`${INSTALL_COMMAND}\` gives every machine`);
|
|
1382
1486
|
io2.out(`the bytes you reviewed. \`${LOCAL_FLAG}\` pins nothing and touches no manifest.`);
|
|
1487
|
+
io2.out("");
|
|
1488
|
+
io2.out(`An \`${import_core7.OFFICIAL_SCOPE}*\` package asks nothing, so it adds unattended. Anything else`);
|
|
1489
|
+
io2.out("records who publishes it and why you trust it, which needs a person at a terminal \u2014");
|
|
1490
|
+
io2.out(`\`${YES_FLAG}\` cannot write that line for you.`);
|
|
1491
|
+
}
|
|
1492
|
+
function printUpgradeHelp(io2) {
|
|
1493
|
+
io2.out("penv upgrade [version]");
|
|
1494
|
+
io2.out("");
|
|
1495
|
+
io2.out(` ${YES_FLAG} Skip the question \u2014 unattended runs need it and a version`);
|
|
1496
|
+
io2.out("");
|
|
1497
|
+
io2.out(`Moves the ${import_core7.ENGINE_PACKAGE} pin in ${import_core7.MANIFEST_PATH} and this project's`);
|
|
1498
|
+
io2.out(`${import_install.RUNTIME_PACKAGE} dependency to the same exact version. No version takes whatever`);
|
|
1499
|
+
io2.out("`latest` points at; the integrity is the one the registry states, never one penv");
|
|
1500
|
+
io2.out("computed. Both files are shown before either moves, and they move together or not");
|
|
1501
|
+
io2.out("at all. Extensions keep their own pins.");
|
|
1383
1502
|
}
|
|
1384
1503
|
|
|
1385
1504
|
// src/pins.ts
|
|
@@ -1388,8 +1507,8 @@ var DEV_PIN_INTEGRITY = "sha512-development-build-not-a-published-release";
|
|
|
1388
1507
|
var DEV_PIN_VERSION = "0.0.0-dev";
|
|
1389
1508
|
var BUNDLED_ENGINE_PIN = {
|
|
1390
1509
|
package: import_core8.ENGINE_PACKAGE,
|
|
1391
|
-
version: "0.
|
|
1392
|
-
integrity: "sha512-
|
|
1510
|
+
version: "0.12.0",
|
|
1511
|
+
integrity: "sha512-9HUylEIbFq0BGTOW54Vxhkzv8AvuB7H3bImTFP5J+dfglkR7udP2KUsr8b0I2mf45YMTQO5xsYpI5+nhLERGtA=="
|
|
1393
1512
|
};
|
|
1394
1513
|
function assertReleasePin(pin) {
|
|
1395
1514
|
if (pin.integrity === DEV_PIN_INTEGRITY || pin.version === DEV_PIN_VERSION) {
|
|
@@ -1430,9 +1549,112 @@ function findAdoptedRoot(cwd) {
|
|
|
1430
1549
|
return findUp(cwd, (dir) => (0, import_node_fs6.existsSync)((0, import_core9.stateDir)(dir)));
|
|
1431
1550
|
}
|
|
1432
1551
|
|
|
1552
|
+
// src/upgrade.ts
|
|
1553
|
+
var import_node_fs7 = require("fs");
|
|
1554
|
+
var import_install2 = require("@penvhq/cli/install");
|
|
1555
|
+
var import_core10 = require("@penvhq/core");
|
|
1556
|
+
function parseRequest2(argv) {
|
|
1557
|
+
let version;
|
|
1558
|
+
let yes = false;
|
|
1559
|
+
for (const token of argv) {
|
|
1560
|
+
if (token === YES_FLAG) {
|
|
1561
|
+
yes = true;
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
if (token.startsWith("-")) {
|
|
1565
|
+
throw new UpgradeFlagError(token);
|
|
1566
|
+
}
|
|
1567
|
+
if (version !== void 0 || token === "") {
|
|
1568
|
+
throw new UpgradeSubjectError();
|
|
1569
|
+
}
|
|
1570
|
+
version = token;
|
|
1571
|
+
}
|
|
1572
|
+
return { version, yes };
|
|
1573
|
+
}
|
|
1574
|
+
function renderPinChange(engine, release) {
|
|
1575
|
+
return [
|
|
1576
|
+
import_core10.MANIFEST_PATH,
|
|
1577
|
+
` - "integrity": "${engine.integrity}"`,
|
|
1578
|
+
` - "version": "${engine.version}"`,
|
|
1579
|
+
` + "integrity": "${release.integrity}"`,
|
|
1580
|
+
` + "version": "${release.version}"`
|
|
1581
|
+
];
|
|
1582
|
+
}
|
|
1583
|
+
function pinnedElsewhere(manifest, version) {
|
|
1584
|
+
return Object.entries(manifest.extensions).filter(([, entry]) => entry.version !== version).map(([name]) => name);
|
|
1585
|
+
}
|
|
1586
|
+
async function consent(options, release, plan, yes) {
|
|
1587
|
+
const { io: io2, manifest } = options;
|
|
1588
|
+
io2.out(`${import_core10.ENGINE_PACKAGE} ${manifest.engine.version} \u2192 ${release.version}`);
|
|
1589
|
+
io2.out("");
|
|
1590
|
+
for (const line of renderPinChange(manifest.engine, release)) {
|
|
1591
|
+
io2.out(line);
|
|
1592
|
+
}
|
|
1593
|
+
for (const line of (0, import_install2.renderInstallPlan)(plan)) {
|
|
1594
|
+
io2.out(line);
|
|
1595
|
+
}
|
|
1596
|
+
if (yes) {
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
if (!await io2.confirm(`Move this project to ${release.version}?`)) {
|
|
1600
|
+
throw new UpgradeDeclinedError(release.version);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
async function upgrade(options) {
|
|
1604
|
+
const { io: io2, fetcher, home, root, manifest, manifestFile } = options;
|
|
1605
|
+
const request = parseRequest2(options.argv);
|
|
1606
|
+
if (options.noDownload === true) {
|
|
1607
|
+
throw new UpgradeNoDownloadError();
|
|
1608
|
+
}
|
|
1609
|
+
if ((options.ci === true || !io2.interactive) && !(request.yes && request.version !== void 0)) {
|
|
1610
|
+
throw new UpgradeUnattendedError();
|
|
1611
|
+
}
|
|
1612
|
+
const release = await fetchRelease({
|
|
1613
|
+
name: import_core10.ENGINE_PACKAGE,
|
|
1614
|
+
...request.version === void 0 ? {} : { version: request.version },
|
|
1615
|
+
retry: UPGRADE_COMMAND,
|
|
1616
|
+
fetcher
|
|
1617
|
+
});
|
|
1618
|
+
const plan = (0, import_install2.planInstall)(root, release.version);
|
|
1619
|
+
if (manifest.engine.version === release.version && plan.satisfied) {
|
|
1620
|
+
io2.out(`\u2713 Already on ${import_core10.ENGINE_PACKAGE} ${release.version} \u2014 nothing to move`);
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
const manifestText = (0, import_core10.serializeManifest)({
|
|
1624
|
+
...manifest,
|
|
1625
|
+
engine: { package: import_core10.ENGINE_PACKAGE, version: release.version, integrity: release.integrity }
|
|
1626
|
+
});
|
|
1627
|
+
await consent(options, release, plan, request.yes);
|
|
1628
|
+
await installPin({
|
|
1629
|
+
home,
|
|
1630
|
+
kind: "engines",
|
|
1631
|
+
pin: { name: import_core10.ENGINE_PACKAGE, version: release.version, integrity: release.integrity },
|
|
1632
|
+
fetcher
|
|
1633
|
+
});
|
|
1634
|
+
io2.out(`\u2713 ${import_core10.ENGINE_PACKAGE} ${release.version} installed`);
|
|
1635
|
+
if (!plan.satisfied) {
|
|
1636
|
+
try {
|
|
1637
|
+
await (options.install ?? import_install2.installWithPackageManager)(plan);
|
|
1638
|
+
} catch {
|
|
1639
|
+
throw new UpgradeInstallFailedError(plan.manager, release.version);
|
|
1640
|
+
}
|
|
1641
|
+
for (const step of plan.steps.filter((entry) => !entry.satisfied)) {
|
|
1642
|
+
io2.out(`\u2713 ${step.manifest} depends on ${import_install2.RUNTIME_PACKAGE} ${release.version}`);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
(0, import_node_fs7.writeFileSync)(manifestFile, manifestText);
|
|
1646
|
+
io2.out(`\u2713 ${import_core10.MANIFEST_PATH} pins ${import_core10.ENGINE_PACKAGE} ${release.version}`);
|
|
1647
|
+
const kept = pinnedElsewhere(manifest, release.version);
|
|
1648
|
+
if (kept.length > 0) {
|
|
1649
|
+
const subject = kept.length === 1 ? "keeps its own pin" : "keep their own pins";
|
|
1650
|
+
io2.out(`\u2192 ${kept.join(", ")} ${subject} \u2014 \`penv add <package>@<version>\` moves one.`);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1433
1654
|
// src/launcher.ts
|
|
1434
1655
|
var INSTALL = "install";
|
|
1435
1656
|
var ADD = "add";
|
|
1657
|
+
var UPGRADE = "upgrade";
|
|
1436
1658
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["--version", "-v"]);
|
|
1437
1659
|
var HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
|
|
1438
1660
|
var NO_DOWNLOAD = "--no-download";
|
|
@@ -1476,27 +1698,27 @@ function pinsOf(manifest) {
|
|
|
1476
1698
|
];
|
|
1477
1699
|
}
|
|
1478
1700
|
function reportable(error, home, argv) {
|
|
1479
|
-
return error instanceof
|
|
1701
|
+
return error instanceof import_core11.UnsupportedManifestFormatError ? error.withLauncherUpdate({
|
|
1480
1702
|
updateCommand: launcherUpdateCommand(home),
|
|
1481
1703
|
invokedCommand: invokedCommand(argv)
|
|
1482
1704
|
}) : error;
|
|
1483
1705
|
}
|
|
1484
1706
|
function readManifest(manifestFile, home, argv) {
|
|
1485
1707
|
try {
|
|
1486
|
-
return (0,
|
|
1708
|
+
return (0, import_core11.parseManifest)((0, import_node_fs8.readFileSync)(manifestFile, "utf8"));
|
|
1487
1709
|
} catch (error) {
|
|
1488
1710
|
throw reportable(error, home, argv);
|
|
1489
1711
|
}
|
|
1490
1712
|
}
|
|
1491
1713
|
function readManifestToRepair(manifestFile, home, argv) {
|
|
1492
1714
|
try {
|
|
1493
|
-
return readManifestForRepair((0,
|
|
1715
|
+
return readManifestForRepair((0, import_node_fs8.readFileSync)(manifestFile, "utf8"));
|
|
1494
1716
|
} catch (error) {
|
|
1495
1717
|
throw reportable(error, home, argv);
|
|
1496
1718
|
}
|
|
1497
1719
|
}
|
|
1498
1720
|
function report(error, io2) {
|
|
1499
|
-
if (error instanceof
|
|
1721
|
+
if (error instanceof import_core11.PenvError && error.remedy !== void 0) {
|
|
1500
1722
|
const suffix = `
|
|
1501
1723
|
${error.remedy}`;
|
|
1502
1724
|
const message = error.message.endsWith(suffix) ? error.message.slice(0, -suffix.length) : error.message;
|
|
@@ -1518,7 +1740,7 @@ async function launch(options) {
|
|
|
1518
1740
|
const { argv, cwd, env, io: io2 } = options;
|
|
1519
1741
|
const { noDownload, forwarded } = splitLauncherFlags(argv);
|
|
1520
1742
|
const first = forwarded[0];
|
|
1521
|
-
const home = (0,
|
|
1743
|
+
const home = (0, import_core11.penvHome)(env);
|
|
1522
1744
|
if (first !== void 0 && forwarded.slice(1).some((token) => HELP_FLAGS.has(token))) {
|
|
1523
1745
|
if (first === INSTALL) {
|
|
1524
1746
|
printInstallHelp(io2);
|
|
@@ -1528,6 +1750,10 @@ async function launch(options) {
|
|
|
1528
1750
|
printAddHelp(io2);
|
|
1529
1751
|
return 0;
|
|
1530
1752
|
}
|
|
1753
|
+
if (first === UPGRADE) {
|
|
1754
|
+
printUpgradeHelp(io2);
|
|
1755
|
+
return 0;
|
|
1756
|
+
}
|
|
1531
1757
|
}
|
|
1532
1758
|
const project = findProject(cwd);
|
|
1533
1759
|
if (project === void 0) {
|
|
@@ -1555,6 +1781,20 @@ async function launch(options) {
|
|
|
1555
1781
|
io2.out(`penv ${manifest.engine.version}`);
|
|
1556
1782
|
return 0;
|
|
1557
1783
|
}
|
|
1784
|
+
if (first === UPGRADE) {
|
|
1785
|
+
await upgrade({
|
|
1786
|
+
argv: forwarded.slice(1),
|
|
1787
|
+
root: project.root,
|
|
1788
|
+
manifestFile: project.manifestFile,
|
|
1789
|
+
manifest,
|
|
1790
|
+
home,
|
|
1791
|
+
io: io2,
|
|
1792
|
+
fetcher: options.fetcher,
|
|
1793
|
+
noDownload,
|
|
1794
|
+
ci: isCi(env)
|
|
1795
|
+
});
|
|
1796
|
+
return 0;
|
|
1797
|
+
}
|
|
1558
1798
|
const enginePin = enginePinOf(manifest);
|
|
1559
1799
|
const engineDir = await ensure(options, "engines", enginePin, home, noDownload);
|
|
1560
1800
|
for (const pin of extensionPinsOf(manifest)) {
|
|
@@ -1573,16 +1813,16 @@ async function adopt(options, forwarded, home, cwd, noDownload) {
|
|
|
1573
1813
|
if (root === void 0) {
|
|
1574
1814
|
return 0;
|
|
1575
1815
|
}
|
|
1576
|
-
const manifestFile = (0, import_node_path7.join)(root, ...
|
|
1577
|
-
if ((0,
|
|
1816
|
+
const manifestFile = (0, import_node_path7.join)(root, ...import_core11.MANIFEST_PATH.split("/"));
|
|
1817
|
+
if ((0, import_node_fs8.existsSync)(manifestFile)) {
|
|
1578
1818
|
return 0;
|
|
1579
1819
|
}
|
|
1580
1820
|
const pin = releaseEnginePin(options.bundledPin, engine.version);
|
|
1581
|
-
(0,
|
|
1821
|
+
(0, import_node_fs8.writeFileSync)(
|
|
1582
1822
|
manifestFile,
|
|
1583
|
-
(0,
|
|
1823
|
+
(0, import_core11.serializeManifest)({ format: import_core11.MANIFEST_FORMAT, engine: pin, extensions: {} })
|
|
1584
1824
|
);
|
|
1585
|
-
options.io.out(`\u2713 ${
|
|
1825
|
+
options.io.out(`\u2713 ${import_core11.MANIFEST_PATH} pins ${pin.package} ${pin.version}`);
|
|
1586
1826
|
await ensureAdoptedEngine(
|
|
1587
1827
|
options,
|
|
1588
1828
|
{ name: pin.package, version: pin.version, integrity: pin.integrity },
|
|
@@ -1629,12 +1869,14 @@ async function install(options, pins, home, broken) {
|
|
|
1629
1869
|
if (state === "corrupt") {
|
|
1630
1870
|
throw new PackageCorruptError(pin.name, pin.version, dir);
|
|
1631
1871
|
}
|
|
1632
|
-
if (state === "
|
|
1633
|
-
|
|
1634
|
-
|
|
1872
|
+
if (state === "absent") {
|
|
1873
|
+
await installPin({ home, kind, pin, fetcher: options.fetcher });
|
|
1874
|
+
}
|
|
1875
|
+
if (kind === "extensions") {
|
|
1876
|
+
await assertLoadable(pin.name, (0, import_core11.packageEntry)(dir), false);
|
|
1635
1877
|
}
|
|
1636
|
-
|
|
1637
|
-
options.io.out(`\u2713 ${pin.name} ${pin.version}
|
|
1878
|
+
const verb = state === "absent" ? "installed" : "already installed";
|
|
1879
|
+
options.io.out(`\u2713 ${pin.name} ${pin.version} ${verb}`);
|
|
1638
1880
|
}
|
|
1639
1881
|
if (broken.length > 0) {
|
|
1640
1882
|
report(new ManifestEntriesUnreadableError(broken), options.io);
|
|
@@ -1670,7 +1912,7 @@ async function delegate(options, engine, forwarded, home, cwd) {
|
|
|
1670
1912
|
command: process.execPath,
|
|
1671
1913
|
args: [engine.entry, ...forwarded],
|
|
1672
1914
|
cwd,
|
|
1673
|
-
env: { ...options.env, [
|
|
1915
|
+
env: { ...options.env, [import_core11.PENV_HOME_VAR]: home }
|
|
1674
1916
|
});
|
|
1675
1917
|
if (code === 0 && isRootHelp(forwarded)) {
|
|
1676
1918
|
printLauncherCommands(options.io);
|