@penvhq/cli 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 +515 -186
- package/dist/bin.cjs.map +1 -1
- package/dist/index.cjs +436 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -12
- package/dist/index.d.ts +39 -12
- package/dist/index.js +425 -150
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
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
|
|
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");
|
|
@@ -114,7 +114,7 @@ var startChild = (invocation) => {
|
|
|
114
114
|
const ended = new Promise((resolve9, reject) => {
|
|
115
115
|
child.on("error", (cause) => {
|
|
116
116
|
release();
|
|
117
|
-
reject(cannotStart(executable, cause));
|
|
117
|
+
reject(cannotStart(executable, cause, invocation.purpose));
|
|
118
118
|
});
|
|
119
119
|
child.on("exit", (code, signal) => {
|
|
120
120
|
release();
|
|
@@ -135,8 +135,15 @@ function noCommand() {
|
|
|
135
135
|
"Put the command after `--`, e.g. `penv run -- pnpm dev`."
|
|
136
136
|
);
|
|
137
137
|
}
|
|
138
|
-
function cannotStart(executable, cause) {
|
|
138
|
+
function cannotStart(executable, cause, purpose) {
|
|
139
139
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
140
|
+
if (purpose !== void 0) {
|
|
141
|
+
return new import_core.PenvError(
|
|
142
|
+
"PENV_COMMAND_NOT_STARTED",
|
|
143
|
+
`penv could not start \`${executable}\` to ${purpose}: ${detail}`,
|
|
144
|
+
`Check that \`${executable}\` runs on its own \u2014 penv starts it the way your shell does, so it has to be on PATH. Nothing was changed.`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
140
147
|
return new import_core.PenvError(
|
|
141
148
|
"RUN_COMMAND_NOT_STARTED",
|
|
142
149
|
`\`${executable}\` could not be started: ${detail}`,
|
|
@@ -165,12 +172,15 @@ function cmdCommandLine(resolved, args) {
|
|
|
165
172
|
" "
|
|
166
173
|
);
|
|
167
174
|
}
|
|
168
|
-
function extensions(env) {
|
|
175
|
+
function extensions(env, platform) {
|
|
176
|
+
if (platform !== "win32") {
|
|
177
|
+
return [""];
|
|
178
|
+
}
|
|
169
179
|
const declared = env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD";
|
|
170
|
-
return [
|
|
180
|
+
return [...declared.split(";").filter((extension) => extension.length > 0), ""];
|
|
171
181
|
}
|
|
172
|
-
function findExecutable(executable, env) {
|
|
173
|
-
const candidates = extensions(env);
|
|
182
|
+
function findExecutable(executable, env, platform = process.platform) {
|
|
183
|
+
const candidates = extensions(env, platform);
|
|
174
184
|
const isFile = (path2) => (0, import_node_fs.existsSync)(path2) && (0, import_node_fs.statSync)(path2).isFile();
|
|
175
185
|
if (executable.includes("/") || executable.includes("\\") || (0, import_node_path.isAbsolute)(executable)) {
|
|
176
186
|
return candidates.map((extension) => executable + extension).find(isFile);
|
|
@@ -197,6 +207,7 @@ function escapeArgument(argument, doubleEscape) {
|
|
|
197
207
|
// src/install.ts
|
|
198
208
|
var import_meta = {};
|
|
199
209
|
var RUNTIME_PACKAGE = "@penvhq/penv";
|
|
210
|
+
var SCHEMA_PACKAGE = "zod";
|
|
200
211
|
var LOCKFILES = [
|
|
201
212
|
["pnpm", "pnpm-lock.yaml"],
|
|
202
213
|
["yarn", "yarn.lock"],
|
|
@@ -211,13 +222,9 @@ var ADD = {
|
|
|
211
222
|
bun: ["bun", "add", "--exact"]
|
|
212
223
|
};
|
|
213
224
|
function engineVersion() {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (typeof version === "string" && version.length > 0) {
|
|
218
|
-
return version;
|
|
219
|
-
}
|
|
220
|
-
} catch {
|
|
225
|
+
const version = ownManifest()?.version;
|
|
226
|
+
if (typeof version === "string" && version.length > 0) {
|
|
227
|
+
return version;
|
|
221
228
|
}
|
|
222
229
|
throw new import_core2.PenvError(
|
|
223
230
|
"ENGINE_VERSION_UNREADABLE",
|
|
@@ -225,6 +232,29 @@ function engineVersion() {
|
|
|
225
232
|
`Reinstall penv, then run \`penv init\` again.`
|
|
226
233
|
);
|
|
227
234
|
}
|
|
235
|
+
function schemaPackageVersion() {
|
|
236
|
+
const peers = ownManifest()?.peerDependencies;
|
|
237
|
+
const declared = peers !== null && typeof peers === "object" && !Array.isArray(peers) ? peers[SCHEMA_PACKAGE] : void 0;
|
|
238
|
+
const floor = typeof declared === "string" ? declared.replace(/^[\^~>=\s]+/, "").trim() : "";
|
|
239
|
+
if (floor.length > 0) {
|
|
240
|
+
return floor;
|
|
241
|
+
}
|
|
242
|
+
throw new import_core2.PenvError(
|
|
243
|
+
"ENGINE_PEER_UNREADABLE",
|
|
244
|
+
`penv could not read its own \`${SCHEMA_PACKAGE}\` peer range, so it cannot say which ${SCHEMA_PACKAGE} this project needs`,
|
|
245
|
+
`Reinstall penv, then run \`penv init\` again.`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
function ownManifest() {
|
|
249
|
+
try {
|
|
250
|
+
const parsed = JSON.parse(
|
|
251
|
+
(0, import_node_fs2.readFileSync)(new URL("../package.json", import_meta.url), "utf8")
|
|
252
|
+
);
|
|
253
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
254
|
+
} catch {
|
|
255
|
+
return void 0;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
228
258
|
function detectPackageManager(root) {
|
|
229
259
|
for (const [manager, lockfile] of LOCKFILES) {
|
|
230
260
|
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, lockfile))) {
|
|
@@ -253,12 +283,12 @@ function manifestOf(root) {
|
|
|
253
283
|
return void 0;
|
|
254
284
|
}
|
|
255
285
|
}
|
|
256
|
-
function declaredVersion(root) {
|
|
286
|
+
function declaredVersion(root, name) {
|
|
257
287
|
const manifest = manifestOf(root);
|
|
258
288
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
259
289
|
const block = manifest?.[field];
|
|
260
290
|
if (block !== null && typeof block === "object" && !Array.isArray(block)) {
|
|
261
|
-
const version = block[
|
|
291
|
+
const version = block[name];
|
|
262
292
|
if (typeof version === "string") {
|
|
263
293
|
return version;
|
|
264
294
|
}
|
|
@@ -271,27 +301,61 @@ function planInstall(root, version = engineVersion()) {
|
|
|
271
301
|
const lockfile = LOCKFILES.find(
|
|
272
302
|
([name, file]) => name === manager && (0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, file))
|
|
273
303
|
)?.[1];
|
|
274
|
-
const
|
|
304
|
+
const runtimeDeclared = declaredVersion(root, RUNTIME_PACKAGE);
|
|
305
|
+
const zodDeclared = declaredVersion(root, SCHEMA_PACKAGE);
|
|
306
|
+
const packages = [
|
|
307
|
+
{
|
|
308
|
+
name: RUNTIME_PACKAGE,
|
|
309
|
+
version,
|
|
310
|
+
...runtimeDeclared === void 0 ? {} : { declared: runtimeDeclared },
|
|
311
|
+
satisfied: runtimeDeclared === version
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: SCHEMA_PACKAGE,
|
|
315
|
+
version: schemaPackageVersion(),
|
|
316
|
+
...zodDeclared === void 0 ? {} : { declared: zodDeclared },
|
|
317
|
+
// Any declared zod counts: which zod a project uses is the project's
|
|
318
|
+
// decision, and penv is here to make sure there is one, not to move it.
|
|
319
|
+
satisfied: zodDeclared !== void 0
|
|
320
|
+
}
|
|
321
|
+
];
|
|
322
|
+
const pending = packages.filter((entry) => !entry.satisfied);
|
|
323
|
+
const specs = (pending.length === 0 ? packages : pending).map(
|
|
324
|
+
(entry) => `${entry.name}@${entry.version}`
|
|
325
|
+
);
|
|
275
326
|
return {
|
|
276
327
|
root,
|
|
277
328
|
manager,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
command: [...ADD[manager], `${RUNTIME_PACKAGE}@${version}`],
|
|
329
|
+
packages,
|
|
330
|
+
command: [...ADD[manager], ...specs],
|
|
281
331
|
...lockfile === void 0 ? {} : { lockfile },
|
|
282
|
-
|
|
283
|
-
satisfied: declared === version
|
|
332
|
+
satisfied: pending.length === 0
|
|
284
333
|
};
|
|
285
334
|
}
|
|
335
|
+
function describe(entry) {
|
|
336
|
+
return `${entry.name} ${entry.version}`;
|
|
337
|
+
}
|
|
286
338
|
function renderInstallPlan(plan2) {
|
|
287
339
|
if (plan2.satisfied) {
|
|
288
|
-
return [
|
|
340
|
+
return [
|
|
341
|
+
`package.json already has ${plan2.packages.map(describe).join(" and ")} \u2014 nothing to install.`
|
|
342
|
+
];
|
|
289
343
|
}
|
|
290
|
-
const
|
|
344
|
+
const pending = plan2.packages.filter((entry) => !entry.satisfied);
|
|
345
|
+
const added = pending.filter((entry) => entry.declared === void 0);
|
|
346
|
+
const replaced = pending.filter((entry) => entry.declared !== void 0);
|
|
291
347
|
return [
|
|
292
348
|
"package.json",
|
|
293
|
-
...
|
|
294
|
-
|
|
349
|
+
...added.length === 0 ? [] : [
|
|
350
|
+
' + "dependencies": {',
|
|
351
|
+
...added.map((entry) => ` + "${entry.name}": "${entry.version}"`),
|
|
352
|
+
" + }"
|
|
353
|
+
],
|
|
354
|
+
...replaced.flatMap((entry) => [
|
|
355
|
+
` - "${entry.name}": "${entry.declared}"`,
|
|
356
|
+
` + "${entry.name}": "${entry.version}"`
|
|
357
|
+
]),
|
|
358
|
+
...plan2.lockfile === void 0 ? [] : [plan2.lockfile, ...pending.map((entry) => ` + ${entry.name}@${entry.version}`)],
|
|
295
359
|
"",
|
|
296
360
|
`Run with: ${plan2.command.join(" ")}`
|
|
297
361
|
];
|
|
@@ -300,7 +364,8 @@ var installWithPackageManager = async (plan2) => {
|
|
|
300
364
|
const child = startChild({
|
|
301
365
|
command: plan2.command,
|
|
302
366
|
env: process.env,
|
|
303
|
-
cwd: plan2.root
|
|
367
|
+
cwd: plan2.root,
|
|
368
|
+
purpose: `install ${plan2.packages.map(describe).join(" and ")}`
|
|
304
369
|
});
|
|
305
370
|
const ended = await child.ended;
|
|
306
371
|
if (ended.exitCode !== 0 || ended.signal !== null) {
|
|
@@ -316,7 +381,7 @@ function installFailed(plan2) {
|
|
|
316
381
|
}
|
|
317
382
|
|
|
318
383
|
// src/project.ts
|
|
319
|
-
var
|
|
384
|
+
var import_node_fs4 = require("fs");
|
|
320
385
|
var import_node_path4 = require("path");
|
|
321
386
|
var import_core5 = require("@penvhq/core");
|
|
322
387
|
var import_provider_filesystem2 = require("@penvhq/provider-filesystem");
|
|
@@ -380,6 +445,7 @@ function environmentFromShorthand(config, candidates, explicit) {
|
|
|
380
445
|
}
|
|
381
446
|
|
|
382
447
|
// src/registry.ts
|
|
448
|
+
var import_node_fs3 = require("fs");
|
|
383
449
|
var import_node_module = require("module");
|
|
384
450
|
var import_node_path3 = require("path");
|
|
385
451
|
var import_node_url = require("url");
|
|
@@ -452,16 +518,40 @@ async function loadPluginProvider(type, context) {
|
|
|
452
518
|
assertSatisfiesContract(provider, type);
|
|
453
519
|
return provider;
|
|
454
520
|
}
|
|
455
|
-
function assertProvidersRegistered(config, projectRoot) {
|
|
521
|
+
function assertProvidersRegistered(config, projectRoot, options) {
|
|
522
|
+
const local = localExtensions(projectRoot);
|
|
523
|
+
const ci = options?.ci ?? isCi(process.env.CI);
|
|
456
524
|
for (const [environment, provider] of Object.entries(config.providers)) {
|
|
457
525
|
if (isProviderRegistered(provider.type)) {
|
|
458
526
|
continue;
|
|
459
527
|
}
|
|
528
|
+
if (ci && local.includes(provider.type)) {
|
|
529
|
+
throw localExtensionInCi(provider.type, environment);
|
|
530
|
+
}
|
|
460
531
|
if (resolvePlugin(provider.type, projectRoot) === void 0) {
|
|
461
532
|
throw unknownProvider(provider.type, environment);
|
|
462
533
|
}
|
|
463
534
|
}
|
|
464
535
|
}
|
|
536
|
+
function localExtensions(projectRoot) {
|
|
537
|
+
let text;
|
|
538
|
+
try {
|
|
539
|
+
text = (0, import_node_fs3.readFileSync)((0, import_core4.localExtensionsFile)(projectRoot), "utf8");
|
|
540
|
+
} catch {
|
|
541
|
+
return [];
|
|
542
|
+
}
|
|
543
|
+
return (0, import_core4.parseLocalExtensions)(text);
|
|
544
|
+
}
|
|
545
|
+
function isCi(value) {
|
|
546
|
+
return value !== void 0 && value !== "" && value !== "0" && value.toLowerCase() !== "false";
|
|
547
|
+
}
|
|
548
|
+
function localExtensionInCi(type, environment) {
|
|
549
|
+
return new import_core4.PenvError(
|
|
550
|
+
"LOCAL_EXTENSION_IN_CI",
|
|
551
|
+
`The provider \`${type}\` for environment ${environment} is a local extension, and this is CI`,
|
|
552
|
+
`${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.`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
465
555
|
function resolvePlugin(specifier, fromDir) {
|
|
466
556
|
try {
|
|
467
557
|
const require2 = (0, import_node_module.createRequire)((0, import_node_path3.resolve)(fromDir, "noop.js"));
|
|
@@ -499,7 +589,7 @@ function unknownProvider(type, environment) {
|
|
|
499
589
|
return new import_core4.PenvError(
|
|
500
590
|
"UNKNOWN_PROVIDER",
|
|
501
591
|
`The provider \`${type}\`${where} in penv.config.ts is not installed in this project`,
|
|
502
|
-
`
|
|
592
|
+
`A provider's \`type\` is the package penv imports, so it has to resolve from this project: install it with \`npm i ${type}\`, or \u2014 if this repository is the one that builds it \u2014 run \`penv add --local ${type}\` once it is a dependency of the root. The CLI ships ${preinstalled} pre-installed.`
|
|
503
593
|
);
|
|
504
594
|
}
|
|
505
595
|
|
|
@@ -529,10 +619,10 @@ function localTree(project) {
|
|
|
529
619
|
}
|
|
530
620
|
function selfContainedSchemaModule(root, schemaFile) {
|
|
531
621
|
const file = (0, import_node_path4.join)(root, ...schemaFile.split("/"));
|
|
532
|
-
if (!(0,
|
|
622
|
+
if (!(0, import_node_fs4.existsSync)(file)) {
|
|
533
623
|
return void 0;
|
|
534
624
|
}
|
|
535
|
-
const source = (0,
|
|
625
|
+
const source = (0, import_node_fs4.readFileSync)(file, "utf8");
|
|
536
626
|
return source.includes("PenvSchemaShape") || source.includes("z.object") ? schemaFile : void 0;
|
|
537
627
|
}
|
|
538
628
|
function schemaShapeFileOf(project) {
|
|
@@ -768,10 +858,7 @@ function writeError(lines) {
|
|
|
768
858
|
}
|
|
769
859
|
function reportError(error) {
|
|
770
860
|
if (error instanceof import_core6.PenvError) {
|
|
771
|
-
|
|
772
|
-
${error.remedy}`;
|
|
773
|
-
const message = suffix !== void 0 && error.message.endsWith(suffix) ? error.message.slice(0, -suffix.length) : error.message;
|
|
774
|
-
process.stderr.write(`${err.red(CROSS)} ${message}
|
|
861
|
+
process.stderr.write(`${err.red(CROSS)} ${error.summary}
|
|
775
862
|
`);
|
|
776
863
|
if (error.remedy !== void 0) {
|
|
777
864
|
process.stderr.write(` ${err.cyan("\u2192")} ${error.remedy}
|
|
@@ -801,7 +888,7 @@ async function guard(run) {
|
|
|
801
888
|
}
|
|
802
889
|
|
|
803
890
|
// src/commands/run.ts
|
|
804
|
-
var
|
|
891
|
+
var import_node_fs6 = require("fs");
|
|
805
892
|
var import_node_module2 = require("module");
|
|
806
893
|
var import_node_path6 = require("path");
|
|
807
894
|
var import_core11 = require("@penvhq/core");
|
|
@@ -809,7 +896,7 @@ var import_runtime = require("@penvhq/runtime");
|
|
|
809
896
|
var import_citty3 = require("citty");
|
|
810
897
|
|
|
811
898
|
// src/dotenv-files.ts
|
|
812
|
-
var
|
|
899
|
+
var import_node_fs5 = require("fs");
|
|
813
900
|
var import_core7 = require("@penvhq/core");
|
|
814
901
|
var SHARED = ".env";
|
|
815
902
|
var LOCAL = "local";
|
|
@@ -869,7 +956,7 @@ function order(file) {
|
|
|
869
956
|
function discoverDotenvFiles(root) {
|
|
870
957
|
let entries;
|
|
871
958
|
try {
|
|
872
|
-
entries = (0,
|
|
959
|
+
entries = (0, import_node_fs5.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
|
|
873
960
|
} catch {
|
|
874
961
|
return [];
|
|
875
962
|
}
|
|
@@ -1606,9 +1693,9 @@ function packageManifest(specifier, root) {
|
|
|
1606
1693
|
}
|
|
1607
1694
|
for (; ; ) {
|
|
1608
1695
|
const file = (0, import_node_path6.join)(directory, "package.json");
|
|
1609
|
-
if ((0,
|
|
1696
|
+
if ((0, import_node_fs6.existsSync)(file)) {
|
|
1610
1697
|
try {
|
|
1611
|
-
const parsed = JSON.parse((0,
|
|
1698
|
+
const parsed = JSON.parse((0, import_node_fs6.readFileSync)(file, "utf8"));
|
|
1612
1699
|
if (isPlainObject(parsed) && parsed.name === specifier) {
|
|
1613
1700
|
return parsed;
|
|
1614
1701
|
}
|
|
@@ -1681,7 +1768,7 @@ function snapshotPath(host) {
|
|
|
1681
1768
|
}
|
|
1682
1769
|
function readSnapshot(path) {
|
|
1683
1770
|
try {
|
|
1684
|
-
return (0,
|
|
1771
|
+
return (0, import_node_fs6.readFileSync)(path, "utf8");
|
|
1685
1772
|
} catch {
|
|
1686
1773
|
throw new import_core11.PenvError(
|
|
1687
1774
|
"RUN_SNAPSHOT_MISSING",
|
|
@@ -1760,11 +1847,11 @@ function watchProject(project, onChange) {
|
|
|
1760
1847
|
timer = setTimeout(onChange, DEBOUNCE_MS);
|
|
1761
1848
|
};
|
|
1762
1849
|
const add = (target, recursive, only) => {
|
|
1763
|
-
if (!(0,
|
|
1850
|
+
if (!(0, import_node_fs6.existsSync)(target)) {
|
|
1764
1851
|
return;
|
|
1765
1852
|
}
|
|
1766
1853
|
try {
|
|
1767
|
-
const watcher = (0,
|
|
1854
|
+
const watcher = (0, import_node_fs6.watch)(target, { recursive }, (_event, filename) => {
|
|
1768
1855
|
if (only !== void 0 && (filename === null || (0, import_node_path6.basename)(filename) !== only)) {
|
|
1769
1856
|
return;
|
|
1770
1857
|
}
|
|
@@ -2027,8 +2114,8 @@ ${lines}`,
|
|
|
2027
2114
|
keySource: (0, import_core12.keySourceIdentifier)(project.config, environment),
|
|
2028
2115
|
values
|
|
2029
2116
|
};
|
|
2030
|
-
(0,
|
|
2031
|
-
(0,
|
|
2117
|
+
(0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)(file), { recursive: true });
|
|
2118
|
+
(0, import_node_fs7.writeFileSync)(file, (0, import_core12.serializeArtifact)(artifact), "utf8");
|
|
2032
2119
|
const inside = (0, import_node_path7.relative)(project.root, file);
|
|
2033
2120
|
return {
|
|
2034
2121
|
file,
|
|
@@ -2098,7 +2185,7 @@ var import_core14 = require("@penvhq/core");
|
|
|
2098
2185
|
var import_citty5 = require("citty");
|
|
2099
2186
|
|
|
2100
2187
|
// src/cutover.ts
|
|
2101
|
-
var
|
|
2188
|
+
var import_node_fs8 = require("fs");
|
|
2102
2189
|
var import_node_path8 = require("path");
|
|
2103
2190
|
var import_core13 = require("@penvhq/core");
|
|
2104
2191
|
var CUTOVER_FORMAT = 1;
|
|
@@ -2117,7 +2204,7 @@ function cutoverRoot(cwd) {
|
|
|
2117
2204
|
}
|
|
2118
2205
|
function bundledFiles(root) {
|
|
2119
2206
|
try {
|
|
2120
|
-
return (0,
|
|
2207
|
+
return (0, import_node_fs8.readdirSync)(bundleDir(root)).sort();
|
|
2121
2208
|
} catch {
|
|
2122
2209
|
return [];
|
|
2123
2210
|
}
|
|
@@ -2127,32 +2214,32 @@ function bundleUnresolved(root) {
|
|
|
2127
2214
|
}
|
|
2128
2215
|
function readCutover(root) {
|
|
2129
2216
|
const file = cutoverFile(root);
|
|
2130
|
-
if (!(0,
|
|
2217
|
+
if (!(0, import_node_fs8.existsSync)(file)) {
|
|
2131
2218
|
return void 0;
|
|
2132
2219
|
}
|
|
2133
2220
|
let parsed;
|
|
2134
2221
|
try {
|
|
2135
|
-
parsed = JSON.parse((0,
|
|
2222
|
+
parsed = JSON.parse((0, import_node_fs8.readFileSync)(file, "utf8"));
|
|
2136
2223
|
} catch {
|
|
2137
2224
|
throw unreadable("it is not JSON");
|
|
2138
2225
|
}
|
|
2139
2226
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2140
2227
|
throw unreadable("it is not an object");
|
|
2141
2228
|
}
|
|
2142
|
-
const
|
|
2143
|
-
if (
|
|
2229
|
+
const record2 = parsed;
|
|
2230
|
+
if (record2.format !== CUTOVER_FORMAT) {
|
|
2144
2231
|
throw unreadable(
|
|
2145
|
-
`it is format ${JSON.stringify(
|
|
2232
|
+
`it is format ${JSON.stringify(record2.format)}, and penv reads format ${CUTOVER_FORMAT}`
|
|
2146
2233
|
);
|
|
2147
2234
|
}
|
|
2148
|
-
const files =
|
|
2235
|
+
const files = record2.files;
|
|
2149
2236
|
if (!Array.isArray(files) || files.some((name) => typeof name !== "string")) {
|
|
2150
2237
|
throw unreadable("it lists no filenames");
|
|
2151
2238
|
}
|
|
2152
|
-
const environments = Array.isArray(
|
|
2239
|
+
const environments = Array.isArray(record2.environments) ? record2.environments.filter((name) => typeof name === "string") : [];
|
|
2153
2240
|
return {
|
|
2154
2241
|
format: CUTOVER_FORMAT,
|
|
2155
|
-
movedAt: typeof
|
|
2242
|
+
movedAt: typeof record2.movedAt === "string" ? record2.movedAt : "",
|
|
2156
2243
|
files,
|
|
2157
2244
|
environments
|
|
2158
2245
|
};
|
|
@@ -2185,12 +2272,12 @@ function bundleDotenvFiles(root, files, environments, now = /* @__PURE__ */ new
|
|
|
2185
2272
|
environments: [...environments]
|
|
2186
2273
|
};
|
|
2187
2274
|
const file = cutoverFile(root);
|
|
2188
|
-
(0,
|
|
2189
|
-
(0,
|
|
2275
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(file), { recursive: true });
|
|
2276
|
+
(0, import_node_fs8.writeFileSync)(file, serializeCutover(cutover), "utf8");
|
|
2190
2277
|
const bundle = bundleDir(root);
|
|
2191
|
-
(0,
|
|
2278
|
+
(0, import_node_fs8.mkdirSync)(bundle, { recursive: true });
|
|
2192
2279
|
for (const name of files) {
|
|
2193
|
-
(0,
|
|
2280
|
+
(0, import_node_fs8.renameSync)((0, import_node_path8.join)(root, name), (0, import_node_path8.join)(bundle, name));
|
|
2194
2281
|
}
|
|
2195
2282
|
return cutover;
|
|
2196
2283
|
}
|
|
@@ -2209,7 +2296,7 @@ function runUndo(options) {
|
|
|
2209
2296
|
const names = [...recorded, ...bundled.filter((name) => !recorded.includes(name))];
|
|
2210
2297
|
const bundle = bundleDir(root);
|
|
2211
2298
|
const held = new Set(bundled);
|
|
2212
|
-
const occupied2 = names.filter((name) => held.has(name) && (0,
|
|
2299
|
+
const occupied2 = names.filter((name) => held.has(name) && (0, import_node_fs8.existsSync)((0, import_node_path8.join)(root, name)));
|
|
2213
2300
|
if (occupied2.length > 0) {
|
|
2214
2301
|
const listed = occupied2.join(", ");
|
|
2215
2302
|
const many = occupied2.length > 1;
|
|
@@ -2224,9 +2311,9 @@ function runUndo(options) {
|
|
|
2224
2311
|
const missing = [];
|
|
2225
2312
|
for (const name of names) {
|
|
2226
2313
|
if (held.has(name)) {
|
|
2227
|
-
(0,
|
|
2314
|
+
(0, import_node_fs8.renameSync)((0, import_node_path8.join)(bundle, name), (0, import_node_path8.join)(root, name));
|
|
2228
2315
|
restored.push(name);
|
|
2229
|
-
} else if ((0,
|
|
2316
|
+
} else if ((0, import_node_fs8.existsSync)((0, import_node_path8.join)(root, name))) {
|
|
2230
2317
|
alreadyBack.push(name);
|
|
2231
2318
|
} else {
|
|
2232
2319
|
missing.push(name);
|
|
@@ -2238,13 +2325,13 @@ function runUndo(options) {
|
|
|
2238
2325
|
function runCleanup(options) {
|
|
2239
2326
|
const root = cutoverRoot(options.cwd);
|
|
2240
2327
|
const held = bundledFiles(root);
|
|
2241
|
-
const cleaned = held.length > 0 || (0,
|
|
2328
|
+
const cleaned = held.length > 0 || (0, import_node_fs8.existsSync)(cutoverFile(root)) || (0, import_node_fs8.existsSync)(fileFor(root, import_core13.ROLLBACK_PATH));
|
|
2242
2329
|
removeBundle(root);
|
|
2243
2330
|
return { root, removed: held, cleaned };
|
|
2244
2331
|
}
|
|
2245
2332
|
function removeBundle(root) {
|
|
2246
|
-
(0,
|
|
2247
|
-
(0,
|
|
2333
|
+
(0, import_node_fs8.rmSync)(fileFor(root, import_core13.ROLLBACK_PATH), { recursive: true, force: true });
|
|
2334
|
+
(0, import_node_fs8.rmSync)(cutoverFile(root), { force: true });
|
|
2248
2335
|
}
|
|
2249
2336
|
|
|
2250
2337
|
// src/commands/cleanup.ts
|
|
@@ -2279,7 +2366,7 @@ var cleanupCommand = (0, import_citty5.defineCommand)({
|
|
|
2279
2366
|
});
|
|
2280
2367
|
|
|
2281
2368
|
// src/commands/doctor.ts
|
|
2282
|
-
var
|
|
2369
|
+
var import_node_fs9 = require("fs");
|
|
2283
2370
|
var import_node_path9 = require("path");
|
|
2284
2371
|
var import_core16 = require("@penvhq/core");
|
|
2285
2372
|
var import_citty7 = require("citty");
|
|
@@ -2725,6 +2812,7 @@ async function runDoctor(options) {
|
|
|
2725
2812
|
findings.push(...unusedFindings(drift));
|
|
2726
2813
|
}
|
|
2727
2814
|
findings.push(...fallbackFindings(subjects, environment));
|
|
2815
|
+
findings.push(...secrecyFindings(subjects, environment));
|
|
2728
2816
|
findings.push(...plaintextSecretFindings(subjects, environment));
|
|
2729
2817
|
findings.push(...publicSecretFindings(subjects, environment, project.config));
|
|
2730
2818
|
findings.push(...encryptionFindings(subjects, environment));
|
|
@@ -2737,6 +2825,7 @@ async function runDoctor(options) {
|
|
|
2737
2825
|
}
|
|
2738
2826
|
findings.push(...await providerDriftFindings(project, environment, options.source));
|
|
2739
2827
|
findings.push(...await projectionFindings(project, environment, options.projection));
|
|
2828
|
+
findings.push(...localExtensionFindings(project));
|
|
2740
2829
|
findings.push(...artifactFindings(project));
|
|
2741
2830
|
findings.push({
|
|
2742
2831
|
check: "provider",
|
|
@@ -2874,6 +2963,31 @@ function fallbackFindings(subjects, environment) {
|
|
|
2874
2963
|
}
|
|
2875
2964
|
];
|
|
2876
2965
|
}
|
|
2966
|
+
function secrecyFindings(subjects, environment) {
|
|
2967
|
+
const undeclared = subjects.filter(
|
|
2968
|
+
({ meta }) => (0, import_core16.effectiveMeta)(meta, environment).secret === void 0
|
|
2969
|
+
);
|
|
2970
|
+
if (undeclared.length === 0) {
|
|
2971
|
+
return [
|
|
2972
|
+
{
|
|
2973
|
+
check: "secrecy-undeclared",
|
|
2974
|
+
severity: "pass",
|
|
2975
|
+
label: "Secrecy policy",
|
|
2976
|
+
subject: subjects.length === 0 ? `no parameter resolves for ${environment}` : `every parameter declares whether it is secret for ${environment}`
|
|
2977
|
+
}
|
|
2978
|
+
];
|
|
2979
|
+
}
|
|
2980
|
+
return [
|
|
2981
|
+
{
|
|
2982
|
+
check: "secrecy-undeclared",
|
|
2983
|
+
severity: "unknown",
|
|
2984
|
+
label: "Secrecy policy",
|
|
2985
|
+
subject: `${undeclared.length} of ${subjects.length} declare neither way for ${environment}`,
|
|
2986
|
+
detail: "penv was never told which of these values must be encrypted",
|
|
2987
|
+
remedy: `declare \`"secret": true\` or \`"secret": false\` in a parameter's meta file, ${import_core16.RECORDS_PATH}/<name>.json`
|
|
2988
|
+
}
|
|
2989
|
+
];
|
|
2990
|
+
}
|
|
2877
2991
|
function plaintextSecretFindings(subjects, environment) {
|
|
2878
2992
|
const secrets = subjects.filter(({ meta }) => (0, import_core16.isSecret)(meta, environment));
|
|
2879
2993
|
const findings = [];
|
|
@@ -3177,7 +3291,7 @@ function looksLikeArtifact(text) {
|
|
|
3177
3291
|
function scannableFiles(directory, out2) {
|
|
3178
3292
|
let entries;
|
|
3179
3293
|
try {
|
|
3180
|
-
entries = (0,
|
|
3294
|
+
entries = (0, import_node_fs9.readdirSync)(directory, { withFileTypes: true });
|
|
3181
3295
|
} catch {
|
|
3182
3296
|
return;
|
|
3183
3297
|
}
|
|
@@ -3194,6 +3308,29 @@ function scannableFiles(directory, out2) {
|
|
|
3194
3308
|
}
|
|
3195
3309
|
}
|
|
3196
3310
|
}
|
|
3311
|
+
function localExtensionFindings(project) {
|
|
3312
|
+
const names = localExtensions(project.root);
|
|
3313
|
+
if (names.length === 0) {
|
|
3314
|
+
return [
|
|
3315
|
+
{
|
|
3316
|
+
check: "local-extension",
|
|
3317
|
+
severity: "pass",
|
|
3318
|
+
label: "Extensions",
|
|
3319
|
+
subject: "every extension this project names is pinned"
|
|
3320
|
+
}
|
|
3321
|
+
];
|
|
3322
|
+
}
|
|
3323
|
+
return [
|
|
3324
|
+
{
|
|
3325
|
+
check: "local-extension",
|
|
3326
|
+
severity: "unknown",
|
|
3327
|
+
label: "Extensions",
|
|
3328
|
+
subject: names.join(", "),
|
|
3329
|
+
detail: "resolved from this project's node_modules \u2014 no release, no pinned bytes",
|
|
3330
|
+
remedy: `publish it and run \`penv add ${names[0]}\` when this stops being a development path`
|
|
3331
|
+
}
|
|
3332
|
+
];
|
|
3333
|
+
}
|
|
3197
3334
|
function artifactFindings(project) {
|
|
3198
3335
|
const files = [];
|
|
3199
3336
|
scannableFiles(project.root, files);
|
|
@@ -3201,10 +3338,10 @@ function artifactFindings(project) {
|
|
|
3201
3338
|
for (const file of files) {
|
|
3202
3339
|
let text;
|
|
3203
3340
|
try {
|
|
3204
|
-
if ((0,
|
|
3341
|
+
if ((0, import_node_fs9.statSync)(file).size > ARTIFACT_SCAN_LIMIT) {
|
|
3205
3342
|
continue;
|
|
3206
3343
|
}
|
|
3207
|
-
text = (0,
|
|
3344
|
+
text = (0, import_node_fs9.readFileSync)(file, "utf8");
|
|
3208
3345
|
} catch {
|
|
3209
3346
|
continue;
|
|
3210
3347
|
}
|
|
@@ -3964,7 +4101,7 @@ var fillCommand = (0, import_citty10.defineCommand)({
|
|
|
3964
4101
|
});
|
|
3965
4102
|
|
|
3966
4103
|
// src/commands/generate.ts
|
|
3967
|
-
var
|
|
4104
|
+
var import_node_fs10 = require("fs");
|
|
3968
4105
|
var import_node_path10 = require("path");
|
|
3969
4106
|
var import_core20 = require("@penvhq/core");
|
|
3970
4107
|
var import_citty11 = require("citty");
|
|
@@ -4018,7 +4155,7 @@ function runGenerate(options) {
|
|
|
4018
4155
|
const environment = targetEnvironment(project, options.environment, options.envFlags);
|
|
4019
4156
|
const { entries, decrypted } = entriesFor(project, environment, options.allowDecrypt === true);
|
|
4020
4157
|
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);
|
|
4021
|
-
(0,
|
|
4158
|
+
(0, import_node_fs10.writeFileSync)(file, (0, import_core20.serializeDotenv)(entries), "utf8");
|
|
4022
4159
|
return { file, environment, entries: entries.length, decrypted };
|
|
4023
4160
|
}
|
|
4024
4161
|
function displayPath2(cwd, file) {
|
|
@@ -4156,8 +4293,8 @@ var getCommand = (0, import_citty12.defineCommand)({
|
|
|
4156
4293
|
});
|
|
4157
4294
|
|
|
4158
4295
|
// src/commands/import.ts
|
|
4159
|
-
var
|
|
4160
|
-
var
|
|
4296
|
+
var import_node_fs14 = require("fs");
|
|
4297
|
+
var import_node_path14 = require("path");
|
|
4161
4298
|
var import_core26 = require("@penvhq/core");
|
|
4162
4299
|
var import_citty14 = require("citty");
|
|
4163
4300
|
|
|
@@ -4227,7 +4364,7 @@ function writeEntries(tree, entries, refs, scope) {
|
|
|
4227
4364
|
}
|
|
4228
4365
|
|
|
4229
4366
|
// src/detect.ts
|
|
4230
|
-
var
|
|
4367
|
+
var import_node_fs11 = require("fs");
|
|
4231
4368
|
var import_node_path11 = require("path");
|
|
4232
4369
|
var import_core23 = require("@penvhq/core");
|
|
4233
4370
|
var SIGNATURES = [
|
|
@@ -4245,7 +4382,7 @@ var SIGNATURES = [
|
|
|
4245
4382
|
function exportsSchema(file) {
|
|
4246
4383
|
let source;
|
|
4247
4384
|
try {
|
|
4248
|
-
source = (0,
|
|
4385
|
+
source = (0, import_node_fs11.readFileSync)(file, "utf8");
|
|
4249
4386
|
} catch {
|
|
4250
4387
|
return false;
|
|
4251
4388
|
}
|
|
@@ -4257,7 +4394,7 @@ function exportsSchema(file) {
|
|
|
4257
4394
|
}
|
|
4258
4395
|
function occupied(cwd, relative5) {
|
|
4259
4396
|
const file = (0, import_node_path11.join)(cwd, ...relative5.split("/"));
|
|
4260
|
-
return (0,
|
|
4397
|
+
return (0, import_node_fs11.existsSync)(file) && !exportsSchema(file);
|
|
4261
4398
|
}
|
|
4262
4399
|
function schemaFileFor(cwd) {
|
|
4263
4400
|
const dir = srcPrefix(cwd);
|
|
@@ -4272,7 +4409,7 @@ function schemaFileFor(cwd) {
|
|
|
4272
4409
|
return { file: import_core23.DEFAULT_SCHEMA_FILE, displaced: preferred };
|
|
4273
4410
|
}
|
|
4274
4411
|
function srcPrefix(cwd) {
|
|
4275
|
-
return (0,
|
|
4412
|
+
return (0, import_node_fs11.existsSync)((0, import_node_path11.join)(cwd, "src")) ? "src/" : "";
|
|
4276
4413
|
}
|
|
4277
4414
|
function dependenciesOf(cwd) {
|
|
4278
4415
|
const manifest = manifestOf2(cwd);
|
|
@@ -4292,12 +4429,12 @@ function dependenciesOf(cwd) {
|
|
|
4292
4429
|
}
|
|
4293
4430
|
function manifestOf2(cwd) {
|
|
4294
4431
|
const file = (0, import_node_path11.join)(cwd, "package.json");
|
|
4295
|
-
if (!(0,
|
|
4432
|
+
if (!(0, import_node_fs11.existsSync)(file)) {
|
|
4296
4433
|
return void 0;
|
|
4297
4434
|
}
|
|
4298
4435
|
let manifest;
|
|
4299
4436
|
try {
|
|
4300
|
-
manifest = JSON.parse((0,
|
|
4437
|
+
manifest = JSON.parse((0, import_node_fs11.readFileSync)(file, "utf8"));
|
|
4301
4438
|
} catch {
|
|
4302
4439
|
return void 0;
|
|
4303
4440
|
}
|
|
@@ -4313,7 +4450,7 @@ function detectFramework(cwd) {
|
|
|
4313
4450
|
return detectedFrom(cwd, signature.name, signature.publicPrefixes);
|
|
4314
4451
|
}
|
|
4315
4452
|
}
|
|
4316
|
-
if ((0,
|
|
4453
|
+
if ((0, import_node_fs11.existsSync)((0, import_node_path11.join)(cwd, "bunfig.toml")) || dependencies.has("bun-types")) {
|
|
4317
4454
|
return detectedFrom(cwd, "Bun", []);
|
|
4318
4455
|
}
|
|
4319
4456
|
return void 0;
|
|
@@ -4392,12 +4529,94 @@ function draftFieldsAcross(sources, environments) {
|
|
|
4392
4529
|
}
|
|
4393
4530
|
|
|
4394
4531
|
// src/commands/init.ts
|
|
4395
|
-
var
|
|
4396
|
-
var
|
|
4532
|
+
var import_node_fs13 = require("fs");
|
|
4533
|
+
var import_node_path13 = require("path");
|
|
4397
4534
|
var import_promises = require("readline/promises");
|
|
4398
4535
|
var import_core25 = require("@penvhq/core");
|
|
4399
4536
|
var import_citty13 = require("citty");
|
|
4400
4537
|
|
|
4538
|
+
// src/scaffold-undo.ts
|
|
4539
|
+
var import_node_fs12 = require("fs");
|
|
4540
|
+
var import_node_path12 = require("path");
|
|
4541
|
+
function record(path, files, dirs) {
|
|
4542
|
+
let stats;
|
|
4543
|
+
try {
|
|
4544
|
+
stats = (0, import_node_fs12.statSync)(path);
|
|
4545
|
+
} catch {
|
|
4546
|
+
return;
|
|
4547
|
+
}
|
|
4548
|
+
if (stats.isDirectory()) {
|
|
4549
|
+
dirs.add(path);
|
|
4550
|
+
for (const entry of (0, import_node_fs12.readdirSync)(path)) {
|
|
4551
|
+
record((0, import_node_path12.join)(path, entry), files, dirs);
|
|
4552
|
+
}
|
|
4553
|
+
return;
|
|
4554
|
+
}
|
|
4555
|
+
if (stats.isFile()) {
|
|
4556
|
+
files.set(path, (0, import_node_fs12.readFileSync)(path));
|
|
4557
|
+
}
|
|
4558
|
+
}
|
|
4559
|
+
function captureScaffold(root, paths) {
|
|
4560
|
+
const files = /* @__PURE__ */ new Map();
|
|
4561
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
4562
|
+
for (const path of paths) {
|
|
4563
|
+
for (let dir = (0, import_node_path12.dirname)(path); dir.startsWith(root) && dir !== root; dir = (0, import_node_path12.dirname)(dir)) {
|
|
4564
|
+
if ((0, import_node_fs12.existsSync)(dir)) {
|
|
4565
|
+
dirs.add(dir);
|
|
4566
|
+
}
|
|
4567
|
+
}
|
|
4568
|
+
record(path, files, dirs);
|
|
4569
|
+
}
|
|
4570
|
+
return { root, paths: [...paths], files, dirs };
|
|
4571
|
+
}
|
|
4572
|
+
function restoreScaffold(undo) {
|
|
4573
|
+
for (const path of undo.paths) {
|
|
4574
|
+
removeAdded(path, undo);
|
|
4575
|
+
}
|
|
4576
|
+
for (const path of undo.paths) {
|
|
4577
|
+
pruneAncestors(path, undo);
|
|
4578
|
+
}
|
|
4579
|
+
for (const [file, contents] of undo.files) {
|
|
4580
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path12.dirname)(file), { recursive: true });
|
|
4581
|
+
(0, import_node_fs12.writeFileSync)(file, contents);
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
function removeAdded(path, undo) {
|
|
4585
|
+
let stats;
|
|
4586
|
+
try {
|
|
4587
|
+
stats = (0, import_node_fs12.statSync)(path);
|
|
4588
|
+
} catch {
|
|
4589
|
+
return;
|
|
4590
|
+
}
|
|
4591
|
+
if (stats.isFile()) {
|
|
4592
|
+
if (!undo.files.has(path)) {
|
|
4593
|
+
(0, import_node_fs12.unlinkSync)(path);
|
|
4594
|
+
}
|
|
4595
|
+
return;
|
|
4596
|
+
}
|
|
4597
|
+
if (!stats.isDirectory()) {
|
|
4598
|
+
return;
|
|
4599
|
+
}
|
|
4600
|
+
for (const entry of (0, import_node_fs12.readdirSync)(path)) {
|
|
4601
|
+
removeAdded((0, import_node_path12.join)(path, entry), undo);
|
|
4602
|
+
}
|
|
4603
|
+
if (!undo.dirs.has(path) && (0, import_node_fs12.readdirSync)(path).length === 0) {
|
|
4604
|
+
(0, import_node_fs12.rmdirSync)(path);
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
function pruneAncestors(path, undo) {
|
|
4608
|
+
for (let dir = (0, import_node_path12.dirname)(path); dir.startsWith(undo.root) && dir !== undo.root; dir = (0, import_node_path12.dirname)(dir)) {
|
|
4609
|
+
if (undo.dirs.has(dir)) {
|
|
4610
|
+
return;
|
|
4611
|
+
}
|
|
4612
|
+
try {
|
|
4613
|
+
(0, import_node_fs12.rmdirSync)(dir);
|
|
4614
|
+
} catch {
|
|
4615
|
+
return;
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4401
4620
|
// src/seams.ts
|
|
4402
4621
|
function nextjs({ alias, srcDir }) {
|
|
4403
4622
|
return {
|
|
@@ -4553,7 +4772,7 @@ var NOT_ENVIRONMENTS2 = [...import_core25.RESERVED_TOKENS, "example", "sample",
|
|
|
4553
4772
|
function suggestEnvironments(root) {
|
|
4554
4773
|
let entries;
|
|
4555
4774
|
try {
|
|
4556
|
-
entries = (0,
|
|
4775
|
+
entries = (0, import_node_fs13.readdirSync)(root);
|
|
4557
4776
|
} catch {
|
|
4558
4777
|
return [];
|
|
4559
4778
|
}
|
|
@@ -4597,8 +4816,8 @@ function configOf(decisions) {
|
|
|
4597
4816
|
return { environments: decisions.environments, providers: {}, schemaFile: decisions.schemaFile };
|
|
4598
4817
|
}
|
|
4599
4818
|
function declaredIn(root) {
|
|
4600
|
-
const file = (0,
|
|
4601
|
-
if (!(0,
|
|
4819
|
+
const file = (0, import_node_path13.join)(root, CONFIG_FILE);
|
|
4820
|
+
if (!(0, import_node_fs13.existsSync)(file)) {
|
|
4602
4821
|
return void 0;
|
|
4603
4822
|
}
|
|
4604
4823
|
return (0, import_core25.loadConfigFrom)(file);
|
|
@@ -5040,16 +5259,16 @@ function renderTsconfig(target, alias) {
|
|
|
5040
5259
|
`;
|
|
5041
5260
|
}
|
|
5042
5261
|
function ensurePenvDir(root) {
|
|
5043
|
-
const dir = (0,
|
|
5044
|
-
if ((0,
|
|
5262
|
+
const dir = (0, import_node_path13.resolve)(root, import_core25.PENV_DIR);
|
|
5263
|
+
if ((0, import_node_fs13.existsSync)(dir)) {
|
|
5045
5264
|
return { target: "penv-dir", action: "kept", text: `Found ${import_core25.PENV_DIR}/` };
|
|
5046
5265
|
}
|
|
5047
|
-
(0,
|
|
5266
|
+
(0, import_node_fs13.mkdirSync)(dir, { recursive: true });
|
|
5048
5267
|
return { target: "penv-dir", action: "created", text: `Created ${import_core25.PENV_DIR}/` };
|
|
5049
5268
|
}
|
|
5050
5269
|
function writeSchemaShapeFile(root, fields, draft, decisions = DEFAULT_DECISIONS) {
|
|
5051
|
-
const file = (0,
|
|
5052
|
-
if ((0,
|
|
5270
|
+
const file = (0, import_node_path13.join)(root, import_core25.SCHEMA_SHAPE_FILE);
|
|
5271
|
+
if ((0, import_node_fs13.existsSync)(file)) {
|
|
5053
5272
|
return {
|
|
5054
5273
|
target: "schema",
|
|
5055
5274
|
action: "kept",
|
|
@@ -5066,7 +5285,7 @@ function writeSchemaShapeFile(root, fields, draft, decisions = DEFAULT_DECISIONS
|
|
|
5066
5285
|
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\`.)`
|
|
5067
5286
|
};
|
|
5068
5287
|
}
|
|
5069
|
-
(0,
|
|
5288
|
+
(0, import_node_fs13.writeFileSync)(file, renderSchemaShapeModule(fields, draft), "utf8");
|
|
5070
5289
|
return {
|
|
5071
5290
|
target: "schema",
|
|
5072
5291
|
action: "created",
|
|
@@ -5075,8 +5294,8 @@ function writeSchemaShapeFile(root, fields, draft, decisions = DEFAULT_DECISIONS
|
|
|
5075
5294
|
};
|
|
5076
5295
|
}
|
|
5077
5296
|
function writeEnvFile(root, decisions = DEFAULT_DECISIONS) {
|
|
5078
|
-
const file = (0,
|
|
5079
|
-
if ((0,
|
|
5297
|
+
const file = (0, import_node_path13.join)(root, ...decisions.schemaFile.split("/"));
|
|
5298
|
+
if ((0, import_node_fs13.existsSync)(file)) {
|
|
5080
5299
|
return {
|
|
5081
5300
|
target: "env",
|
|
5082
5301
|
action: "kept",
|
|
@@ -5084,8 +5303,8 @@ function writeEnvFile(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5084
5303
|
note: "(yours \u2014 penv never regenerates it)"
|
|
5085
5304
|
};
|
|
5086
5305
|
}
|
|
5087
|
-
(0,
|
|
5088
|
-
(0,
|
|
5306
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
|
|
5307
|
+
(0, import_node_fs13.writeFileSync)(file, renderEnvModule(decisions.schemaFile, decisions.inject), "utf8");
|
|
5089
5308
|
return {
|
|
5090
5309
|
target: "env",
|
|
5091
5310
|
action: "created",
|
|
@@ -5094,19 +5313,19 @@ function writeEnvFile(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5094
5313
|
};
|
|
5095
5314
|
}
|
|
5096
5315
|
function writeConfigFile(root, decisions = DEFAULT_DECISIONS) {
|
|
5097
|
-
const file = (0,
|
|
5098
|
-
if ((0,
|
|
5316
|
+
const file = (0, import_node_path13.join)(root, CONFIG_FILE);
|
|
5317
|
+
if ((0, import_node_fs13.existsSync)(file)) {
|
|
5099
5318
|
return { target: "config", action: "kept", text: `Kept ${CONFIG_FILE}` };
|
|
5100
5319
|
}
|
|
5101
|
-
(0,
|
|
5320
|
+
(0, import_node_fs13.writeFileSync)(file, renderConfigModule(decisions), "utf8");
|
|
5102
5321
|
return { target: "config", action: "created", text: `Generated ${CONFIG_FILE}` };
|
|
5103
5322
|
}
|
|
5104
5323
|
function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
|
|
5105
5324
|
const alias = decisions.alias;
|
|
5106
5325
|
const imports = alias.startsWith(IMPORTS_PREFIX);
|
|
5107
|
-
const file = (0,
|
|
5326
|
+
const file = (0, import_node_path13.join)(root, imports ? PACKAGE_FILE : TSCONFIG_FILE);
|
|
5108
5327
|
const where = imports ? PACKAGE_FILE : TSCONFIG_FILE;
|
|
5109
|
-
if (!(0,
|
|
5328
|
+
if (!(0, import_node_fs13.existsSync)(file)) {
|
|
5110
5329
|
if (imports) {
|
|
5111
5330
|
return {
|
|
5112
5331
|
target: "tsconfig",
|
|
@@ -5115,14 +5334,14 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5115
5334
|
note: `(run \`npm init\` first, or use \`--alias @env\` to alias through ${TSCONFIG_FILE})`
|
|
5116
5335
|
};
|
|
5117
5336
|
}
|
|
5118
|
-
(0,
|
|
5337
|
+
(0, import_node_fs13.writeFileSync)(file, renderTsconfig(decisions.schemaFile, alias), "utf8");
|
|
5119
5338
|
return {
|
|
5120
5339
|
target: "tsconfig",
|
|
5121
5340
|
action: "created",
|
|
5122
5341
|
text: `Created ${TSCONFIG_FILE} with the ${alias} path alias`
|
|
5123
5342
|
};
|
|
5124
5343
|
}
|
|
5125
|
-
const source = (0,
|
|
5344
|
+
const source = (0, import_node_fs13.readFileSync)(file, "utf8");
|
|
5126
5345
|
const edit = imports ? insertImportsAlias(source, decisions.schemaFile, alias) : insertEnvAlias(source, decisions.schemaFile, alias);
|
|
5127
5346
|
if (edit.conflict !== void 0) {
|
|
5128
5347
|
return {
|
|
@@ -5139,7 +5358,7 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5139
5358
|
text: `Kept the ${alias} alias in ${where}`
|
|
5140
5359
|
};
|
|
5141
5360
|
}
|
|
5142
|
-
(0,
|
|
5361
|
+
(0, import_node_fs13.writeFileSync)(file, edit.source, "utf8");
|
|
5143
5362
|
return {
|
|
5144
5363
|
target: "tsconfig",
|
|
5145
5364
|
action: "updated",
|
|
@@ -5147,14 +5366,14 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5147
5366
|
};
|
|
5148
5367
|
}
|
|
5149
5368
|
function writeGitignore(root, decisions = DEFAULT_DECISIONS) {
|
|
5150
|
-
const file = (0,
|
|
5369
|
+
const file = (0, import_node_path13.join)(root, ...import_core25.STATE_GITIGNORE_PATH.split("/"));
|
|
5151
5370
|
const wanted = (0, import_core25.renderStateGitignore)(configOf(decisions));
|
|
5152
|
-
const existing = (0,
|
|
5371
|
+
const existing = (0, import_node_fs13.existsSync)(file) ? (0, import_node_fs13.readFileSync)(file, "utf8") : void 0;
|
|
5153
5372
|
if (existing === wanted) {
|
|
5154
5373
|
return { target: "gitignore", action: "kept", text: `Kept ${import_core25.STATE_GITIGNORE_PATH}` };
|
|
5155
5374
|
}
|
|
5156
|
-
(0,
|
|
5157
|
-
(0,
|
|
5375
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
|
|
5376
|
+
(0, import_node_fs13.writeFileSync)(file, wanted, "utf8");
|
|
5158
5377
|
return {
|
|
5159
5378
|
target: "gitignore",
|
|
5160
5379
|
action: existing === void 0 ? "created" : "updated",
|
|
@@ -5170,12 +5389,12 @@ function outdatedRuntimeWarning(root) {
|
|
|
5170
5389
|
return `Injection needs @penvhq/penv ${INJECT_MIN_VERSION}+ \u2014 this project has ${version}, whose \`load\` ignores \`{ inject: true }\`. Upgrade, or process.env stays empty.`;
|
|
5171
5390
|
}
|
|
5172
5391
|
function installedPenvVersion(root) {
|
|
5173
|
-
const file = (0,
|
|
5174
|
-
if (!(0,
|
|
5392
|
+
const file = (0, import_node_path13.join)(root, "node_modules", "@penvhq", "penv", "package.json");
|
|
5393
|
+
if (!(0, import_node_fs13.existsSync)(file)) {
|
|
5175
5394
|
return void 0;
|
|
5176
5395
|
}
|
|
5177
5396
|
try {
|
|
5178
|
-
const version = JSON.parse((0,
|
|
5397
|
+
const version = JSON.parse((0, import_node_fs13.readFileSync)(file, "utf8")).version;
|
|
5179
5398
|
return typeof version === "string" ? version : void 0;
|
|
5180
5399
|
} catch {
|
|
5181
5400
|
return void 0;
|
|
@@ -5215,11 +5434,11 @@ function writeSeam(root, decisions = DEFAULT_DECISIONS, framework = detectFramew
|
|
|
5215
5434
|
};
|
|
5216
5435
|
}
|
|
5217
5436
|
const alsoNote = writeAlso(root, seam.also);
|
|
5218
|
-
const file = (0,
|
|
5437
|
+
const file = (0, import_node_path13.join)(root, ...seam.file.split("/"));
|
|
5219
5438
|
const baseNotes = [...seam.notes, ...alsoNote === void 0 ? [] : [alsoNote]];
|
|
5220
5439
|
const notes = baseNotes.length === 0 ? "" : `
|
|
5221
5440
|
${baseNotes.map((n) => ` ${n}`).join("\n")}`;
|
|
5222
|
-
if ((0,
|
|
5441
|
+
if ((0, import_node_fs13.existsSync)(file)) {
|
|
5223
5442
|
return {
|
|
5224
5443
|
target: "seam",
|
|
5225
5444
|
action: "info",
|
|
@@ -5227,8 +5446,8 @@ ${baseNotes.map((n) => ` ${n}`).join("\n")}`;
|
|
|
5227
5446
|
note: withWarning(`${seam.ifPresent}${notes}`, outdated)
|
|
5228
5447
|
};
|
|
5229
5448
|
}
|
|
5230
|
-
(0,
|
|
5231
|
-
(0,
|
|
5449
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
|
|
5450
|
+
(0, import_node_fs13.writeFileSync)(file, seam.content, "utf8");
|
|
5232
5451
|
return {
|
|
5233
5452
|
target: "seam",
|
|
5234
5453
|
action: outdated === void 0 ? "created" : "info",
|
|
@@ -5240,12 +5459,12 @@ function writeAlso(root, also) {
|
|
|
5240
5459
|
if (also === void 0) {
|
|
5241
5460
|
return void 0;
|
|
5242
5461
|
}
|
|
5243
|
-
const file = (0,
|
|
5244
|
-
if ((0,
|
|
5462
|
+
const file = (0, import_node_path13.join)(root, ...also.file.split("/"));
|
|
5463
|
+
if ((0, import_node_fs13.existsSync)(file)) {
|
|
5245
5464
|
return also.ifPresent;
|
|
5246
5465
|
}
|
|
5247
|
-
(0,
|
|
5248
|
-
(0,
|
|
5466
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true });
|
|
5467
|
+
(0, import_node_fs13.writeFileSync)(file, also.content, "utf8");
|
|
5249
5468
|
return `Wrote ${also.file} to register it.`;
|
|
5250
5469
|
}
|
|
5251
5470
|
function withWarning(note, warning) {
|
|
@@ -5270,6 +5489,23 @@ function scaffold(root, fields, draft, decisions = DEFAULT_DECISIONS, framework
|
|
|
5270
5489
|
const seam = writeSeam(root, decisions, framework);
|
|
5271
5490
|
return seam === void 0 ? steps : [...steps, seam];
|
|
5272
5491
|
}
|
|
5492
|
+
function scaffoldPaths(root, decisions = DEFAULT_DECISIONS, framework = detectFramework(root)?.name) {
|
|
5493
|
+
const fileAt = (relative5) => (0, import_node_path13.join)(root, ...relative5.split("/"));
|
|
5494
|
+
const seam = decisions.inject ? seamFor(framework, {
|
|
5495
|
+
alias: decisions.alias,
|
|
5496
|
+
srcDir: srcPrefix(root),
|
|
5497
|
+
schemaFile: decisions.schemaFile
|
|
5498
|
+
}) : void 0;
|
|
5499
|
+
return [
|
|
5500
|
+
fileAt(import_core25.PENV_DIR),
|
|
5501
|
+
fileAt(import_core25.SCHEMA_SHAPE_FILE),
|
|
5502
|
+
fileAt(decisions.schemaFile),
|
|
5503
|
+
fileAt(CONFIG_FILE),
|
|
5504
|
+
fileAt(TSCONFIG_FILE),
|
|
5505
|
+
fileAt(PACKAGE_FILE),
|
|
5506
|
+
...seam?.kind === "scaffold" ? [fileAt(seam.file), ...seam.also === void 0 ? [] : [fileAt(seam.also.file)]] : []
|
|
5507
|
+
];
|
|
5508
|
+
}
|
|
5273
5509
|
var DEVELOPMENT = "development";
|
|
5274
5510
|
var LOCAL_PROVIDER = "@penvhq/provider-filesystem";
|
|
5275
5511
|
function planAdoption(root) {
|
|
@@ -5332,7 +5568,7 @@ function planCutover(input) {
|
|
|
5332
5568
|
const diagnostics = [];
|
|
5333
5569
|
let variables = 0;
|
|
5334
5570
|
for (const file of selected) {
|
|
5335
|
-
const parsed = (0, import_core25.parseDotenv)((0,
|
|
5571
|
+
const parsed = (0, import_core25.parseDotenv)((0, import_node_fs13.readFileSync)((0, import_node_path13.join)(root, file.name), "utf8"));
|
|
5336
5572
|
const fileRefs = refsForEntries(parsed.entries, file.name, config);
|
|
5337
5573
|
adopted.push({ file, entries: parsed.entries, refs: fileRefs, scope: scopeOf(file) });
|
|
5338
5574
|
refs.push(...fileRefs);
|
|
@@ -5443,17 +5679,27 @@ async function applyCutover(plan2, options = {}) {
|
|
|
5443
5679
|
if (!plan2.install.satisfied) {
|
|
5444
5680
|
await (options.install ?? installWithPackageManager)(plan2.install);
|
|
5445
5681
|
}
|
|
5446
|
-
const
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5682
|
+
const undo = captureScaffold(plan2.root, scaffoldPaths(plan2.root, plan2.decisions, plan2.framework));
|
|
5683
|
+
let steps;
|
|
5684
|
+
try {
|
|
5685
|
+
steps = scaffold(plan2.root, plan2.fields, true, plan2.decisions, plan2.framework);
|
|
5686
|
+
const project = openProject(plan2.root);
|
|
5687
|
+
const tree = localTree(project);
|
|
5688
|
+
for (const adopted of plan2.adopted) {
|
|
5689
|
+
writeEntries(tree, adopted.entries, adopted.refs, adopted.scope);
|
|
5690
|
+
}
|
|
5691
|
+
for (const environment of plan2.adopting) {
|
|
5692
|
+
const check = await checkEnvironment(project, environment);
|
|
5693
|
+
if (check.schema === void 0) {
|
|
5694
|
+
throw draftNotLoaded(check.result);
|
|
5695
|
+
}
|
|
5696
|
+
if (!check.result.ok) {
|
|
5697
|
+
throw invalidAfterImport(check.result);
|
|
5698
|
+
}
|
|
5456
5699
|
}
|
|
5700
|
+
} catch (error) {
|
|
5701
|
+
restoreScaffold(undo);
|
|
5702
|
+
throw error;
|
|
5457
5703
|
}
|
|
5458
5704
|
const cutover = bundleDotenvFiles(
|
|
5459
5705
|
plan2.root,
|
|
@@ -5462,13 +5708,24 @@ async function applyCutover(plan2, options = {}) {
|
|
|
5462
5708
|
);
|
|
5463
5709
|
return { plan: plan2, steps, moved: cutover.files, validated: plan2.adopting };
|
|
5464
5710
|
}
|
|
5711
|
+
function issueLines(result2) {
|
|
5712
|
+
return result2.issues.map((issue) => ` ${issue.subject}: ${issue.message}`).join("\n");
|
|
5713
|
+
}
|
|
5714
|
+
var SCAFFOLD_ROLLED_BACK = "penv put the project back as it found it \u2014 your dotenv files and everything else are exactly where they were.";
|
|
5465
5715
|
function invalidAfterImport(result2) {
|
|
5466
|
-
const lines = result2.issues.map((issue) => ` ${issue.subject}: ${issue.message}`).join("\n");
|
|
5467
5716
|
return new import_core25.PenvError(
|
|
5468
5717
|
"INIT_CUTOVER_INVALID",
|
|
5469
|
-
`The imported values do not satisfy the draft schema for ${result2.environment}
|
|
5470
|
-
${
|
|
5471
|
-
`Correct
|
|
5718
|
+
`The imported values do not satisfy the draft schema for ${result2.environment}:
|
|
5719
|
+
${issueLines(result2)}`,
|
|
5720
|
+
`Correct the values above, then run \`penv init\` again. ${SCAFFOLD_ROLLED_BACK}`
|
|
5721
|
+
);
|
|
5722
|
+
}
|
|
5723
|
+
function draftNotLoaded(result2) {
|
|
5724
|
+
return new import_core25.PenvError(
|
|
5725
|
+
"INIT_DRAFT_NOT_LOADED",
|
|
5726
|
+
`penv could not load the schema it drafted for ${result2.environment}, so nothing was checked against it:
|
|
5727
|
+
${issueLines(result2)}`,
|
|
5728
|
+
`Fix the error above, then run \`penv init\` again. ${SCAFFOLD_ROLLED_BACK}`
|
|
5472
5729
|
);
|
|
5473
5730
|
}
|
|
5474
5731
|
function renderSelection(plan2, selected = plan2.preselected) {
|
|
@@ -5531,7 +5788,7 @@ function renderCutover(result2) {
|
|
|
5531
5788
|
const glyph = step.action === "conflicted" ? WARN : step.action === "info" ? "\u2192" : CHECK;
|
|
5532
5789
|
return step.note === void 0 ? { glyph, text: step.text } : { glyph, text: step.text, note: step.note };
|
|
5533
5790
|
}),
|
|
5534
|
-
...plan2.install.
|
|
5791
|
+
...plan2.install.packages.filter((entry) => !entry.satisfied).map((entry) => ({ glyph: CHECK, text: `Installed ${entry.name}`, note: entry.version })),
|
|
5535
5792
|
{
|
|
5536
5793
|
glyph: CHECK,
|
|
5537
5794
|
text: `Imported ${plan2.fields.length} parameters`,
|
|
@@ -5555,12 +5812,12 @@ function dailyCommand(root) {
|
|
|
5555
5812
|
return `penv run -- ${detectPackageManager(root)} ${devScript(root)}`;
|
|
5556
5813
|
}
|
|
5557
5814
|
function devScript(root) {
|
|
5558
|
-
const file = (0,
|
|
5559
|
-
if (!(0,
|
|
5815
|
+
const file = (0, import_node_path13.join)(root, PACKAGE_FILE);
|
|
5816
|
+
if (!(0, import_node_fs13.existsSync)(file)) {
|
|
5560
5817
|
return "dev";
|
|
5561
5818
|
}
|
|
5562
5819
|
try {
|
|
5563
|
-
const scripts = JSON.parse((0,
|
|
5820
|
+
const scripts = JSON.parse((0, import_node_fs13.readFileSync)(file, "utf8")).scripts;
|
|
5564
5821
|
if (scripts !== null && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
5565
5822
|
const named = Object.keys(scripts);
|
|
5566
5823
|
return ["dev", "start"].find((script) => named.includes(script)) ?? named[0] ?? "dev";
|
|
@@ -5570,7 +5827,7 @@ function devScript(root) {
|
|
|
5570
5827
|
return "dev";
|
|
5571
5828
|
}
|
|
5572
5829
|
function runInit(options) {
|
|
5573
|
-
const root = (0,
|
|
5830
|
+
const root = (0, import_node_path13.resolve)(options.cwd);
|
|
5574
5831
|
const decisions = options.decisions ?? planInit(root).decisions;
|
|
5575
5832
|
return { root, decisions, steps: scaffold(root, [], false, decisions, options.framework) };
|
|
5576
5833
|
}
|
|
@@ -5733,7 +5990,7 @@ var initCommand = (0, import_citty13.defineCommand)({
|
|
|
5733
5990
|
},
|
|
5734
5991
|
run({ args }) {
|
|
5735
5992
|
return guard(async () => {
|
|
5736
|
-
const root = (0,
|
|
5993
|
+
const root = (0, import_node_path13.resolve)(process.cwd());
|
|
5737
5994
|
if (args.action !== void 0) {
|
|
5738
5995
|
runUndoAction(root, String(args.action));
|
|
5739
5996
|
return;
|
|
@@ -5809,7 +6066,7 @@ function assertDeclared(segment, config) {
|
|
|
5809
6066
|
throw new import_core26.UnknownEnvironmentError(segment, config.environments);
|
|
5810
6067
|
}
|
|
5811
6068
|
function scopeFromFilename(file, config) {
|
|
5812
|
-
const name = (0,
|
|
6069
|
+
const name = (0, import_node_path14.basename)(file);
|
|
5813
6070
|
const segments = name.split(".");
|
|
5814
6071
|
const start = segments.indexOf(DOTENV_SEGMENT);
|
|
5815
6072
|
if (start === -1) {
|
|
@@ -5893,7 +6150,7 @@ function environmentNamed(file, explicit) {
|
|
|
5893
6150
|
if (explicit !== void 0 && explicit.trim().length > 0) {
|
|
5894
6151
|
return explicit.trim();
|
|
5895
6152
|
}
|
|
5896
|
-
const segments = (0,
|
|
6153
|
+
const segments = (0, import_node_path14.basename)(file).split(".");
|
|
5897
6154
|
const start = segments.indexOf(DOTENV_SEGMENT);
|
|
5898
6155
|
if (start === -1) {
|
|
5899
6156
|
return void 0;
|
|
@@ -5927,16 +6184,16 @@ function configInEffect(cwd, environment) {
|
|
|
5927
6184
|
return { config: openProject(cwd).config, decisions };
|
|
5928
6185
|
}
|
|
5929
6186
|
function importDotenv(options) {
|
|
5930
|
-
const cwd = (0,
|
|
5931
|
-
const file = (0,
|
|
5932
|
-
if (!(0,
|
|
6187
|
+
const cwd = (0, import_node_path14.resolve)(options.cwd);
|
|
6188
|
+
const file = (0, import_node_path14.isAbsolute)(options.file) ? options.file : (0, import_node_path14.resolve)(cwd, options.file);
|
|
6189
|
+
if (!(0, import_node_fs14.existsSync)(file)) {
|
|
5933
6190
|
throw new import_core26.PenvError(
|
|
5934
6191
|
"IMPORT_FILE_MISSING",
|
|
5935
6192
|
`There is no file at ${file} to import`,
|
|
5936
6193
|
"Point `penv import` at an existing dotenv file, e.g. `penv import .env`."
|
|
5937
6194
|
);
|
|
5938
6195
|
}
|
|
5939
|
-
const parsed = (0, import_core26.parseDotenv)((0,
|
|
6196
|
+
const parsed = (0, import_core26.parseDotenv)((0, import_node_fs14.readFileSync)(file, "utf8"));
|
|
5940
6197
|
const { config, decisions } = configInEffect(cwd, environmentNamed(file, options.environment));
|
|
5941
6198
|
const source = displayPath3(cwd, file);
|
|
5942
6199
|
const named = scopeFromFilename(file, config);
|
|
@@ -5952,7 +6209,7 @@ function importDotenv(options) {
|
|
|
5952
6209
|
const tree = localTree(project);
|
|
5953
6210
|
writeEntries(tree, parsed.entries, refs, scope);
|
|
5954
6211
|
const backup = `${file}${BACKUP_SUFFIX}`;
|
|
5955
|
-
(0,
|
|
6212
|
+
(0, import_node_fs14.copyFileSync)(file, backup);
|
|
5956
6213
|
return {
|
|
5957
6214
|
root: project.root,
|
|
5958
6215
|
file,
|
|
@@ -5966,7 +6223,7 @@ function importDotenv(options) {
|
|
|
5966
6223
|
};
|
|
5967
6224
|
}
|
|
5968
6225
|
function displayPath3(root, file) {
|
|
5969
|
-
const rel = (0,
|
|
6226
|
+
const rel = (0, import_node_path14.relative)(root, file);
|
|
5970
6227
|
return rel === "" || rel.startsWith("..") ? file : rel.split("\\").join("/");
|
|
5971
6228
|
}
|
|
5972
6229
|
function keptSchemaStep(step, variables) {
|
|
@@ -6287,30 +6544,30 @@ var listCommand = (0, import_citty16.defineCommand)({
|
|
|
6287
6544
|
});
|
|
6288
6545
|
|
|
6289
6546
|
// src/commands/migrate.ts
|
|
6290
|
-
var
|
|
6291
|
-
var
|
|
6547
|
+
var import_node_fs15 = require("fs");
|
|
6548
|
+
var import_node_path15 = require("path");
|
|
6292
6549
|
var import_promises2 = require("readline/promises");
|
|
6293
6550
|
var import_core30 = require("@penvhq/core");
|
|
6294
6551
|
var import_citty17 = require("citty");
|
|
6295
6552
|
var OLD_GITIGNORE = `${import_core30.PENV_DIR}/.gitignore`;
|
|
6296
6553
|
function planMigrate(cwd) {
|
|
6297
6554
|
const { config, file } = (0, import_core30.loadConfig)(cwd);
|
|
6298
|
-
const root = (0,
|
|
6555
|
+
const root = (0, import_node_path15.dirname)(file);
|
|
6299
6556
|
const entries = (0, import_core30.oldLayoutEntries)(root, config);
|
|
6300
6557
|
const tree = (0, import_core30.recordsDir)(root);
|
|
6301
6558
|
const collisions = collidingEntries(entries, tree);
|
|
6302
6559
|
if (collisions.length > 0) {
|
|
6303
6560
|
throw new import_core30.PenvError(
|
|
6304
6561
|
"HALF_MIGRATED",
|
|
6305
|
-
`${
|
|
6562
|
+
`${describe2(collisions)} in both \`${import_core30.PENV_DIR}/\` and \`${import_core30.RECORDS_PATH}/\`, and penv cannot tell which copy is current`,
|
|
6306
6563
|
`Move what is left under \`${import_core30.PENV_DIR}/\` into \`${import_core30.RECORDS_PATH}/\` yourself, keeping the copy you want, then run \`penv validate\`.`
|
|
6307
6564
|
);
|
|
6308
6565
|
}
|
|
6309
6566
|
const creates = [];
|
|
6310
|
-
if (entries.length > 0 && !(0,
|
|
6567
|
+
if (entries.length > 0 && !(0, import_node_fs15.existsSync)(tree)) {
|
|
6311
6568
|
creates.push(`${import_core30.RECORDS_PATH}/`);
|
|
6312
6569
|
}
|
|
6313
|
-
if (readIfPresent((0,
|
|
6570
|
+
if (readIfPresent((0, import_node_path15.join)(root, ...import_core30.STATE_GITIGNORE_PATH.split("/"))) !== (0, import_core30.renderStateGitignore)(config)) {
|
|
6314
6571
|
creates.push(import_core30.STATE_GITIGNORE_PATH);
|
|
6315
6572
|
}
|
|
6316
6573
|
return {
|
|
@@ -6320,23 +6577,23 @@ function planMigrate(cwd) {
|
|
|
6320
6577
|
to: `${import_core30.RECORDS_PATH}/${entry}`
|
|
6321
6578
|
})),
|
|
6322
6579
|
creates,
|
|
6323
|
-
removes: (0,
|
|
6580
|
+
removes: (0, import_node_fs15.existsSync)((0, import_node_path15.join)(root, ...OLD_GITIGNORE.split("/"))) ? [OLD_GITIGNORE] : []
|
|
6324
6581
|
};
|
|
6325
6582
|
}
|
|
6326
6583
|
function readIfPresent(file) {
|
|
6327
|
-
return (0,
|
|
6584
|
+
return (0, import_node_fs15.existsSync)(file) ? (0, import_node_fs15.readFileSync)(file, "utf8") : void 0;
|
|
6328
6585
|
}
|
|
6329
6586
|
function collidingEntries(entries, tree) {
|
|
6330
6587
|
let held;
|
|
6331
6588
|
try {
|
|
6332
|
-
held = (0,
|
|
6589
|
+
held = (0, import_node_fs15.readdirSync)(tree);
|
|
6333
6590
|
} catch {
|
|
6334
6591
|
return [];
|
|
6335
6592
|
}
|
|
6336
6593
|
const taken = new Set(held.map((name) => name.toLowerCase()));
|
|
6337
6594
|
return entries.filter((entry) => taken.has(entry.toLowerCase())).sort();
|
|
6338
6595
|
}
|
|
6339
|
-
function
|
|
6596
|
+
function describe2(names) {
|
|
6340
6597
|
return names.length === 1 ? `\`${names[0]}\` is` : `${names.map((name) => `\`${name}\``).join(", ")} are`;
|
|
6341
6598
|
}
|
|
6342
6599
|
function isNoop(plan2) {
|
|
@@ -6348,18 +6605,18 @@ function applyMigrate(plan2) {
|
|
|
6348
6605
|
}
|
|
6349
6606
|
const { config } = (0, import_core30.loadConfig)(plan2.root);
|
|
6350
6607
|
if (plan2.moves.length > 0) {
|
|
6351
|
-
(0,
|
|
6608
|
+
(0, import_node_fs15.mkdirSync)((0, import_core30.recordsDir)(plan2.root), { recursive: true });
|
|
6352
6609
|
for (const move of plan2.moves) {
|
|
6353
|
-
(0,
|
|
6610
|
+
(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("/")));
|
|
6354
6611
|
}
|
|
6355
6612
|
}
|
|
6356
6613
|
if (plan2.creates.includes(import_core30.STATE_GITIGNORE_PATH)) {
|
|
6357
|
-
const ignore = (0,
|
|
6358
|
-
(0,
|
|
6359
|
-
(0,
|
|
6614
|
+
const ignore = (0, import_node_path15.join)(plan2.root, ...import_core30.STATE_GITIGNORE_PATH.split("/"));
|
|
6615
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path15.dirname)(ignore), { recursive: true });
|
|
6616
|
+
(0, import_node_fs15.writeFileSync)(ignore, (0, import_core30.renderStateGitignore)(config), "utf8");
|
|
6360
6617
|
}
|
|
6361
6618
|
for (const removed of plan2.removes) {
|
|
6362
|
-
(0,
|
|
6619
|
+
(0, import_node_fs15.rmSync)((0, import_node_path15.join)(plan2.root, ...removed.split("/")), { force: true });
|
|
6363
6620
|
}
|
|
6364
6621
|
return { ...plan2, status: "migrated" };
|
|
6365
6622
|
}
|
|
@@ -6845,14 +7102,14 @@ var rotateCommand = (0, import_citty20.defineCommand)({
|
|
|
6845
7102
|
});
|
|
6846
7103
|
|
|
6847
7104
|
// src/commands/watch.ts
|
|
6848
|
-
var
|
|
6849
|
-
var
|
|
7105
|
+
var import_node_fs16 = require("fs");
|
|
7106
|
+
var import_node_path16 = require("path");
|
|
6850
7107
|
var import_core34 = require("@penvhq/core");
|
|
6851
7108
|
var import_citty21 = require("citty");
|
|
6852
7109
|
var DEBOUNCE_MS2 = 100;
|
|
6853
7110
|
function runWatch(options) {
|
|
6854
7111
|
const project = openProject(options.cwd);
|
|
6855
|
-
const configFile = (0,
|
|
7112
|
+
const configFile = (0, import_node_path16.basename)(project.configFile);
|
|
6856
7113
|
const debounceMs = options.debounceMs ?? DEBOUNCE_MS2;
|
|
6857
7114
|
const watchers = /* @__PURE__ */ new Set();
|
|
6858
7115
|
let timer;
|
|
@@ -6905,22 +7162,22 @@ function runWatch(options) {
|
|
|
6905
7162
|
watcher.close();
|
|
6906
7163
|
}
|
|
6907
7164
|
function armRecovery(target, recursive, only) {
|
|
6908
|
-
const parent = (0,
|
|
6909
|
-
const name = (0,
|
|
7165
|
+
const parent = (0, import_node_path16.dirname)(target);
|
|
7166
|
+
const name = (0, import_node_path16.basename)(target);
|
|
6910
7167
|
let recovery;
|
|
6911
7168
|
try {
|
|
6912
|
-
recovery = (0,
|
|
7169
|
+
recovery = (0, import_node_fs16.watch)(parent, { recursive: false }, (_event, filename) => {
|
|
6913
7170
|
if (closed || recovery === void 0) {
|
|
6914
7171
|
return;
|
|
6915
7172
|
}
|
|
6916
|
-
if (!(0,
|
|
7173
|
+
if (!(0, import_node_fs16.existsSync)(parent)) {
|
|
6917
7174
|
stop2(recovery);
|
|
6918
7175
|
return;
|
|
6919
7176
|
}
|
|
6920
|
-
if (filename !== null && (0,
|
|
7177
|
+
if (filename !== null && (0, import_node_path16.basename)(filename) !== name) {
|
|
6921
7178
|
return;
|
|
6922
7179
|
}
|
|
6923
|
-
if (!(0,
|
|
7180
|
+
if (!(0, import_node_fs16.existsSync)(target)) {
|
|
6924
7181
|
return;
|
|
6925
7182
|
}
|
|
6926
7183
|
stop2(recovery);
|
|
@@ -6940,11 +7197,11 @@ function runWatch(options) {
|
|
|
6940
7197
|
}
|
|
6941
7198
|
function addWatcher(target, recursive, only) {
|
|
6942
7199
|
let watcher;
|
|
6943
|
-
const listen = (useRecursive) => (0,
|
|
7200
|
+
const listen = (useRecursive) => (0, import_node_fs16.watch)(target, { recursive: useRecursive }, (_event, filename) => {
|
|
6944
7201
|
if (closed) {
|
|
6945
7202
|
return;
|
|
6946
7203
|
}
|
|
6947
|
-
if (!(0,
|
|
7204
|
+
if (!(0, import_node_fs16.existsSync)(target)) {
|
|
6948
7205
|
if (watcher !== void 0) {
|
|
6949
7206
|
stop2(watcher);
|
|
6950
7207
|
}
|
|
@@ -6952,7 +7209,7 @@ function runWatch(options) {
|
|
|
6952
7209
|
schedule();
|
|
6953
7210
|
return;
|
|
6954
7211
|
}
|
|
6955
|
-
if (only !== void 0 && (filename === null || (0,
|
|
7212
|
+
if (only !== void 0 && (filename === null || (0, import_node_path16.basename)(filename) !== only)) {
|
|
6956
7213
|
return;
|
|
6957
7214
|
}
|
|
6958
7215
|
schedule();
|
|
@@ -6979,11 +7236,11 @@ function runWatch(options) {
|
|
|
6979
7236
|
watchers.add(watcher);
|
|
6980
7237
|
}
|
|
6981
7238
|
addWatcher(project.recordsDir, true);
|
|
6982
|
-
addWatcher((0,
|
|
7239
|
+
addWatcher((0, import_node_path16.dirname)(project.configFile), false, configFile);
|
|
6983
7240
|
addWatcher(project.root, false, import_core34.SCHEMA_SHAPE_FILE);
|
|
6984
7241
|
if ((0, import_core34.schemaInsideTree)(project.config) === void 0) {
|
|
6985
|
-
const schemaFile = (0,
|
|
6986
|
-
addWatcher((0,
|
|
7242
|
+
const schemaFile = (0, import_node_path16.resolve)(project.root, (0, import_core34.schemaFileOf)(project.config));
|
|
7243
|
+
addWatcher((0, import_node_path16.dirname)(schemaFile), false, (0, import_node_path16.basename)(schemaFile));
|
|
6987
7244
|
}
|
|
6988
7245
|
void validate();
|
|
6989
7246
|
return {
|