@penvhq/cli 0.9.4 → 0.10.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
@@ -69,7 +69,7 @@ var import_core35 = require("@penvhq/core");
69
69
  var import_citty22 = require("citty");
70
70
 
71
71
  // src/commands/artifact.ts
72
- var import_node_fs6 = require("fs");
72
+ var import_node_fs7 = require("fs");
73
73
  var import_node_path7 = require("path");
74
74
  var import_core12 = require("@penvhq/core");
75
75
  var import_runtime2 = require("@penvhq/runtime");
@@ -381,7 +381,7 @@ function installFailed(plan2) {
381
381
  }
382
382
 
383
383
  // src/project.ts
384
- var import_node_fs3 = require("fs");
384
+ var import_node_fs4 = require("fs");
385
385
  var import_node_path4 = require("path");
386
386
  var import_core5 = require("@penvhq/core");
387
387
  var import_provider_filesystem2 = require("@penvhq/provider-filesystem");
@@ -445,6 +445,7 @@ function environmentFromShorthand(config, candidates, explicit) {
445
445
  }
446
446
 
447
447
  // src/registry.ts
448
+ var import_node_fs3 = require("fs");
448
449
  var import_node_module = require("module");
449
450
  var import_node_path3 = require("path");
450
451
  var import_node_url = require("url");
@@ -491,19 +492,12 @@ async function createSourceProvider(type, context) {
491
492
  return loadPluginProvider(type, context);
492
493
  }
493
494
  async function loadPluginProvider(type, context) {
494
- const resolved = resolvePlugin(type, context.root);
495
- if (resolved === void 0) {
496
- throw unknownProvider(type, context.environment);
497
- }
495
+ const path = resolveExtension(type, context.root, context.environment);
498
496
  let mod;
499
497
  try {
500
- mod = await importPlugin(resolved);
501
- } catch {
502
- throw new import_core4.PenvError(
503
- "PROVIDER_PLUGIN_LOAD",
504
- `The provider package \`${type}\` failed to load`,
505
- "It resolved but threw while importing. Check it builds and its dependencies are installed."
506
- );
498
+ mod = await importPlugin(path);
499
+ } catch (cause) {
500
+ throw providerLoadFailed(type, path, cause);
507
501
  }
508
502
  const factory = mod[PLUGIN_FACTORY_EXPORT];
509
503
  if (typeof factory !== "function") {
@@ -517,15 +511,71 @@ async function loadPluginProvider(type, context) {
517
511
  assertSatisfiesContract(provider, type);
518
512
  return provider;
519
513
  }
520
- function assertProvidersRegistered(config, projectRoot) {
514
+ function assertProvidersRegistered(config, projectRoot, options) {
515
+ const local = localExtensions(projectRoot);
516
+ const ci = options?.ci ?? isCi(process.env.CI);
521
517
  for (const [environment, provider] of Object.entries(config.providers)) {
522
518
  if (isProviderRegistered(provider.type)) {
523
519
  continue;
524
520
  }
525
- if (resolvePlugin(provider.type, projectRoot) === void 0) {
526
- throw unknownProvider(provider.type, environment);
521
+ if (ci && local.includes(provider.type)) {
522
+ throw localExtensionInCi(provider.type, environment);
523
+ }
524
+ resolveExtension(provider.type, projectRoot, environment, local);
525
+ }
526
+ }
527
+ function resolveExtension(type, projectRoot, environment, local = localExtensions(projectRoot)) {
528
+ const fromProject = resolvePlugin(type, projectRoot);
529
+ if (local.includes(type)) {
530
+ if (fromProject === void 0) {
531
+ throw localExtensionUnresolved(type, projectRoot, environment);
527
532
  }
533
+ return fromProject;
534
+ }
535
+ if (fromProject !== void 0) {
536
+ return fromProject;
537
+ }
538
+ const version = pinnedVersion(type, projectRoot);
539
+ if (version === void 0) {
540
+ throw unknownProvider(type, environment);
541
+ }
542
+ const stored = storedExtension(type, version);
543
+ if (stored === void 0) {
544
+ throw extensionNotInstalled(type, version, environment);
545
+ }
546
+ return stored;
547
+ }
548
+ function pinnedVersion(type, projectRoot) {
549
+ let manifest;
550
+ try {
551
+ manifest = (0, import_core4.parseManifest)((0, import_node_fs3.readFileSync)((0, import_node_path3.join)(projectRoot, ...import_core4.MANIFEST_PATH.split("/")), "utf8"));
552
+ } catch {
553
+ return void 0;
528
554
  }
555
+ return manifest.extensions[type]?.version;
556
+ }
557
+ function storedExtension(type, version) {
558
+ const entry = (0, import_core4.packageEntry)((0, import_core4.packageDir)((0, import_core4.penvHome)(process.env), "extensions", type, version));
559
+ return entry?.file;
560
+ }
561
+ function localExtensions(projectRoot) {
562
+ let text;
563
+ try {
564
+ text = (0, import_node_fs3.readFileSync)((0, import_core4.localExtensionsFile)(projectRoot), "utf8");
565
+ } catch {
566
+ return [];
567
+ }
568
+ return (0, import_core4.parseLocalExtensions)(text);
569
+ }
570
+ function isCi(value) {
571
+ return value !== void 0 && value !== "" && value !== "0" && value.toLowerCase() !== "false";
572
+ }
573
+ function localExtensionInCi(type, environment) {
574
+ return new import_core4.PenvError(
575
+ "LOCAL_EXTENSION_IN_CI",
576
+ `The provider \`${type}\` for environment ${environment} is a local extension, and this is CI`,
577
+ `${import_core4.LOCAL_EXTENSIONS_PATH} records it as a package this project develops, so nothing pins the bytes CI would run. Publish it and run \`penv add ${type}\` to pin a release.`
578
+ );
529
579
  }
530
580
  function resolvePlugin(specifier, fromDir) {
531
581
  try {
@@ -558,13 +608,37 @@ function assertSatisfiesContract(provider, specifier) {
558
608
  }
559
609
  }
560
610
  }
611
+ function where(environment) {
612
+ return environment === void 0 ? "" : ` for environment ${environment}`;
613
+ }
561
614
  function unknownProvider(type, environment) {
562
615
  const preinstalled = [...REGISTRY.keys()].map((name) => `\`${name}\``).join(", ");
563
- const where = environment === void 0 ? "" : ` for environment ${environment}`;
564
616
  return new import_core4.PenvError(
565
617
  "UNKNOWN_PROVIDER",
566
- `The provider \`${type}\`${where} in penv.config.ts is not installed in this project`,
567
- `Install it with \`npm i ${type}\` \u2014 a provider's \`type\` is the package penv imports. The CLI ships ${preinstalled} pre-installed.`
618
+ `The provider \`${type}\`${where(environment)} in penv.config.ts is nowhere penv looks for it`,
619
+ `Run \`penv add ${type}\` to pin a release, or \`penv add --local ${type}\` if this repository is the one that builds it. penv looks in ${import_core4.LOCAL_EXTENSIONS_PATH}, this project's node_modules, and then $PENV_HOME at the version ${import_core4.MANIFEST_PATH} pins. The CLI ships ${preinstalled} pre-installed.`
620
+ );
621
+ }
622
+ function extensionNotInstalled(type, version, environment) {
623
+ return new import_core4.PenvError(
624
+ "EXTENSION_NOT_INSTALLED",
625
+ `${import_core4.MANIFEST_PATH} pins \`${type}\` ${version}${where(environment)}, and it is not installed in ${(0, import_core4.penvHome)(process.env)}`,
626
+ "Run `penv install` \u2014 it downloads and verifies every version the manifest pins, extensions included."
627
+ );
628
+ }
629
+ function localExtensionUnresolved(type, projectRoot, environment) {
630
+ return new import_core4.PenvError(
631
+ "LOCAL_EXTENSION_UNRESOLVED",
632
+ `${import_core4.LOCAL_EXTENSIONS_PATH} records \`${type}\`${where(environment)} as a package this project develops, and it does not resolve from ${projectRoot}`,
633
+ `Add it as a dependency of the root (a workspace link is one) and run \`pnpm install\`, or drop the name from ${import_core4.LOCAL_EXTENSIONS_PATH} if this project no longer builds it.`
634
+ );
635
+ }
636
+ function providerLoadFailed(type, path, cause) {
637
+ const detail = cause instanceof Error ? cause.message : String(cause);
638
+ return new import_core4.PenvError(
639
+ "PROVIDER_PLUGIN_LOAD",
640
+ `The provider package \`${type}\` failed to load from ${path}: ${detail}`,
641
+ "penv imports that file exactly as it stands, with no transform, so it has to be built JavaScript with its dependencies installed."
568
642
  );
569
643
  }
570
644
 
@@ -594,10 +668,10 @@ function localTree(project) {
594
668
  }
595
669
  function selfContainedSchemaModule(root, schemaFile) {
596
670
  const file = (0, import_node_path4.join)(root, ...schemaFile.split("/"));
597
- if (!(0, import_node_fs3.existsSync)(file)) {
671
+ if (!(0, import_node_fs4.existsSync)(file)) {
598
672
  return void 0;
599
673
  }
600
- const source = (0, import_node_fs3.readFileSync)(file, "utf8");
674
+ const source = (0, import_node_fs4.readFileSync)(file, "utf8");
601
675
  return source.includes("PenvSchemaShape") || source.includes("z.object") ? schemaFile : void 0;
602
676
  }
603
677
  function schemaShapeFileOf(project) {
@@ -833,10 +907,7 @@ function writeError(lines) {
833
907
  }
834
908
  function reportError(error) {
835
909
  if (error instanceof import_core6.PenvError) {
836
- const suffix = error.remedy === void 0 ? void 0 : `
837
- ${error.remedy}`;
838
- const message = suffix !== void 0 && error.message.endsWith(suffix) ? error.message.slice(0, -suffix.length) : error.message;
839
- process.stderr.write(`${err.red(CROSS)} ${message}
910
+ process.stderr.write(`${err.red(CROSS)} ${error.summary}
840
911
  `);
841
912
  if (error.remedy !== void 0) {
842
913
  process.stderr.write(` ${err.cyan("\u2192")} ${error.remedy}
@@ -866,7 +937,7 @@ async function guard(run) {
866
937
  }
867
938
 
868
939
  // src/commands/run.ts
869
- var import_node_fs5 = require("fs");
940
+ var import_node_fs6 = require("fs");
870
941
  var import_node_module2 = require("module");
871
942
  var import_node_path6 = require("path");
872
943
  var import_core11 = require("@penvhq/core");
@@ -874,7 +945,7 @@ var import_runtime = require("@penvhq/runtime");
874
945
  var import_citty3 = require("citty");
875
946
 
876
947
  // src/dotenv-files.ts
877
- var import_node_fs4 = require("fs");
948
+ var import_node_fs5 = require("fs");
878
949
  var import_core7 = require("@penvhq/core");
879
950
  var SHARED = ".env";
880
951
  var LOCAL = "local";
@@ -934,7 +1005,7 @@ function order(file) {
934
1005
  function discoverDotenvFiles(root) {
935
1006
  let entries;
936
1007
  try {
937
- entries = (0, import_node_fs4.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
1008
+ entries = (0, import_node_fs5.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
938
1009
  } catch {
939
1010
  return [];
940
1011
  }
@@ -1671,9 +1742,9 @@ function packageManifest(specifier, root) {
1671
1742
  }
1672
1743
  for (; ; ) {
1673
1744
  const file = (0, import_node_path6.join)(directory, "package.json");
1674
- if ((0, import_node_fs5.existsSync)(file)) {
1745
+ if ((0, import_node_fs6.existsSync)(file)) {
1675
1746
  try {
1676
- const parsed = JSON.parse((0, import_node_fs5.readFileSync)(file, "utf8"));
1747
+ const parsed = JSON.parse((0, import_node_fs6.readFileSync)(file, "utf8"));
1677
1748
  if (isPlainObject(parsed) && parsed.name === specifier) {
1678
1749
  return parsed;
1679
1750
  }
@@ -1746,7 +1817,7 @@ function snapshotPath(host) {
1746
1817
  }
1747
1818
  function readSnapshot(path) {
1748
1819
  try {
1749
- return (0, import_node_fs5.readFileSync)(path, "utf8");
1820
+ return (0, import_node_fs6.readFileSync)(path, "utf8");
1750
1821
  } catch {
1751
1822
  throw new import_core11.PenvError(
1752
1823
  "RUN_SNAPSHOT_MISSING",
@@ -1825,11 +1896,11 @@ function watchProject(project, onChange) {
1825
1896
  timer = setTimeout(onChange, DEBOUNCE_MS);
1826
1897
  };
1827
1898
  const add = (target, recursive, only) => {
1828
- if (!(0, import_node_fs5.existsSync)(target)) {
1899
+ if (!(0, import_node_fs6.existsSync)(target)) {
1829
1900
  return;
1830
1901
  }
1831
1902
  try {
1832
- const watcher = (0, import_node_fs5.watch)(target, { recursive }, (_event, filename) => {
1903
+ const watcher = (0, import_node_fs6.watch)(target, { recursive }, (_event, filename) => {
1833
1904
  if (only !== void 0 && (filename === null || (0, import_node_path6.basename)(filename) !== only)) {
1834
1905
  return;
1835
1906
  }
@@ -2092,8 +2163,8 @@ ${lines}`,
2092
2163
  keySource: (0, import_core12.keySourceIdentifier)(project.config, environment),
2093
2164
  values
2094
2165
  };
2095
- (0, import_node_fs6.mkdirSync)((0, import_node_path7.dirname)(file), { recursive: true });
2096
- (0, import_node_fs6.writeFileSync)(file, (0, import_core12.serializeArtifact)(artifact), "utf8");
2166
+ (0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)(file), { recursive: true });
2167
+ (0, import_node_fs7.writeFileSync)(file, (0, import_core12.serializeArtifact)(artifact), "utf8");
2097
2168
  const inside = (0, import_node_path7.relative)(project.root, file);
2098
2169
  return {
2099
2170
  file,
@@ -2163,7 +2234,7 @@ var import_core14 = require("@penvhq/core");
2163
2234
  var import_citty5 = require("citty");
2164
2235
 
2165
2236
  // src/cutover.ts
2166
- var import_node_fs7 = require("fs");
2237
+ var import_node_fs8 = require("fs");
2167
2238
  var import_node_path8 = require("path");
2168
2239
  var import_core13 = require("@penvhq/core");
2169
2240
  var CUTOVER_FORMAT = 1;
@@ -2182,7 +2253,7 @@ function cutoverRoot(cwd) {
2182
2253
  }
2183
2254
  function bundledFiles(root) {
2184
2255
  try {
2185
- return (0, import_node_fs7.readdirSync)(bundleDir(root)).sort();
2256
+ return (0, import_node_fs8.readdirSync)(bundleDir(root)).sort();
2186
2257
  } catch {
2187
2258
  return [];
2188
2259
  }
@@ -2192,12 +2263,12 @@ function bundleUnresolved(root) {
2192
2263
  }
2193
2264
  function readCutover(root) {
2194
2265
  const file = cutoverFile(root);
2195
- if (!(0, import_node_fs7.existsSync)(file)) {
2266
+ if (!(0, import_node_fs8.existsSync)(file)) {
2196
2267
  return void 0;
2197
2268
  }
2198
2269
  let parsed;
2199
2270
  try {
2200
- parsed = JSON.parse((0, import_node_fs7.readFileSync)(file, "utf8"));
2271
+ parsed = JSON.parse((0, import_node_fs8.readFileSync)(file, "utf8"));
2201
2272
  } catch {
2202
2273
  throw unreadable("it is not JSON");
2203
2274
  }
@@ -2250,12 +2321,12 @@ function bundleDotenvFiles(root, files, environments, now = /* @__PURE__ */ new
2250
2321
  environments: [...environments]
2251
2322
  };
2252
2323
  const file = cutoverFile(root);
2253
- (0, import_node_fs7.mkdirSync)((0, import_node_path8.dirname)(file), { recursive: true });
2254
- (0, import_node_fs7.writeFileSync)(file, serializeCutover(cutover), "utf8");
2324
+ (0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(file), { recursive: true });
2325
+ (0, import_node_fs8.writeFileSync)(file, serializeCutover(cutover), "utf8");
2255
2326
  const bundle = bundleDir(root);
2256
- (0, import_node_fs7.mkdirSync)(bundle, { recursive: true });
2327
+ (0, import_node_fs8.mkdirSync)(bundle, { recursive: true });
2257
2328
  for (const name of files) {
2258
- (0, import_node_fs7.renameSync)((0, import_node_path8.join)(root, name), (0, import_node_path8.join)(bundle, name));
2329
+ (0, import_node_fs8.renameSync)((0, import_node_path8.join)(root, name), (0, import_node_path8.join)(bundle, name));
2259
2330
  }
2260
2331
  return cutover;
2261
2332
  }
@@ -2274,7 +2345,7 @@ function runUndo(options) {
2274
2345
  const names = [...recorded, ...bundled.filter((name) => !recorded.includes(name))];
2275
2346
  const bundle = bundleDir(root);
2276
2347
  const held = new Set(bundled);
2277
- const occupied2 = names.filter((name) => held.has(name) && (0, import_node_fs7.existsSync)((0, import_node_path8.join)(root, name)));
2348
+ const occupied2 = names.filter((name) => held.has(name) && (0, import_node_fs8.existsSync)((0, import_node_path8.join)(root, name)));
2278
2349
  if (occupied2.length > 0) {
2279
2350
  const listed = occupied2.join(", ");
2280
2351
  const many = occupied2.length > 1;
@@ -2289,9 +2360,9 @@ function runUndo(options) {
2289
2360
  const missing = [];
2290
2361
  for (const name of names) {
2291
2362
  if (held.has(name)) {
2292
- (0, import_node_fs7.renameSync)((0, import_node_path8.join)(bundle, name), (0, import_node_path8.join)(root, name));
2363
+ (0, import_node_fs8.renameSync)((0, import_node_path8.join)(bundle, name), (0, import_node_path8.join)(root, name));
2293
2364
  restored.push(name);
2294
- } else if ((0, import_node_fs7.existsSync)((0, import_node_path8.join)(root, name))) {
2365
+ } else if ((0, import_node_fs8.existsSync)((0, import_node_path8.join)(root, name))) {
2295
2366
  alreadyBack.push(name);
2296
2367
  } else {
2297
2368
  missing.push(name);
@@ -2303,13 +2374,13 @@ function runUndo(options) {
2303
2374
  function runCleanup(options) {
2304
2375
  const root = cutoverRoot(options.cwd);
2305
2376
  const held = bundledFiles(root);
2306
- const cleaned = held.length > 0 || (0, import_node_fs7.existsSync)(cutoverFile(root)) || (0, import_node_fs7.existsSync)(fileFor(root, import_core13.ROLLBACK_PATH));
2377
+ const cleaned = held.length > 0 || (0, import_node_fs8.existsSync)(cutoverFile(root)) || (0, import_node_fs8.existsSync)(fileFor(root, import_core13.ROLLBACK_PATH));
2307
2378
  removeBundle(root);
2308
2379
  return { root, removed: held, cleaned };
2309
2380
  }
2310
2381
  function removeBundle(root) {
2311
- (0, import_node_fs7.rmSync)(fileFor(root, import_core13.ROLLBACK_PATH), { recursive: true, force: true });
2312
- (0, import_node_fs7.rmSync)(cutoverFile(root), { force: true });
2382
+ (0, import_node_fs8.rmSync)(fileFor(root, import_core13.ROLLBACK_PATH), { recursive: true, force: true });
2383
+ (0, import_node_fs8.rmSync)(cutoverFile(root), { force: true });
2313
2384
  }
2314
2385
 
2315
2386
  // src/commands/cleanup.ts
@@ -2344,7 +2415,7 @@ var cleanupCommand = (0, import_citty5.defineCommand)({
2344
2415
  });
2345
2416
 
2346
2417
  // src/commands/doctor.ts
2347
- var import_node_fs8 = require("fs");
2418
+ var import_node_fs9 = require("fs");
2348
2419
  var import_node_path9 = require("path");
2349
2420
  var import_core16 = require("@penvhq/core");
2350
2421
  var import_citty7 = require("citty");
@@ -2790,6 +2861,7 @@ async function runDoctor(options) {
2790
2861
  findings.push(...unusedFindings(drift));
2791
2862
  }
2792
2863
  findings.push(...fallbackFindings(subjects, environment));
2864
+ findings.push(...secrecyFindings(subjects, environment));
2793
2865
  findings.push(...plaintextSecretFindings(subjects, environment));
2794
2866
  findings.push(...publicSecretFindings(subjects, environment, project.config));
2795
2867
  findings.push(...encryptionFindings(subjects, environment));
@@ -2802,6 +2874,7 @@ async function runDoctor(options) {
2802
2874
  }
2803
2875
  findings.push(...await providerDriftFindings(project, environment, options.source));
2804
2876
  findings.push(...await projectionFindings(project, environment, options.projection));
2877
+ findings.push(...localExtensionFindings(project));
2805
2878
  findings.push(...artifactFindings(project));
2806
2879
  findings.push({
2807
2880
  check: "provider",
@@ -2939,6 +3012,31 @@ function fallbackFindings(subjects, environment) {
2939
3012
  }
2940
3013
  ];
2941
3014
  }
3015
+ function secrecyFindings(subjects, environment) {
3016
+ const undeclared = subjects.filter(
3017
+ ({ meta }) => (0, import_core16.effectiveMeta)(meta, environment).secret === void 0
3018
+ );
3019
+ if (undeclared.length === 0) {
3020
+ return [
3021
+ {
3022
+ check: "secrecy-undeclared",
3023
+ severity: "pass",
3024
+ label: "Secrecy policy",
3025
+ subject: subjects.length === 0 ? `no parameter resolves for ${environment}` : `every parameter declares whether it is secret for ${environment}`
3026
+ }
3027
+ ];
3028
+ }
3029
+ return [
3030
+ {
3031
+ check: "secrecy-undeclared",
3032
+ severity: "unknown",
3033
+ label: "Secrecy policy",
3034
+ subject: `${undeclared.length} of ${subjects.length} declare neither way for ${environment}`,
3035
+ detail: "penv was never told which of these values must be encrypted",
3036
+ remedy: `declare \`"secret": true\` or \`"secret": false\` in a parameter's meta file, ${import_core16.RECORDS_PATH}/<name>.json`
3037
+ }
3038
+ ];
3039
+ }
2942
3040
  function plaintextSecretFindings(subjects, environment) {
2943
3041
  const secrets = subjects.filter(({ meta }) => (0, import_core16.isSecret)(meta, environment));
2944
3042
  const findings = [];
@@ -3242,7 +3340,7 @@ function looksLikeArtifact(text) {
3242
3340
  function scannableFiles(directory, out2) {
3243
3341
  let entries;
3244
3342
  try {
3245
- entries = (0, import_node_fs8.readdirSync)(directory, { withFileTypes: true });
3343
+ entries = (0, import_node_fs9.readdirSync)(directory, { withFileTypes: true });
3246
3344
  } catch {
3247
3345
  return;
3248
3346
  }
@@ -3259,6 +3357,29 @@ function scannableFiles(directory, out2) {
3259
3357
  }
3260
3358
  }
3261
3359
  }
3360
+ function localExtensionFindings(project) {
3361
+ const names = localExtensions(project.root);
3362
+ if (names.length === 0) {
3363
+ return [
3364
+ {
3365
+ check: "local-extension",
3366
+ severity: "pass",
3367
+ label: "Extensions",
3368
+ subject: "every extension this project names is pinned"
3369
+ }
3370
+ ];
3371
+ }
3372
+ return [
3373
+ {
3374
+ check: "local-extension",
3375
+ severity: "unknown",
3376
+ label: "Extensions",
3377
+ subject: names.join(", "),
3378
+ detail: "resolved from this project's node_modules \u2014 no release, no pinned bytes",
3379
+ remedy: `publish it and run \`penv add ${names[0]}\` when this stops being a development path`
3380
+ }
3381
+ ];
3382
+ }
3262
3383
  function artifactFindings(project) {
3263
3384
  const files = [];
3264
3385
  scannableFiles(project.root, files);
@@ -3266,10 +3387,10 @@ function artifactFindings(project) {
3266
3387
  for (const file of files) {
3267
3388
  let text;
3268
3389
  try {
3269
- if ((0, import_node_fs8.statSync)(file).size > ARTIFACT_SCAN_LIMIT) {
3390
+ if ((0, import_node_fs9.statSync)(file).size > ARTIFACT_SCAN_LIMIT) {
3270
3391
  continue;
3271
3392
  }
3272
- text = (0, import_node_fs8.readFileSync)(file, "utf8");
3393
+ text = (0, import_node_fs9.readFileSync)(file, "utf8");
3273
3394
  } catch {
3274
3395
  continue;
3275
3396
  }
@@ -4029,7 +4150,7 @@ var fillCommand = (0, import_citty10.defineCommand)({
4029
4150
  });
4030
4151
 
4031
4152
  // src/commands/generate.ts
4032
- var import_node_fs9 = require("fs");
4153
+ var import_node_fs10 = require("fs");
4033
4154
  var import_node_path10 = require("path");
4034
4155
  var import_core20 = require("@penvhq/core");
4035
4156
  var import_citty11 = require("citty");
@@ -4083,7 +4204,7 @@ function runGenerate(options) {
4083
4204
  const environment = targetEnvironment(project, options.environment, options.envFlags);
4084
4205
  const { entries, decrypted } = entriesFor(project, environment, options.allowDecrypt === true);
4085
4206
  const file = options.out === void 0 ? (0, import_node_path10.resolve)(project.root, DEFAULT_OUTPUT) : (0, import_node_path10.isAbsolute)(options.out) ? options.out : (0, import_node_path10.resolve)(options.cwd, options.out);
4086
- (0, import_node_fs9.writeFileSync)(file, (0, import_core20.serializeDotenv)(entries), "utf8");
4207
+ (0, import_node_fs10.writeFileSync)(file, (0, import_core20.serializeDotenv)(entries), "utf8");
4087
4208
  return { file, environment, entries: entries.length, decrypted };
4088
4209
  }
4089
4210
  function displayPath2(cwd, file) {
@@ -4221,7 +4342,7 @@ var getCommand = (0, import_citty12.defineCommand)({
4221
4342
  });
4222
4343
 
4223
4344
  // src/commands/import.ts
4224
- var import_node_fs13 = require("fs");
4345
+ var import_node_fs14 = require("fs");
4225
4346
  var import_node_path14 = require("path");
4226
4347
  var import_core26 = require("@penvhq/core");
4227
4348
  var import_citty14 = require("citty");
@@ -4238,9 +4359,9 @@ function assertImportable(ref, variable) {
4238
4359
  `Filenames are split on \`.\`. Rename ${variable} in the source file, then import it again.`
4239
4360
  );
4240
4361
  }
4241
- function assertNotReserved(ref, variable, where, config) {
4362
+ function assertNotReserved(ref, variable, where2, config) {
4242
4363
  if ((0, import_core22.isReservedToken)(ref.name, config)) {
4243
- throw new import_core22.ReservedTokenError("parameter", variable, where);
4364
+ throw new import_core22.ReservedTokenError("parameter", variable, where2);
4244
4365
  }
4245
4366
  }
4246
4367
  function assertRoundTrips(ref, variable, config) {
@@ -4257,12 +4378,12 @@ function assertRoundTrips(ref, variable, config) {
4257
4378
  `\`penv generate\` would write ${generated}, so anything reading \`process.env["${variable}"]\` would read \`undefined\`. Declare the name you want in the \`override\` block of penv.config.ts \u2014 \`override: { "${ref.name}": "${variable}" }\` \u2014 then import it again. Nothing was imported.`
4258
4379
  );
4259
4380
  }
4260
- function refsForEntries(entries, where, config) {
4381
+ function refsForEntries(entries, where2, config) {
4261
4382
  const refs = [];
4262
4383
  for (const entry of entries) {
4263
4384
  const ref = (0, import_core22.refFromVariable)(entry.key);
4264
4385
  assertImportable(ref, entry.key);
4265
- assertNotReserved(ref, entry.key, where, config);
4386
+ assertNotReserved(ref, entry.key, where2, config);
4266
4387
  assertRoundTrips(ref, entry.key, config);
4267
4388
  refs.push(ref);
4268
4389
  }
@@ -4292,7 +4413,7 @@ function writeEntries(tree, entries, refs, scope) {
4292
4413
  }
4293
4414
 
4294
4415
  // src/detect.ts
4295
- var import_node_fs10 = require("fs");
4416
+ var import_node_fs11 = require("fs");
4296
4417
  var import_node_path11 = require("path");
4297
4418
  var import_core23 = require("@penvhq/core");
4298
4419
  var SIGNATURES = [
@@ -4310,7 +4431,7 @@ var SIGNATURES = [
4310
4431
  function exportsSchema(file) {
4311
4432
  let source;
4312
4433
  try {
4313
- source = (0, import_node_fs10.readFileSync)(file, "utf8");
4434
+ source = (0, import_node_fs11.readFileSync)(file, "utf8");
4314
4435
  } catch {
4315
4436
  return false;
4316
4437
  }
@@ -4322,7 +4443,7 @@ function exportsSchema(file) {
4322
4443
  }
4323
4444
  function occupied(cwd, relative5) {
4324
4445
  const file = (0, import_node_path11.join)(cwd, ...relative5.split("/"));
4325
- return (0, import_node_fs10.existsSync)(file) && !exportsSchema(file);
4446
+ return (0, import_node_fs11.existsSync)(file) && !exportsSchema(file);
4326
4447
  }
4327
4448
  function schemaFileFor(cwd) {
4328
4449
  const dir = srcPrefix(cwd);
@@ -4337,7 +4458,7 @@ function schemaFileFor(cwd) {
4337
4458
  return { file: import_core23.DEFAULT_SCHEMA_FILE, displaced: preferred };
4338
4459
  }
4339
4460
  function srcPrefix(cwd) {
4340
- return (0, import_node_fs10.existsSync)((0, import_node_path11.join)(cwd, "src")) ? "src/" : "";
4461
+ return (0, import_node_fs11.existsSync)((0, import_node_path11.join)(cwd, "src")) ? "src/" : "";
4341
4462
  }
4342
4463
  function dependenciesOf(cwd) {
4343
4464
  const manifest = manifestOf2(cwd);
@@ -4357,12 +4478,12 @@ function dependenciesOf(cwd) {
4357
4478
  }
4358
4479
  function manifestOf2(cwd) {
4359
4480
  const file = (0, import_node_path11.join)(cwd, "package.json");
4360
- if (!(0, import_node_fs10.existsSync)(file)) {
4481
+ if (!(0, import_node_fs11.existsSync)(file)) {
4361
4482
  return void 0;
4362
4483
  }
4363
4484
  let manifest;
4364
4485
  try {
4365
- manifest = JSON.parse((0, import_node_fs10.readFileSync)(file, "utf8"));
4486
+ manifest = JSON.parse((0, import_node_fs11.readFileSync)(file, "utf8"));
4366
4487
  } catch {
4367
4488
  return void 0;
4368
4489
  }
@@ -4378,7 +4499,7 @@ function detectFramework(cwd) {
4378
4499
  return detectedFrom(cwd, signature.name, signature.publicPrefixes);
4379
4500
  }
4380
4501
  }
4381
- if ((0, import_node_fs10.existsSync)((0, import_node_path11.join)(cwd, "bunfig.toml")) || dependencies.has("bun-types")) {
4502
+ if ((0, import_node_fs11.existsSync)((0, import_node_path11.join)(cwd, "bunfig.toml")) || dependencies.has("bun-types")) {
4382
4503
  return detectedFrom(cwd, "Bun", []);
4383
4504
  }
4384
4505
  return void 0;
@@ -4457,31 +4578,31 @@ function draftFieldsAcross(sources, environments) {
4457
4578
  }
4458
4579
 
4459
4580
  // src/commands/init.ts
4460
- var import_node_fs12 = require("fs");
4581
+ var import_node_fs13 = require("fs");
4461
4582
  var import_node_path13 = require("path");
4462
4583
  var import_promises = require("readline/promises");
4463
4584
  var import_core25 = require("@penvhq/core");
4464
4585
  var import_citty13 = require("citty");
4465
4586
 
4466
4587
  // src/scaffold-undo.ts
4467
- var import_node_fs11 = require("fs");
4588
+ var import_node_fs12 = require("fs");
4468
4589
  var import_node_path12 = require("path");
4469
4590
  function record(path, files, dirs) {
4470
4591
  let stats;
4471
4592
  try {
4472
- stats = (0, import_node_fs11.statSync)(path);
4593
+ stats = (0, import_node_fs12.statSync)(path);
4473
4594
  } catch {
4474
4595
  return;
4475
4596
  }
4476
4597
  if (stats.isDirectory()) {
4477
4598
  dirs.add(path);
4478
- for (const entry of (0, import_node_fs11.readdirSync)(path)) {
4599
+ for (const entry of (0, import_node_fs12.readdirSync)(path)) {
4479
4600
  record((0, import_node_path12.join)(path, entry), files, dirs);
4480
4601
  }
4481
4602
  return;
4482
4603
  }
4483
4604
  if (stats.isFile()) {
4484
- files.set(path, (0, import_node_fs11.readFileSync)(path));
4605
+ files.set(path, (0, import_node_fs12.readFileSync)(path));
4485
4606
  }
4486
4607
  }
4487
4608
  function captureScaffold(root, paths) {
@@ -4489,7 +4610,7 @@ function captureScaffold(root, paths) {
4489
4610
  const dirs = /* @__PURE__ */ new Set();
4490
4611
  for (const path of paths) {
4491
4612
  for (let dir = (0, import_node_path12.dirname)(path); dir.startsWith(root) && dir !== root; dir = (0, import_node_path12.dirname)(dir)) {
4492
- if ((0, import_node_fs11.existsSync)(dir)) {
4613
+ if ((0, import_node_fs12.existsSync)(dir)) {
4493
4614
  dirs.add(dir);
4494
4615
  }
4495
4616
  }
@@ -4505,31 +4626,31 @@ function restoreScaffold(undo) {
4505
4626
  pruneAncestors(path, undo);
4506
4627
  }
4507
4628
  for (const [file, contents] of undo.files) {
4508
- (0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true });
4509
- (0, import_node_fs11.writeFileSync)(file, contents);
4629
+ (0, import_node_fs12.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true });
4630
+ (0, import_node_fs12.writeFileSync)(file, contents);
4510
4631
  }
4511
4632
  }
4512
4633
  function removeAdded(path, undo) {
4513
4634
  let stats;
4514
4635
  try {
4515
- stats = (0, import_node_fs11.statSync)(path);
4636
+ stats = (0, import_node_fs12.statSync)(path);
4516
4637
  } catch {
4517
4638
  return;
4518
4639
  }
4519
4640
  if (stats.isFile()) {
4520
4641
  if (!undo.files.has(path)) {
4521
- (0, import_node_fs11.unlinkSync)(path);
4642
+ (0, import_node_fs12.unlinkSync)(path);
4522
4643
  }
4523
4644
  return;
4524
4645
  }
4525
4646
  if (!stats.isDirectory()) {
4526
4647
  return;
4527
4648
  }
4528
- for (const entry of (0, import_node_fs11.readdirSync)(path)) {
4649
+ for (const entry of (0, import_node_fs12.readdirSync)(path)) {
4529
4650
  removeAdded((0, import_node_path12.join)(path, entry), undo);
4530
4651
  }
4531
- if (!undo.dirs.has(path) && (0, import_node_fs11.readdirSync)(path).length === 0) {
4532
- (0, import_node_fs11.rmdirSync)(path);
4652
+ if (!undo.dirs.has(path) && (0, import_node_fs12.readdirSync)(path).length === 0) {
4653
+ (0, import_node_fs12.rmdirSync)(path);
4533
4654
  }
4534
4655
  }
4535
4656
  function pruneAncestors(path, undo) {
@@ -4538,7 +4659,7 @@ function pruneAncestors(path, undo) {
4538
4659
  return;
4539
4660
  }
4540
4661
  try {
4541
- (0, import_node_fs11.rmdirSync)(dir);
4662
+ (0, import_node_fs12.rmdirSync)(dir);
4542
4663
  } catch {
4543
4664
  return;
4544
4665
  }
@@ -4700,7 +4821,7 @@ var NOT_ENVIRONMENTS2 = [...import_core25.RESERVED_TOKENS, "example", "sample",
4700
4821
  function suggestEnvironments(root) {
4701
4822
  let entries;
4702
4823
  try {
4703
- entries = (0, import_node_fs12.readdirSync)(root);
4824
+ entries = (0, import_node_fs13.readdirSync)(root);
4704
4825
  } catch {
4705
4826
  return [];
4706
4827
  }
@@ -4745,7 +4866,7 @@ function configOf(decisions) {
4745
4866
  }
4746
4867
  function declaredIn(root) {
4747
4868
  const file = (0, import_node_path13.join)(root, CONFIG_FILE);
4748
- if (!(0, import_node_fs12.existsSync)(file)) {
4869
+ if (!(0, import_node_fs13.existsSync)(file)) {
4749
4870
  return void 0;
4750
4871
  }
4751
4872
  return (0, import_core25.loadConfigFrom)(file);
@@ -5188,15 +5309,15 @@ function renderTsconfig(target, alias) {
5188
5309
  }
5189
5310
  function ensurePenvDir(root) {
5190
5311
  const dir = (0, import_node_path13.resolve)(root, import_core25.PENV_DIR);
5191
- if ((0, import_node_fs12.existsSync)(dir)) {
5312
+ if ((0, import_node_fs13.existsSync)(dir)) {
5192
5313
  return { target: "penv-dir", action: "kept", text: `Found ${import_core25.PENV_DIR}/` };
5193
5314
  }
5194
- (0, import_node_fs12.mkdirSync)(dir, { recursive: true });
5315
+ (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
5195
5316
  return { target: "penv-dir", action: "created", text: `Created ${import_core25.PENV_DIR}/` };
5196
5317
  }
5197
5318
  function writeSchemaShapeFile(root, fields, draft, decisions = DEFAULT_DECISIONS) {
5198
5319
  const file = (0, import_node_path13.join)(root, import_core25.SCHEMA_SHAPE_FILE);
5199
- if ((0, import_node_fs12.existsSync)(file)) {
5320
+ if ((0, import_node_fs13.existsSync)(file)) {
5200
5321
  return {
5201
5322
  target: "schema",
5202
5323
  action: "kept",
@@ -5213,7 +5334,7 @@ function writeSchemaShapeFile(root, fields, draft, decisions = DEFAULT_DECISIONS
5213
5334
  note: `(the shape lives there, from before the ${import_core25.SCHEMA_SHAPE_FILE} split \u2014 penv did not add a second one. To adopt the split: move the \`z.object\` (and any \`declare module\` block) into ${import_core25.SCHEMA_SHAPE_FILE}, leaving ${oldLayout} importing \`schema\` from it and calling \`load\`.)`
5214
5335
  };
5215
5336
  }
5216
- (0, import_node_fs12.writeFileSync)(file, renderSchemaShapeModule(fields, draft), "utf8");
5337
+ (0, import_node_fs13.writeFileSync)(file, renderSchemaShapeModule(fields, draft), "utf8");
5217
5338
  return {
5218
5339
  target: "schema",
5219
5340
  action: "created",
@@ -5223,7 +5344,7 @@ function writeSchemaShapeFile(root, fields, draft, decisions = DEFAULT_DECISIONS
5223
5344
  }
5224
5345
  function writeEnvFile(root, decisions = DEFAULT_DECISIONS) {
5225
5346
  const file = (0, import_node_path13.join)(root, ...decisions.schemaFile.split("/"));
5226
- if ((0, import_node_fs12.existsSync)(file)) {
5347
+ if ((0, import_node_fs13.existsSync)(file)) {
5227
5348
  return {
5228
5349
  target: "env",
5229
5350
  action: "kept",
@@ -5231,8 +5352,8 @@ function writeEnvFile(root, decisions = DEFAULT_DECISIONS) {
5231
5352
  note: "(yours \u2014 penv never regenerates it)"
5232
5353
  };
5233
5354
  }
5234
- (0, import_node_fs12.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5235
- (0, import_node_fs12.writeFileSync)(file, renderEnvModule(decisions.schemaFile, decisions.inject), "utf8");
5355
+ (0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5356
+ (0, import_node_fs13.writeFileSync)(file, renderEnvModule(decisions.schemaFile, decisions.inject), "utf8");
5236
5357
  return {
5237
5358
  target: "env",
5238
5359
  action: "created",
@@ -5242,18 +5363,18 @@ function writeEnvFile(root, decisions = DEFAULT_DECISIONS) {
5242
5363
  }
5243
5364
  function writeConfigFile(root, decisions = DEFAULT_DECISIONS) {
5244
5365
  const file = (0, import_node_path13.join)(root, CONFIG_FILE);
5245
- if ((0, import_node_fs12.existsSync)(file)) {
5366
+ if ((0, import_node_fs13.existsSync)(file)) {
5246
5367
  return { target: "config", action: "kept", text: `Kept ${CONFIG_FILE}` };
5247
5368
  }
5248
- (0, import_node_fs12.writeFileSync)(file, renderConfigModule(decisions), "utf8");
5369
+ (0, import_node_fs13.writeFileSync)(file, renderConfigModule(decisions), "utf8");
5249
5370
  return { target: "config", action: "created", text: `Generated ${CONFIG_FILE}` };
5250
5371
  }
5251
5372
  function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
5252
5373
  const alias = decisions.alias;
5253
5374
  const imports = alias.startsWith(IMPORTS_PREFIX);
5254
5375
  const file = (0, import_node_path13.join)(root, imports ? PACKAGE_FILE : TSCONFIG_FILE);
5255
- const where = imports ? PACKAGE_FILE : TSCONFIG_FILE;
5256
- if (!(0, import_node_fs12.existsSync)(file)) {
5376
+ const where2 = imports ? PACKAGE_FILE : TSCONFIG_FILE;
5377
+ if (!(0, import_node_fs13.existsSync)(file)) {
5257
5378
  if (imports) {
5258
5379
  return {
5259
5380
  target: "tsconfig",
@@ -5262,20 +5383,20 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
5262
5383
  note: `(run \`npm init\` first, or use \`--alias @env\` to alias through ${TSCONFIG_FILE})`
5263
5384
  };
5264
5385
  }
5265
- (0, import_node_fs12.writeFileSync)(file, renderTsconfig(decisions.schemaFile, alias), "utf8");
5386
+ (0, import_node_fs13.writeFileSync)(file, renderTsconfig(decisions.schemaFile, alias), "utf8");
5266
5387
  return {
5267
5388
  target: "tsconfig",
5268
5389
  action: "created",
5269
5390
  text: `Created ${TSCONFIG_FILE} with the ${alias} path alias`
5270
5391
  };
5271
5392
  }
5272
- const source = (0, import_node_fs12.readFileSync)(file, "utf8");
5393
+ const source = (0, import_node_fs13.readFileSync)(file, "utf8");
5273
5394
  const edit = imports ? insertImportsAlias(source, decisions.schemaFile, alias) : insertEnvAlias(source, decisions.schemaFile, alias);
5274
5395
  if (edit.conflict !== void 0) {
5275
5396
  return {
5276
5397
  target: "tsconfig",
5277
5398
  action: "conflicted",
5278
- text: `${where} already maps ${alias} to ${edit.conflict}`,
5399
+ text: `${where2} already maps ${alias} to ${edit.conflict}`,
5279
5400
  note: `(left alone \u2014 \`import { env } from "${alias}"\` will not reach ${decisions.schemaFile})`
5280
5401
  };
5281
5402
  }
@@ -5283,25 +5404,25 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
5283
5404
  return {
5284
5405
  target: "tsconfig",
5285
5406
  action: "kept",
5286
- text: `Kept the ${alias} alias in ${where}`
5407
+ text: `Kept the ${alias} alias in ${where2}`
5287
5408
  };
5288
5409
  }
5289
- (0, import_node_fs12.writeFileSync)(file, edit.source, "utf8");
5410
+ (0, import_node_fs13.writeFileSync)(file, edit.source, "utf8");
5290
5411
  return {
5291
5412
  target: "tsconfig",
5292
5413
  action: "updated",
5293
- text: `Added ${alias} alias to ${where}`
5414
+ text: `Added ${alias} alias to ${where2}`
5294
5415
  };
5295
5416
  }
5296
5417
  function writeGitignore(root, decisions = DEFAULT_DECISIONS) {
5297
5418
  const file = (0, import_node_path13.join)(root, ...import_core25.STATE_GITIGNORE_PATH.split("/"));
5298
5419
  const wanted = (0, import_core25.renderStateGitignore)(configOf(decisions));
5299
- const existing = (0, import_node_fs12.existsSync)(file) ? (0, import_node_fs12.readFileSync)(file, "utf8") : void 0;
5420
+ const existing = (0, import_node_fs13.existsSync)(file) ? (0, import_node_fs13.readFileSync)(file, "utf8") : void 0;
5300
5421
  if (existing === wanted) {
5301
5422
  return { target: "gitignore", action: "kept", text: `Kept ${import_core25.STATE_GITIGNORE_PATH}` };
5302
5423
  }
5303
- (0, import_node_fs12.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5304
- (0, import_node_fs12.writeFileSync)(file, wanted, "utf8");
5424
+ (0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5425
+ (0, import_node_fs13.writeFileSync)(file, wanted, "utf8");
5305
5426
  return {
5306
5427
  target: "gitignore",
5307
5428
  action: existing === void 0 ? "created" : "updated",
@@ -5318,11 +5439,11 @@ function outdatedRuntimeWarning(root) {
5318
5439
  }
5319
5440
  function installedPenvVersion(root) {
5320
5441
  const file = (0, import_node_path13.join)(root, "node_modules", "@penvhq", "penv", "package.json");
5321
- if (!(0, import_node_fs12.existsSync)(file)) {
5442
+ if (!(0, import_node_fs13.existsSync)(file)) {
5322
5443
  return void 0;
5323
5444
  }
5324
5445
  try {
5325
- const version = JSON.parse((0, import_node_fs12.readFileSync)(file, "utf8")).version;
5446
+ const version = JSON.parse((0, import_node_fs13.readFileSync)(file, "utf8")).version;
5326
5447
  return typeof version === "string" ? version : void 0;
5327
5448
  } catch {
5328
5449
  return void 0;
@@ -5366,7 +5487,7 @@ function writeSeam(root, decisions = DEFAULT_DECISIONS, framework = detectFramew
5366
5487
  const baseNotes = [...seam.notes, ...alsoNote === void 0 ? [] : [alsoNote]];
5367
5488
  const notes = baseNotes.length === 0 ? "" : `
5368
5489
  ${baseNotes.map((n) => ` ${n}`).join("\n")}`;
5369
- if ((0, import_node_fs12.existsSync)(file)) {
5490
+ if ((0, import_node_fs13.existsSync)(file)) {
5370
5491
  return {
5371
5492
  target: "seam",
5372
5493
  action: "info",
@@ -5374,8 +5495,8 @@ ${baseNotes.map((n) => ` ${n}`).join("\n")}`;
5374
5495
  note: withWarning(`${seam.ifPresent}${notes}`, outdated)
5375
5496
  };
5376
5497
  }
5377
- (0, import_node_fs12.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5378
- (0, import_node_fs12.writeFileSync)(file, seam.content, "utf8");
5498
+ (0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5499
+ (0, import_node_fs13.writeFileSync)(file, seam.content, "utf8");
5379
5500
  return {
5380
5501
  target: "seam",
5381
5502
  action: outdated === void 0 ? "created" : "info",
@@ -5388,11 +5509,11 @@ function writeAlso(root, also) {
5388
5509
  return void 0;
5389
5510
  }
5390
5511
  const file = (0, import_node_path13.join)(root, ...also.file.split("/"));
5391
- if ((0, import_node_fs12.existsSync)(file)) {
5512
+ if ((0, import_node_fs13.existsSync)(file)) {
5392
5513
  return also.ifPresent;
5393
5514
  }
5394
- (0, import_node_fs12.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5395
- (0, import_node_fs12.writeFileSync)(file, also.content, "utf8");
5515
+ (0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
5516
+ (0, import_node_fs13.writeFileSync)(file, also.content, "utf8");
5396
5517
  return `Wrote ${also.file} to register it.`;
5397
5518
  }
5398
5519
  function withWarning(note, warning) {
@@ -5496,7 +5617,7 @@ function planCutover(input) {
5496
5617
  const diagnostics = [];
5497
5618
  let variables = 0;
5498
5619
  for (const file of selected) {
5499
- const parsed = (0, import_core25.parseDotenv)((0, import_node_fs12.readFileSync)((0, import_node_path13.join)(root, file.name), "utf8"));
5620
+ const parsed = (0, import_core25.parseDotenv)((0, import_node_fs13.readFileSync)((0, import_node_path13.join)(root, file.name), "utf8"));
5500
5621
  const fileRefs = refsForEntries(parsed.entries, file.name, config);
5501
5622
  adopted.push({ file, entries: parsed.entries, refs: fileRefs, scope: scopeOf(file) });
5502
5623
  refs.push(...fileRefs);
@@ -5741,11 +5862,11 @@ function dailyCommand(root) {
5741
5862
  }
5742
5863
  function devScript(root) {
5743
5864
  const file = (0, import_node_path13.join)(root, PACKAGE_FILE);
5744
- if (!(0, import_node_fs12.existsSync)(file)) {
5865
+ if (!(0, import_node_fs13.existsSync)(file)) {
5745
5866
  return "dev";
5746
5867
  }
5747
5868
  try {
5748
- const scripts = JSON.parse((0, import_node_fs12.readFileSync)(file, "utf8")).scripts;
5869
+ const scripts = JSON.parse((0, import_node_fs13.readFileSync)(file, "utf8")).scripts;
5749
5870
  if (scripts !== null && typeof scripts === "object" && !Array.isArray(scripts)) {
5750
5871
  const named = Object.keys(scripts);
5751
5872
  return ["dev", "start"].find((script) => named.includes(script)) ?? named[0] ?? "dev";
@@ -6114,14 +6235,14 @@ function configInEffect(cwd, environment) {
6114
6235
  function importDotenv(options) {
6115
6236
  const cwd = (0, import_node_path14.resolve)(options.cwd);
6116
6237
  const file = (0, import_node_path14.isAbsolute)(options.file) ? options.file : (0, import_node_path14.resolve)(cwd, options.file);
6117
- if (!(0, import_node_fs13.existsSync)(file)) {
6238
+ if (!(0, import_node_fs14.existsSync)(file)) {
6118
6239
  throw new import_core26.PenvError(
6119
6240
  "IMPORT_FILE_MISSING",
6120
6241
  `There is no file at ${file} to import`,
6121
6242
  "Point `penv import` at an existing dotenv file, e.g. `penv import .env`."
6122
6243
  );
6123
6244
  }
6124
- const parsed = (0, import_core26.parseDotenv)((0, import_node_fs13.readFileSync)(file, "utf8"));
6245
+ const parsed = (0, import_core26.parseDotenv)((0, import_node_fs14.readFileSync)(file, "utf8"));
6125
6246
  const { config, decisions } = configInEffect(cwd, environmentNamed(file, options.environment));
6126
6247
  const source = displayPath3(cwd, file);
6127
6248
  const named = scopeFromFilename(file, config);
@@ -6137,7 +6258,7 @@ function importDotenv(options) {
6137
6258
  const tree = localTree(project);
6138
6259
  writeEntries(tree, parsed.entries, refs, scope);
6139
6260
  const backup = `${file}${BACKUP_SUFFIX}`;
6140
- (0, import_node_fs13.copyFileSync)(file, backup);
6261
+ (0, import_node_fs14.copyFileSync)(file, backup);
6141
6262
  return {
6142
6263
  root: project.root,
6143
6264
  file,
@@ -6472,7 +6593,7 @@ var listCommand = (0, import_citty16.defineCommand)({
6472
6593
  });
6473
6594
 
6474
6595
  // src/commands/migrate.ts
6475
- var import_node_fs14 = require("fs");
6596
+ var import_node_fs15 = require("fs");
6476
6597
  var import_node_path15 = require("path");
6477
6598
  var import_promises2 = require("readline/promises");
6478
6599
  var import_core30 = require("@penvhq/core");
@@ -6492,7 +6613,7 @@ function planMigrate(cwd) {
6492
6613
  );
6493
6614
  }
6494
6615
  const creates = [];
6495
- if (entries.length > 0 && !(0, import_node_fs14.existsSync)(tree)) {
6616
+ if (entries.length > 0 && !(0, import_node_fs15.existsSync)(tree)) {
6496
6617
  creates.push(`${import_core30.RECORDS_PATH}/`);
6497
6618
  }
6498
6619
  if (readIfPresent((0, import_node_path15.join)(root, ...import_core30.STATE_GITIGNORE_PATH.split("/"))) !== (0, import_core30.renderStateGitignore)(config)) {
@@ -6505,16 +6626,16 @@ function planMigrate(cwd) {
6505
6626
  to: `${import_core30.RECORDS_PATH}/${entry}`
6506
6627
  })),
6507
6628
  creates,
6508
- removes: (0, import_node_fs14.existsSync)((0, import_node_path15.join)(root, ...OLD_GITIGNORE.split("/"))) ? [OLD_GITIGNORE] : []
6629
+ removes: (0, import_node_fs15.existsSync)((0, import_node_path15.join)(root, ...OLD_GITIGNORE.split("/"))) ? [OLD_GITIGNORE] : []
6509
6630
  };
6510
6631
  }
6511
6632
  function readIfPresent(file) {
6512
- return (0, import_node_fs14.existsSync)(file) ? (0, import_node_fs14.readFileSync)(file, "utf8") : void 0;
6633
+ return (0, import_node_fs15.existsSync)(file) ? (0, import_node_fs15.readFileSync)(file, "utf8") : void 0;
6513
6634
  }
6514
6635
  function collidingEntries(entries, tree) {
6515
6636
  let held;
6516
6637
  try {
6517
- held = (0, import_node_fs14.readdirSync)(tree);
6638
+ held = (0, import_node_fs15.readdirSync)(tree);
6518
6639
  } catch {
6519
6640
  return [];
6520
6641
  }
@@ -6533,18 +6654,18 @@ function applyMigrate(plan2) {
6533
6654
  }
6534
6655
  const { config } = (0, import_core30.loadConfig)(plan2.root);
6535
6656
  if (plan2.moves.length > 0) {
6536
- (0, import_node_fs14.mkdirSync)((0, import_core30.recordsDir)(plan2.root), { recursive: true });
6657
+ (0, import_node_fs15.mkdirSync)((0, import_core30.recordsDir)(plan2.root), { recursive: true });
6537
6658
  for (const move of plan2.moves) {
6538
- (0, import_node_fs14.renameSync)((0, import_node_path15.join)(plan2.root, ...move.from.split("/")), (0, import_node_path15.join)(plan2.root, ...move.to.split("/")));
6659
+ (0, import_node_fs15.renameSync)((0, import_node_path15.join)(plan2.root, ...move.from.split("/")), (0, import_node_path15.join)(plan2.root, ...move.to.split("/")));
6539
6660
  }
6540
6661
  }
6541
6662
  if (plan2.creates.includes(import_core30.STATE_GITIGNORE_PATH)) {
6542
6663
  const ignore = (0, import_node_path15.join)(plan2.root, ...import_core30.STATE_GITIGNORE_PATH.split("/"));
6543
- (0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(ignore), { recursive: true });
6544
- (0, import_node_fs14.writeFileSync)(ignore, (0, import_core30.renderStateGitignore)(config), "utf8");
6664
+ (0, import_node_fs15.mkdirSync)((0, import_node_path15.dirname)(ignore), { recursive: true });
6665
+ (0, import_node_fs15.writeFileSync)(ignore, (0, import_core30.renderStateGitignore)(config), "utf8");
6545
6666
  }
6546
6667
  for (const removed of plan2.removes) {
6547
- (0, import_node_fs14.rmSync)((0, import_node_path15.join)(plan2.root, ...removed.split("/")), { force: true });
6668
+ (0, import_node_fs15.rmSync)((0, import_node_path15.join)(plan2.root, ...removed.split("/")), { force: true });
6548
6669
  }
6549
6670
  return { ...plan2, status: "migrated" };
6550
6671
  }
@@ -7030,7 +7151,7 @@ var rotateCommand = (0, import_citty20.defineCommand)({
7030
7151
  });
7031
7152
 
7032
7153
  // src/commands/watch.ts
7033
- var import_node_fs15 = require("fs");
7154
+ var import_node_fs16 = require("fs");
7034
7155
  var import_node_path16 = require("path");
7035
7156
  var import_core34 = require("@penvhq/core");
7036
7157
  var import_citty21 = require("citty");
@@ -7094,18 +7215,18 @@ function runWatch(options) {
7094
7215
  const name = (0, import_node_path16.basename)(target);
7095
7216
  let recovery;
7096
7217
  try {
7097
- recovery = (0, import_node_fs15.watch)(parent, { recursive: false }, (_event, filename) => {
7218
+ recovery = (0, import_node_fs16.watch)(parent, { recursive: false }, (_event, filename) => {
7098
7219
  if (closed || recovery === void 0) {
7099
7220
  return;
7100
7221
  }
7101
- if (!(0, import_node_fs15.existsSync)(parent)) {
7222
+ if (!(0, import_node_fs16.existsSync)(parent)) {
7102
7223
  stop2(recovery);
7103
7224
  return;
7104
7225
  }
7105
7226
  if (filename !== null && (0, import_node_path16.basename)(filename) !== name) {
7106
7227
  return;
7107
7228
  }
7108
- if (!(0, import_node_fs15.existsSync)(target)) {
7229
+ if (!(0, import_node_fs16.existsSync)(target)) {
7109
7230
  return;
7110
7231
  }
7111
7232
  stop2(recovery);
@@ -7125,11 +7246,11 @@ function runWatch(options) {
7125
7246
  }
7126
7247
  function addWatcher(target, recursive, only) {
7127
7248
  let watcher;
7128
- const listen = (useRecursive) => (0, import_node_fs15.watch)(target, { recursive: useRecursive }, (_event, filename) => {
7249
+ const listen = (useRecursive) => (0, import_node_fs16.watch)(target, { recursive: useRecursive }, (_event, filename) => {
7129
7250
  if (closed) {
7130
7251
  return;
7131
7252
  }
7132
- if (!(0, import_node_fs15.existsSync)(target)) {
7253
+ if (!(0, import_node_fs16.existsSync)(target)) {
7133
7254
  if (watcher !== void 0) {
7134
7255
  stop2(watcher);
7135
7256
  }