@penvhq/launcher 0.9.3 → 0.9.5

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 CHANGED
@@ -155,7 +155,38 @@ var AddFlagError = class extends import_core.PenvError {
155
155
  super(
156
156
  "PENV_ADD_FLAG",
157
157
  `\`penv add\` does not understand \`${flag}\``,
158
- `Run \`penv add <package>\` with \`${TRUST_YOUNG_FLAG}\` or \`--registry <url>\` \u2014 those are the two it takes.`
158
+ `Run \`penv add <package>\` with \`${TRUST_YOUNG_FLAG}\`, \`--registry <url>\`, or \`${LOCAL_FLAG}\` \u2014 those are the three it takes.`
159
+ );
160
+ }
161
+ };
162
+ var LOCAL_FLAG = "--local";
163
+ var AddLocalFlagError = class extends import_core.PenvError {
164
+ name = "AddLocalFlagError";
165
+ constructor(subject) {
166
+ super(
167
+ "PENV_ADD_LOCAL_FLAG",
168
+ `\`penv add ${LOCAL_FLAG}\` cannot take ${subject}`,
169
+ `${LOCAL_FLAG} adds the package this project already builds, so there is no release to name and nothing to pin. Publish it and run \`penv add <package>\` to pin one.`
170
+ );
171
+ }
172
+ };
173
+ var LocalExtensionUnresolvedError = class extends import_core.PenvError {
174
+ name = "LocalExtensionUnresolvedError";
175
+ constructor(name, root) {
176
+ super(
177
+ "PENV_LOCAL_EXTENSION_UNRESOLVED",
178
+ `${name} does not resolve from ${root}`,
179
+ `${LOCAL_FLAG} records that penv should read this package out of the project, so the project has to have it \u2014 add it as a dependency of the root (a workspace link is one), then run this again.`
180
+ );
181
+ }
182
+ };
183
+ var AddLocalInCiError = class extends import_core.PenvError {
184
+ name = "AddLocalInCiError";
185
+ constructor(name) {
186
+ super(
187
+ "PENV_ADD_LOCAL_IN_CI",
188
+ `Adding ${name} writes ${import_core.LOCAL_EXTENSIONS_PATH}, and CI does not decide what a project develops`,
189
+ `Run \`penv add ${LOCAL_FLAG} ${name}\` from a terminal and commit what it writes.`
159
190
  );
160
191
  }
161
192
  };
@@ -412,6 +443,7 @@ var import_core9 = require("@penvhq/core");
412
443
 
413
444
  // src/add.ts
414
445
  var import_node_fs5 = require("fs");
446
+ var import_node_module2 = require("module");
415
447
  var import_node_path5 = require("path");
416
448
  var import_core6 = require("@penvhq/core");
417
449
 
@@ -594,14 +626,20 @@ function readExtensionPackage(dir) {
594
626
  try {
595
627
  parsed = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(dir, "package.json"), "utf8"));
596
628
  } catch {
597
- return { types: void 0, onboard: void 0 };
629
+ return { name: void 0, version: void 0, types: void 0, onboard: void 0 };
598
630
  }
599
631
  const penv = field(parsed, "penv");
600
- return { types: text(field(penv, "types")), onboard: text(field(penv, "onboard")) };
632
+ return {
633
+ name: text(field(parsed, "name")),
634
+ version: text(field(parsed, "version")),
635
+ types: text(field(penv, "types")),
636
+ onboard: text(field(penv, "onboard"))
637
+ };
601
638
  }
602
639
  function header(subject) {
603
- const provenance = subject.attested ? "npm records a provenance attestation for it" : "npm records no provenance attestation for it";
604
- return `// Written by \`penv add ${subject.name}\`, and committed.
640
+ const local = subject.local === true;
641
+ const provenance = local ? "resolved from this project, not from a published release" : subject.attested ? "npm records a provenance attestation for it" : "npm records no provenance attestation for it";
642
+ return `// Written by \`penv add ${local ? "--local " : ""}${subject.name}\`, and committed.
605
643
  // ${subject.name} ${subject.version} \u2014 ${provenance}.
606
644
  //
607
645
  // Types only: this declares the shape of the provider's \`penv.config.ts\`
@@ -994,8 +1032,13 @@ function parseRequest(argv) {
994
1032
  let spec;
995
1033
  let registry;
996
1034
  let trustYoung = false;
1035
+ let local = false;
997
1036
  for (let index = 0; index < argv.length; index += 1) {
998
1037
  const token = argv[index] ?? "";
1038
+ if (token === LOCAL_FLAG) {
1039
+ local = true;
1040
+ continue;
1041
+ }
999
1042
  if (token === TRUST_YOUNG_FLAG) {
1000
1043
  trustYoung = true;
1001
1044
  continue;
@@ -1024,7 +1067,18 @@ function parseRequest(argv) {
1024
1067
  if (!PACKAGE_NAME.test(name) || version === "") {
1025
1068
  throw new AddPackageNameError(spec);
1026
1069
  }
1027
- return { name, version, registry, trustYoung };
1070
+ if (local) {
1071
+ if (version !== void 0) {
1072
+ throw new AddLocalFlagError("a version");
1073
+ }
1074
+ if (registry !== void 0) {
1075
+ throw new AddLocalFlagError(`\`${REGISTRY_FLAG}\``);
1076
+ }
1077
+ if (trustYoung) {
1078
+ throw new AddLocalFlagError(`\`${TRUST_YOUNG_FLAG}\``);
1079
+ }
1080
+ }
1081
+ return { name, version, registry, trustYoung, local };
1028
1082
  }
1029
1083
  function tierOf(request) {
1030
1084
  if (request.name.startsWith(import_core6.OFFICIAL_SCOPE)) {
@@ -1157,9 +1211,69 @@ async function offerOnboarding(io2, name, onboard) {
1157
1211
  io2.out(`Run \`${command}\` to finish setting ${name} up.`);
1158
1212
  return void 0;
1159
1213
  }
1214
+ function resolvePackageDir(name, root) {
1215
+ const require2 = (0, import_node_module2.createRequire)((0, import_node_path5.resolve)(root, "noop.js"));
1216
+ try {
1217
+ return (0, import_node_path5.dirname)(require2.resolve(`${name}/package.json`));
1218
+ } catch {
1219
+ let dir;
1220
+ try {
1221
+ dir = (0, import_node_path5.dirname)(require2.resolve(name));
1222
+ } catch {
1223
+ return void 0;
1224
+ }
1225
+ for (let current = dir, parent = (0, import_node_path5.dirname)(dir); current !== parent; parent = (0, import_node_path5.dirname)(current)) {
1226
+ if (readExtensionPackage(current).name === name) {
1227
+ return current;
1228
+ }
1229
+ current = parent;
1230
+ }
1231
+ return void 0;
1232
+ }
1233
+ }
1234
+ function recordLocalExtension(root, name) {
1235
+ const file = (0, import_core6.localExtensionsFile)(root);
1236
+ let current;
1237
+ try {
1238
+ current = (0, import_node_fs5.readFileSync)(file, "utf8");
1239
+ } catch {
1240
+ current = "[]";
1241
+ }
1242
+ (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(file), { recursive: true });
1243
+ (0, import_node_fs5.writeFileSync)(file, (0, import_core6.serializeLocalExtensions)([...(0, import_core6.parseLocalExtensions)(current), name]));
1244
+ }
1245
+ async function addLocal(options, request) {
1246
+ const { io: io2, root } = options;
1247
+ if (options.ci === true) {
1248
+ throw new AddLocalInCiError(request.name);
1249
+ }
1250
+ const dir = resolvePackageDir(request.name, root);
1251
+ if (dir === void 0) {
1252
+ throw new LocalExtensionUnresolvedError(request.name, root);
1253
+ }
1254
+ const installed = readExtensionPackage(dir);
1255
+ const declaration = writeDeclaration({
1256
+ root,
1257
+ dir,
1258
+ name: request.name,
1259
+ version: installed.version ?? "unpublished",
1260
+ attested: false,
1261
+ local: true,
1262
+ types: installed.types
1263
+ });
1264
+ recordLocalExtension(root, request.name);
1265
+ io2.out(`\u2713 ${request.name} resolves from this project \u2014 nothing is pinned`);
1266
+ io2.out(`\u2713 ${import_core6.LOCAL_EXTENSIONS_PATH} records it`);
1267
+ io2.out(`\u2713 ${declaration} declares its config type`);
1268
+ await offerConfigEdit(options, request.name);
1269
+ return { onboard: await offerOnboarding(io2, request.name, installed.onboard) };
1270
+ }
1160
1271
  async function add(options) {
1161
1272
  const { io: io2, fetcher, home, root, manifestFile } = options;
1162
1273
  const request = parseRequest(options.argv);
1274
+ if (request.local) {
1275
+ return addLocal(options, request);
1276
+ }
1163
1277
  const tier = tierOf(request);
1164
1278
  const now = (options.now ?? (() => /* @__PURE__ */ new Date()))();
1165
1279
  if (options.noDownload === true) {
@@ -1217,8 +1331,8 @@ var DEV_PIN_INTEGRITY = "sha512-development-build-not-a-published-release";
1217
1331
  var DEV_PIN_VERSION = "0.0.0-dev";
1218
1332
  var BUNDLED_ENGINE_PIN = {
1219
1333
  package: import_core7.ENGINE_PACKAGE,
1220
- version: "0.9.3",
1221
- integrity: "sha512-9ZPRFCovPXXFYxT7SWJth8IX1Rgu/FXl8+60Pn8MBu5UYG4m4l0fBi1aFwnxVVcriAnFmxNtNG4hwn1a1IliWw=="
1334
+ version: "0.9.5",
1335
+ integrity: "sha512-cacsvynscs6G0NThpGaK1BfKy3POQSoogI/vvQNZ5sTZaftzwg4mPtUpT+i2GSc3KbYAHQu4Kq9MpYLOvSvulA=="
1222
1336
  };
1223
1337
  function assertReleasePin(pin) {
1224
1338
  if (pin.integrity === DEV_PIN_INTEGRITY || pin.version === DEV_PIN_VERSION) {
@@ -1358,7 +1472,7 @@ async function launch(options) {
1358
1472
  return delegate(options, options.bundledEngine(), forwarded, home, cwd);
1359
1473
  }
1360
1474
  if (ADOPTS.has(first)) {
1361
- return adopt(options, forwarded, home, cwd);
1475
+ return adopt(options, forwarded, home, cwd, noDownload);
1362
1476
  }
1363
1477
  throw new NoProjectError(cwd);
1364
1478
  }
@@ -1382,7 +1496,7 @@ async function launch(options) {
1382
1496
  const engine = engineAt(engineDir, enginePin.name, enginePin.version);
1383
1497
  return delegate(options, engine, forwarded, home, cwd);
1384
1498
  }
1385
- async function adopt(options, forwarded, home, cwd) {
1499
+ async function adopt(options, forwarded, home, cwd, noDownload) {
1386
1500
  const engine = options.bundledEngine();
1387
1501
  const code = await delegate(options, engine, forwarded, home, cwd);
1388
1502
  if (code !== 0) {
@@ -1402,8 +1516,26 @@ async function adopt(options, forwarded, home, cwd) {
1402
1516
  (0, import_core9.serializeManifest)({ format: import_core9.MANIFEST_FORMAT, engine: pin, extensions: {} })
1403
1517
  );
1404
1518
  options.io.out(`\u2713 ${import_core9.MANIFEST_PATH} pins ${pin.package} ${pin.version}`);
1519
+ await ensureAdoptedEngine(
1520
+ options,
1521
+ { name: pin.package, version: pin.version, integrity: pin.integrity },
1522
+ home,
1523
+ noDownload
1524
+ );
1405
1525
  return 0;
1406
1526
  }
1527
+ async function ensureAdoptedEngine(options, pin, home, noDownload) {
1528
+ try {
1529
+ await ensure(options, "engines", pin, home, noDownload);
1530
+ } catch (error) {
1531
+ if (!(error instanceof PackageMissingError || error instanceof InstallDeclinedError)) {
1532
+ report(error, options.io);
1533
+ }
1534
+ options.io.out(
1535
+ `\u2192 Run \`${INSTALL_COMMAND}\` to install ${pin.name} ${pin.version} before your first \`penv run\`.`
1536
+ );
1537
+ }
1538
+ }
1407
1539
  async function ensure(options, kind, pin, home, noDownload) {
1408
1540
  const { io: io2, env, fetcher } = options;
1409
1541
  const { dir, state } = inspectInstall(home, kind, pin);