@penvhq/launcher 0.10.0 → 0.11.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/index.cjs CHANGED
@@ -63,7 +63,15 @@ __export(src_exports, {
63
63
  TrustDeclinedError: () => TrustDeclinedError,
64
64
  TrustPublisherMissingError: () => TrustPublisherMissingError,
65
65
  TrustReasonMissingError: () => TrustReasonMissingError,
66
+ UPGRADE_COMMAND: () => UPGRADE_COMMAND,
67
+ UpgradeDeclinedError: () => UpgradeDeclinedError,
68
+ UpgradeFlagError: () => UpgradeFlagError,
69
+ UpgradeInstallFailedError: () => UpgradeInstallFailedError,
70
+ UpgradeNoDownloadError: () => UpgradeNoDownloadError,
71
+ UpgradeSubjectError: () => UpgradeSubjectError,
72
+ UpgradeUnattendedError: () => UpgradeUnattendedError,
66
73
  VersionUnknownError: () => VersionUnknownError,
74
+ YES_FLAG: () => YES_FLAG,
67
75
  add: () => add,
68
76
  assertReleasePin: () => assertReleasePin,
69
77
  bundledEngine: () => bundledEngine,
@@ -87,6 +95,7 @@ __export(src_exports, {
87
95
  runLauncher: () => runLauncher,
88
96
  setProviderType: () => setProviderType,
89
97
  tarballUrl: () => tarballUrl,
98
+ upgrade: () => upgrade,
90
99
  writeDeclaration: () => writeDeclaration
91
100
  });
92
101
  module.exports = __toCommonJS(src_exports);
@@ -268,6 +277,8 @@ var import_core2 = require("@penvhq/core");
268
277
  // src/errors.ts
269
278
  var import_core = require("@penvhq/core");
270
279
  var INSTALL_COMMAND = "penv install";
280
+ var UPGRADE_COMMAND = "penv upgrade";
281
+ var YES_FLAG = "--yes";
271
282
  var MIN_PACKAGE_AGE_DAYS = 7;
272
283
  var TRUST_YOUNG_FLAG = "--trust-young";
273
284
  function addCommand(name, version, extra) {
@@ -450,11 +461,11 @@ var OfficialRegistryError = class extends import_core.PenvError {
450
461
  };
451
462
  var RegistryUnreadableError = class extends import_core.PenvError {
452
463
  name = "RegistryUnreadableError";
453
- constructor(name, url, detail) {
464
+ constructor(name, url, detail, retry = addCommand(name)) {
454
465
  super(
455
466
  "PENV_REGISTRY_UNREADABLE",
456
467
  `Reading ${name} from ${url} failed: ${detail}`,
457
- `Run \`${addCommand(name)}\` again when the registry is reachable.`
468
+ `Run \`${retry}\` again when the registry is reachable.`
458
469
  );
459
470
  }
460
471
  };
@@ -470,11 +481,11 @@ var PackageUnknownError = class extends import_core.PenvError {
470
481
  };
471
482
  var VersionUnknownError = class extends import_core.PenvError {
472
483
  name = "VersionUnknownError";
473
- constructor(name, version, url) {
484
+ constructor(name, version, url, retry = addCommand(name)) {
474
485
  super(
475
486
  "PENV_VERSION_UNKNOWN",
476
487
  `${url} publishes no ${version} of ${name}`,
477
- `Run \`${addCommand(name)}\` to take the version \`latest\` points at.`
488
+ `Run \`${retry}\` to take the version \`latest\` points at.`
478
489
  );
479
490
  }
480
491
  };
@@ -599,6 +610,66 @@ var EnginePinMismatchError = class extends import_core.PenvError {
599
610
  );
600
611
  }
601
612
  };
613
+ var UpgradeSubjectError = class extends import_core.PenvError {
614
+ name = "UpgradeSubjectError";
615
+ constructor() {
616
+ super(
617
+ "PENV_UPGRADE_SUBJECT",
618
+ "`penv upgrade` takes one version, or none",
619
+ `Run \`${UPGRADE_COMMAND}\` to move to whatever \`latest\` points at, or \`${UPGRADE_COMMAND} 0.9.6\` to move to an exact release.`
620
+ );
621
+ }
622
+ };
623
+ var UpgradeFlagError = class extends import_core.PenvError {
624
+ name = "UpgradeFlagError";
625
+ constructor(flag) {
626
+ super(
627
+ "PENV_UPGRADE_FLAG",
628
+ `\`${UPGRADE_COMMAND}\` does not understand \`${flag}\``,
629
+ `Run \`${UPGRADE_COMMAND} [version]\` with \`${YES_FLAG}\` \u2014 that is the one flag it takes.`
630
+ );
631
+ }
632
+ };
633
+ var UpgradeNoDownloadError = class extends import_core.PenvError {
634
+ name = "UpgradeNoDownloadError";
635
+ constructor() {
636
+ super(
637
+ "PENV_UPGRADE_NO_DOWNLOAD",
638
+ `Upgrading means reading the registry for the version and integrity to pin, and \`--no-download\` says this run does not`,
639
+ `Run \`${UPGRADE_COMMAND}\` without \`--no-download\`. Nothing was fetched or written.`
640
+ );
641
+ }
642
+ };
643
+ var UpgradeUnattendedError = class extends import_core.PenvError {
644
+ name = "UpgradeUnattendedError";
645
+ constructor() {
646
+ super(
647
+ "PENV_UPGRADE_UNATTENDED",
648
+ `Upgrading rewrites ${import_core.MANIFEST_PATH} and package.json, and this run has nobody to decide that`,
649
+ `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.`
650
+ );
651
+ }
652
+ };
653
+ var UpgradeDeclinedError = class extends import_core.PenvError {
654
+ name = "UpgradeDeclinedError";
655
+ constructor(version) {
656
+ super(
657
+ "PENV_UPGRADE_DECLINED",
658
+ `${import_core.ENGINE_PACKAGE} ${version} was not installed, so ${import_core.MANIFEST_PATH} and package.json are unchanged`,
659
+ `Run \`${UPGRADE_COMMAND} ${version}\` again when you want both of them to move.`
660
+ );
661
+ }
662
+ };
663
+ var UpgradeInstallFailedError = class extends import_core.PenvError {
664
+ name = "UpgradeInstallFailedError";
665
+ constructor(command) {
666
+ super(
667
+ "PENV_UPGRADE_INSTALL_FAILED",
668
+ `${command} did not finish, so ${import_core.MANIFEST_PATH} still pins the engine it pinned before`,
669
+ `Run \`${command}\` yourself, then run \`${UPGRADE_COMMAND}\` again \u2014 the pin and the dependency move together or not at all.`
670
+ );
671
+ }
672
+ };
602
673
  var EngineEntryError = class extends import_core.PenvError {
603
674
  name = "EngineEntryError";
604
675
  constructor(name, version, dir) {
@@ -900,7 +971,8 @@ async function fetchRelease(query) {
900
971
  throw new RegistryUnreadableError(
901
972
  query.name,
902
973
  url,
903
- cause instanceof Error ? cause.message : String(cause)
974
+ cause instanceof Error ? cause.message : String(cause),
975
+ query.retry
904
976
  );
905
977
  }
906
978
  let parsed;
@@ -910,7 +982,8 @@ async function fetchRelease(query) {
910
982
  throw new RegistryUnreadableError(
911
983
  query.name,
912
984
  url,
913
- cause instanceof Error ? cause.message : String(cause)
985
+ cause instanceof Error ? cause.message : String(cause),
986
+ query.retry
914
987
  );
915
988
  }
916
989
  const packument = record(parsed);
@@ -926,7 +999,7 @@ async function fetchRelease(query) {
926
999
  const version = record(at(versions, asked)) === void 0 ? text3(at(tags, asked)) ?? asked : asked;
927
1000
  const release = record(at(versions, version));
928
1001
  if (release === void 0) {
929
- throw new VersionUnknownError(query.name, asked, url);
1002
+ throw new VersionUnknownError(query.name, asked, url, query.retry);
930
1003
  }
931
1004
  const dist = record(at(release, "dist"));
932
1005
  const integrity = text3(at(dist, "integrity"));
@@ -1436,11 +1509,12 @@ function httpFetcher() {
1436
1509
  }
1437
1510
 
1438
1511
  // src/launcher.ts
1439
- var import_node_fs7 = require("fs");
1512
+ var import_node_fs8 = require("fs");
1440
1513
  var import_node_path7 = require("path");
1441
- var import_core10 = require("@penvhq/core");
1514
+ var import_core11 = require("@penvhq/core");
1442
1515
 
1443
1516
  // src/help.ts
1517
+ var import_install = require("@penvhq/cli/install");
1444
1518
  var import_core7 = require("@penvhq/core");
1445
1519
  function printLauncherCommands(io) {
1446
1520
  io.out("");
@@ -1449,6 +1523,7 @@ function printLauncherCommands(io) {
1449
1523
  io.out(` install Installs everything ${import_core7.MANIFEST_PATH} pins`);
1450
1524
  io.out(" add <package> Pins a provider extension, and commits the decision");
1451
1525
  io.out(` add ${LOCAL_FLAG} <package> Adds the one this repository builds \u2014 nothing is pinned`);
1526
+ io.out(` upgrade [version] Moves the engine pin and ${import_install.RUNTIME_PACKAGE} together`);
1452
1527
  io.out("");
1453
1528
  }
1454
1529
  function printInstallHelp(io) {
@@ -1471,6 +1546,17 @@ function printAddHelp(io) {
1471
1546
  io.out(`${import_core7.EXTENSIONS_PATH}/. Both are committed, so \`${INSTALL_COMMAND}\` gives every machine`);
1472
1547
  io.out(`the bytes you reviewed. \`${LOCAL_FLAG}\` pins nothing and touches no manifest.`);
1473
1548
  }
1549
+ function printUpgradeHelp(io) {
1550
+ io.out("penv upgrade [version]");
1551
+ io.out("");
1552
+ io.out(` ${YES_FLAG} Skip the question \u2014 unattended runs need it and a version`);
1553
+ io.out("");
1554
+ io.out(`Moves the ${import_core7.ENGINE_PACKAGE} pin in ${import_core7.MANIFEST_PATH} and this project's`);
1555
+ io.out(`${import_install.RUNTIME_PACKAGE} dependency to the same exact version. No version takes whatever`);
1556
+ io.out("`latest` points at; the integrity is the one the registry states, never one penv");
1557
+ io.out("computed. Both files are shown before either moves, and they move together or not");
1558
+ io.out("at all. Extensions keep their own pins.");
1559
+ }
1474
1560
 
1475
1561
  // src/pins.ts
1476
1562
  var import_core8 = require("@penvhq/core");
@@ -1478,8 +1564,8 @@ var DEV_PIN_INTEGRITY = "sha512-development-build-not-a-published-release";
1478
1564
  var DEV_PIN_VERSION = "0.0.0-dev";
1479
1565
  var BUNDLED_ENGINE_PIN = {
1480
1566
  package: import_core8.ENGINE_PACKAGE,
1481
- version: "0.10.0",
1482
- integrity: "sha512-b+U0c3xWbk1ILtMfPjJW8x5XBxSLAaw/IAOLMBmGvT2uuYv41JPED8PrenEj4s3ZJY5BxpWU9mQcJHEBouaw/Q=="
1567
+ version: "0.11.0",
1568
+ integrity: "sha512-Y+WKyuPsX4U8/1j0e+VMUhj0LaGrp67YEoDAWyyinrgA+c8IM4H1blqje/YK4LsQwzQDQQDF9bhWIhfmDAWoxA=="
1483
1569
  };
1484
1570
  function assertReleasePin(pin) {
1485
1571
  if (pin.integrity === DEV_PIN_INTEGRITY || pin.version === DEV_PIN_VERSION) {
@@ -1520,9 +1606,110 @@ function findAdoptedRoot(cwd) {
1520
1606
  return findUp(cwd, (dir) => (0, import_node_fs6.existsSync)((0, import_core9.stateDir)(dir)));
1521
1607
  }
1522
1608
 
1609
+ // src/upgrade.ts
1610
+ var import_node_fs7 = require("fs");
1611
+ var import_install2 = require("@penvhq/cli/install");
1612
+ var import_core10 = require("@penvhq/core");
1613
+ function parseRequest2(argv) {
1614
+ let version;
1615
+ let yes = false;
1616
+ for (const token of argv) {
1617
+ if (token === YES_FLAG) {
1618
+ yes = true;
1619
+ continue;
1620
+ }
1621
+ if (token.startsWith("-")) {
1622
+ throw new UpgradeFlagError(token);
1623
+ }
1624
+ if (version !== void 0 || token === "") {
1625
+ throw new UpgradeSubjectError();
1626
+ }
1627
+ version = token;
1628
+ }
1629
+ return { version, yes };
1630
+ }
1631
+ function renderPinChange(engine, release) {
1632
+ return [
1633
+ import_core10.MANIFEST_PATH,
1634
+ ` - "integrity": "${engine.integrity}"`,
1635
+ ` - "version": "${engine.version}"`,
1636
+ ` + "integrity": "${release.integrity}"`,
1637
+ ` + "version": "${release.version}"`
1638
+ ];
1639
+ }
1640
+ function pinnedElsewhere(manifest, version) {
1641
+ return Object.entries(manifest.extensions).filter(([, entry]) => entry.version !== version).map(([name]) => name);
1642
+ }
1643
+ async function consent(options, release, plan, yes) {
1644
+ const { io, manifest } = options;
1645
+ io.out(`${import_core10.ENGINE_PACKAGE} ${manifest.engine.version} \u2192 ${release.version}`);
1646
+ io.out("");
1647
+ for (const line of renderPinChange(manifest.engine, release)) {
1648
+ io.out(line);
1649
+ }
1650
+ for (const line of (0, import_install2.renderInstallPlan)(plan)) {
1651
+ io.out(line);
1652
+ }
1653
+ if (yes) {
1654
+ return;
1655
+ }
1656
+ if (!await io.confirm(`Move this project to ${release.version}?`)) {
1657
+ throw new UpgradeDeclinedError(release.version);
1658
+ }
1659
+ }
1660
+ async function upgrade(options) {
1661
+ const { io, fetcher, home, root, manifest, manifestFile } = options;
1662
+ const request = parseRequest2(options.argv);
1663
+ if (options.noDownload === true) {
1664
+ throw new UpgradeNoDownloadError();
1665
+ }
1666
+ if ((options.ci === true || !io.interactive) && !(request.yes && request.version !== void 0)) {
1667
+ throw new UpgradeUnattendedError();
1668
+ }
1669
+ const release = await fetchRelease({
1670
+ name: import_core10.ENGINE_PACKAGE,
1671
+ ...request.version === void 0 ? {} : { version: request.version },
1672
+ retry: UPGRADE_COMMAND,
1673
+ fetcher
1674
+ });
1675
+ const plan = (0, import_install2.planInstall)(root, release.version);
1676
+ if (manifest.engine.version === release.version && plan.satisfied) {
1677
+ io.out(`\u2713 Already on ${import_core10.ENGINE_PACKAGE} ${release.version} \u2014 nothing to move`);
1678
+ return;
1679
+ }
1680
+ const manifestText = (0, import_core10.serializeManifest)({
1681
+ ...manifest,
1682
+ engine: { package: import_core10.ENGINE_PACKAGE, version: release.version, integrity: release.integrity }
1683
+ });
1684
+ await consent(options, release, plan, request.yes);
1685
+ await installPin({
1686
+ home,
1687
+ kind: "engines",
1688
+ pin: { name: import_core10.ENGINE_PACKAGE, version: release.version, integrity: release.integrity },
1689
+ fetcher
1690
+ });
1691
+ io.out(`\u2713 ${import_core10.ENGINE_PACKAGE} ${release.version} installed`);
1692
+ if (!plan.satisfied) {
1693
+ try {
1694
+ await (options.install ?? import_install2.installWithPackageManager)(plan);
1695
+ } catch {
1696
+ throw new UpgradeInstallFailedError(plan.command.join(" "));
1697
+ }
1698
+ io.out(`\u2713 package.json depends on ${import_install2.RUNTIME_PACKAGE} ${release.version}`);
1699
+ }
1700
+ (0, import_node_fs7.writeFileSync)(manifestFile, manifestText);
1701
+ io.out(`\u2713 ${import_core10.MANIFEST_PATH} pins ${import_core10.ENGINE_PACKAGE} ${release.version}`);
1702
+ const kept = pinnedElsewhere(manifest, release.version);
1703
+ if (kept.length > 0) {
1704
+ const subject = kept.length === 1 ? "keeps its own pin" : "keep their own pins";
1705
+ io.out(`\u2192 ${kept.join(", ")} ${subject} \u2014 \`penv add <package>@<version>\` moves one.`);
1706
+ }
1707
+ }
1708
+
1523
1709
  // src/launcher.ts
1524
1710
  var INSTALL = "install";
1525
1711
  var ADD = "add";
1712
+ var UPGRADE = "upgrade";
1526
1713
  var VERSION_FLAGS = /* @__PURE__ */ new Set(["--version", "-v"]);
1527
1714
  var HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
1528
1715
  var NO_DOWNLOAD = "--no-download";
@@ -1566,27 +1753,27 @@ function pinsOf(manifest) {
1566
1753
  ];
1567
1754
  }
1568
1755
  function reportable(error, home, argv) {
1569
- return error instanceof import_core10.UnsupportedManifestFormatError ? error.withLauncherUpdate({
1756
+ return error instanceof import_core11.UnsupportedManifestFormatError ? error.withLauncherUpdate({
1570
1757
  updateCommand: launcherUpdateCommand(home),
1571
1758
  invokedCommand: invokedCommand(argv)
1572
1759
  }) : error;
1573
1760
  }
1574
1761
  function readManifest(manifestFile, home, argv) {
1575
1762
  try {
1576
- return (0, import_core10.parseManifest)((0, import_node_fs7.readFileSync)(manifestFile, "utf8"));
1763
+ return (0, import_core11.parseManifest)((0, import_node_fs8.readFileSync)(manifestFile, "utf8"));
1577
1764
  } catch (error) {
1578
1765
  throw reportable(error, home, argv);
1579
1766
  }
1580
1767
  }
1581
1768
  function readManifestToRepair(manifestFile, home, argv) {
1582
1769
  try {
1583
- return readManifestForRepair((0, import_node_fs7.readFileSync)(manifestFile, "utf8"));
1770
+ return readManifestForRepair((0, import_node_fs8.readFileSync)(manifestFile, "utf8"));
1584
1771
  } catch (error) {
1585
1772
  throw reportable(error, home, argv);
1586
1773
  }
1587
1774
  }
1588
1775
  function report(error, io) {
1589
- if (error instanceof import_core10.PenvError && error.remedy !== void 0) {
1776
+ if (error instanceof import_core11.PenvError && error.remedy !== void 0) {
1590
1777
  const suffix = `
1591
1778
  ${error.remedy}`;
1592
1779
  const message = error.message.endsWith(suffix) ? error.message.slice(0, -suffix.length) : error.message;
@@ -1608,7 +1795,7 @@ async function launch(options) {
1608
1795
  const { argv, cwd, env, io } = options;
1609
1796
  const { noDownload, forwarded } = splitLauncherFlags(argv);
1610
1797
  const first = forwarded[0];
1611
- const home = (0, import_core10.penvHome)(env);
1798
+ const home = (0, import_core11.penvHome)(env);
1612
1799
  if (first !== void 0 && forwarded.slice(1).some((token) => HELP_FLAGS.has(token))) {
1613
1800
  if (first === INSTALL) {
1614
1801
  printInstallHelp(io);
@@ -1618,6 +1805,10 @@ async function launch(options) {
1618
1805
  printAddHelp(io);
1619
1806
  return 0;
1620
1807
  }
1808
+ if (first === UPGRADE) {
1809
+ printUpgradeHelp(io);
1810
+ return 0;
1811
+ }
1621
1812
  }
1622
1813
  const project = findProject(cwd);
1623
1814
  if (project === void 0) {
@@ -1645,6 +1836,20 @@ async function launch(options) {
1645
1836
  io.out(`penv ${manifest.engine.version}`);
1646
1837
  return 0;
1647
1838
  }
1839
+ if (first === UPGRADE) {
1840
+ await upgrade({
1841
+ argv: forwarded.slice(1),
1842
+ root: project.root,
1843
+ manifestFile: project.manifestFile,
1844
+ manifest,
1845
+ home,
1846
+ io,
1847
+ fetcher: options.fetcher,
1848
+ noDownload,
1849
+ ci: isCi(env)
1850
+ });
1851
+ return 0;
1852
+ }
1648
1853
  const enginePin = enginePinOf(manifest);
1649
1854
  const engineDir = await ensure(options, "engines", enginePin, home, noDownload);
1650
1855
  for (const pin of extensionPinsOf(manifest)) {
@@ -1663,16 +1868,16 @@ async function adopt(options, forwarded, home, cwd, noDownload) {
1663
1868
  if (root === void 0) {
1664
1869
  return 0;
1665
1870
  }
1666
- const manifestFile = (0, import_node_path7.join)(root, ...import_core10.MANIFEST_PATH.split("/"));
1667
- if ((0, import_node_fs7.existsSync)(manifestFile)) {
1871
+ const manifestFile = (0, import_node_path7.join)(root, ...import_core11.MANIFEST_PATH.split("/"));
1872
+ if ((0, import_node_fs8.existsSync)(manifestFile)) {
1668
1873
  return 0;
1669
1874
  }
1670
1875
  const pin = releaseEnginePin(options.bundledPin, engine.version);
1671
- (0, import_node_fs7.writeFileSync)(
1876
+ (0, import_node_fs8.writeFileSync)(
1672
1877
  manifestFile,
1673
- (0, import_core10.serializeManifest)({ format: import_core10.MANIFEST_FORMAT, engine: pin, extensions: {} })
1878
+ (0, import_core11.serializeManifest)({ format: import_core11.MANIFEST_FORMAT, engine: pin, extensions: {} })
1674
1879
  );
1675
- options.io.out(`\u2713 ${import_core10.MANIFEST_PATH} pins ${pin.package} ${pin.version}`);
1880
+ options.io.out(`\u2713 ${import_core11.MANIFEST_PATH} pins ${pin.package} ${pin.version}`);
1676
1881
  await ensureAdoptedEngine(
1677
1882
  options,
1678
1883
  { name: pin.package, version: pin.version, integrity: pin.integrity },
@@ -1760,7 +1965,7 @@ async function delegate(options, engine, forwarded, home, cwd) {
1760
1965
  command: process.execPath,
1761
1966
  args: [engine.entry, ...forwarded],
1762
1967
  cwd,
1763
- env: { ...options.env, [import_core10.PENV_HOME_VAR]: home }
1968
+ env: { ...options.env, [import_core11.PENV_HOME_VAR]: home }
1764
1969
  });
1765
1970
  if (code === 0 && isRootHelp(forwarded)) {
1766
1971
  printLauncherCommands(options.io);
@@ -1812,7 +2017,15 @@ async function delegate(options, engine, forwarded, home, cwd) {
1812
2017
  TrustDeclinedError,
1813
2018
  TrustPublisherMissingError,
1814
2019
  TrustReasonMissingError,
2020
+ UPGRADE_COMMAND,
2021
+ UpgradeDeclinedError,
2022
+ UpgradeFlagError,
2023
+ UpgradeInstallFailedError,
2024
+ UpgradeNoDownloadError,
2025
+ UpgradeSubjectError,
2026
+ UpgradeUnattendedError,
1815
2027
  VersionUnknownError,
2028
+ YES_FLAG,
1816
2029
  add,
1817
2030
  assertReleasePin,
1818
2031
  bundledEngine,
@@ -1836,6 +2049,7 @@ async function delegate(options, engine, forwarded, home, cwd) {
1836
2049
  runLauncher,
1837
2050
  setProviderType,
1838
2051
  tarballUrl,
2052
+ upgrade,
1839
2053
  writeDeclaration
1840
2054
  });
1841
2055
  //# sourceMappingURL=index.cjs.map