@penvhq/cli 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.cjs +249 -54
- package/dist/bin.cjs.map +1 -1
- package/dist/{chunk-JJY4RLDJ.js → chunk-NHTDIZZ2.js} +231 -45
- package/dist/chunk-NHTDIZZ2.js.map +1 -0
- package/dist/index.cjs +239 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -88
- package/dist/index.js.map +1 -1
- package/dist/install.cjs +230 -42
- package/dist/install.cjs.map +1 -1
- package/dist/install.d.cts +41 -7
- package/dist/install.d.ts +41 -7
- package/dist/install.js +5 -1
- package/package.json +13 -7
- package/dist/chunk-JJY4RLDJ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -216,11 +216,25 @@ var LOCKFILES = [
|
|
|
216
216
|
["npm", "package-lock.json"]
|
|
217
217
|
];
|
|
218
218
|
var ADD = {
|
|
219
|
-
pnpm: ["pnpm", "add"
|
|
220
|
-
npm: ["npm", "install"
|
|
221
|
-
yarn: ["yarn", "add"
|
|
222
|
-
bun: ["bun", "add"
|
|
219
|
+
pnpm: ["pnpm", "add"],
|
|
220
|
+
npm: ["npm", "install"],
|
|
221
|
+
yarn: ["yarn", "add"],
|
|
222
|
+
bun: ["bun", "add"]
|
|
223
223
|
};
|
|
224
|
+
var EXACT = {
|
|
225
|
+
pnpm: "--save-exact",
|
|
226
|
+
npm: "--save-exact",
|
|
227
|
+
yarn: "--exact",
|
|
228
|
+
bun: "--exact"
|
|
229
|
+
};
|
|
230
|
+
var DEV = {
|
|
231
|
+
pnpm: "-D",
|
|
232
|
+
npm: "--save-dev",
|
|
233
|
+
yarn: "--dev",
|
|
234
|
+
bun: "--dev"
|
|
235
|
+
};
|
|
236
|
+
var WORKSPACE_ROOT_FLAG = "-w";
|
|
237
|
+
var PNPM_WORKSPACE = "pnpm-workspace.yaml";
|
|
224
238
|
function engineVersion() {
|
|
225
239
|
const version = ownManifest()?.version;
|
|
226
240
|
if (typeof version === "string" && version.length > 0) {
|
|
@@ -283,69 +297,219 @@ function manifestOf(root) {
|
|
|
283
297
|
return void 0;
|
|
284
298
|
}
|
|
285
299
|
}
|
|
286
|
-
function
|
|
287
|
-
const manifest = manifestOf(
|
|
300
|
+
function declaredIn(dir, name) {
|
|
301
|
+
const manifest = manifestOf(dir);
|
|
288
302
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
289
303
|
const block = manifest?.[field];
|
|
290
304
|
if (block !== null && typeof block === "object" && !Array.isArray(block)) {
|
|
291
305
|
const version = block[name];
|
|
292
306
|
if (typeof version === "string") {
|
|
293
|
-
return version;
|
|
307
|
+
return { version, dev: field === "devDependencies" };
|
|
294
308
|
}
|
|
295
309
|
}
|
|
296
310
|
}
|
|
297
311
|
return void 0;
|
|
298
312
|
}
|
|
313
|
+
function isPnpmWorkspaceRoot(root) {
|
|
314
|
+
return (0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, PNPM_WORKSPACE)) && (0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, "package.json"));
|
|
315
|
+
}
|
|
316
|
+
function workspaceGlobs(root) {
|
|
317
|
+
let text;
|
|
318
|
+
try {
|
|
319
|
+
text = (0, import_node_fs2.readFileSync)((0, import_node_path2.join)(root, PNPM_WORKSPACE), "utf8");
|
|
320
|
+
} catch {
|
|
321
|
+
return [];
|
|
322
|
+
}
|
|
323
|
+
const unquote = (raw) => raw.replace(/^['"]|['"]$/g, "").trim();
|
|
324
|
+
const globs = [];
|
|
325
|
+
let inside = false;
|
|
326
|
+
for (const line of text.split(/\r?\n/)) {
|
|
327
|
+
const flow = /^packages:\s*\[(.*)\]\s*$/.exec(line);
|
|
328
|
+
if (flow?.[1] !== void 0) {
|
|
329
|
+
return flow[1].split(",").map(unquote).filter((glob) => glob !== "");
|
|
330
|
+
}
|
|
331
|
+
if (/^packages:\s*$/.test(line)) {
|
|
332
|
+
inside = true;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (!inside) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const item = /^\s+-\s*(.+?)\s*$/.exec(line);
|
|
339
|
+
if (item?.[1] !== void 0) {
|
|
340
|
+
globs.push(unquote(item[1]));
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (line.trim() !== "" && !line.trimStart().startsWith("#")) {
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return globs;
|
|
348
|
+
}
|
|
349
|
+
function directoriesIn(dir) {
|
|
350
|
+
try {
|
|
351
|
+
return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name !== "node_modules").map((entry) => (0, import_node_path2.join)(dir, entry.name));
|
|
352
|
+
} catch {
|
|
353
|
+
return [];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function isDirectory(path) {
|
|
357
|
+
try {
|
|
358
|
+
return (0, import_node_fs2.statSync)(path).isDirectory();
|
|
359
|
+
} catch {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function expandGlob(root, glob) {
|
|
364
|
+
let dirs = [root];
|
|
365
|
+
for (const segment of glob.split("/").filter((part) => part !== "" && part !== ".")) {
|
|
366
|
+
const next = [];
|
|
367
|
+
for (const dir of dirs) {
|
|
368
|
+
if (segment === "**") {
|
|
369
|
+
const stack = [dir];
|
|
370
|
+
while (stack.length > 0) {
|
|
371
|
+
const current = stack.pop();
|
|
372
|
+
next.push(current);
|
|
373
|
+
stack.push(...directoriesIn(current));
|
|
374
|
+
}
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (segment.includes("*")) {
|
|
378
|
+
const pattern = new RegExp(
|
|
379
|
+
`^${segment.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*")}$`
|
|
380
|
+
);
|
|
381
|
+
next.push(
|
|
382
|
+
...directoriesIn(dir).filter((child) => pattern.test(child.slice(dir.length + 1)))
|
|
383
|
+
);
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
const candidate = (0, import_node_path2.join)(dir, segment);
|
|
387
|
+
if (isDirectory(candidate)) {
|
|
388
|
+
next.push(candidate);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
dirs = next;
|
|
392
|
+
}
|
|
393
|
+
return dirs;
|
|
394
|
+
}
|
|
395
|
+
function workspaceMembers(root, name) {
|
|
396
|
+
if (!isPnpmWorkspaceRoot(root)) {
|
|
397
|
+
return [];
|
|
398
|
+
}
|
|
399
|
+
const globs = workspaceGlobs(root);
|
|
400
|
+
const excluded = globs.filter((glob) => glob.startsWith("!")).flatMap((glob) => expandGlob(root, glob.slice(1)));
|
|
401
|
+
const found = /* @__PURE__ */ new Set();
|
|
402
|
+
for (const glob of globs.filter((entry) => !entry.startsWith("!"))) {
|
|
403
|
+
for (const dir of expandGlob(root, glob)) {
|
|
404
|
+
if (dir !== root && !excluded.includes(dir) && declaredIn(dir, name) !== void 0) {
|
|
405
|
+
found.add(dir);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return [...found].sort();
|
|
410
|
+
}
|
|
411
|
+
function manifestPathOf(root, dir) {
|
|
412
|
+
const within = (0, import_node_path2.relative)(root, dir).split(import_node_path2.sep).filter((part) => part !== "");
|
|
413
|
+
return [...within, "package.json"].join("/");
|
|
414
|
+
}
|
|
415
|
+
function addCommand(manager, options, specs) {
|
|
416
|
+
const [bin, verb] = ADD[manager];
|
|
417
|
+
return [
|
|
418
|
+
bin,
|
|
419
|
+
...options.filter === void 0 ? [] : ["--filter", options.filter],
|
|
420
|
+
verb,
|
|
421
|
+
...options.workspaceRoot ? [WORKSPACE_ROOT_FLAG] : [],
|
|
422
|
+
EXACT[manager],
|
|
423
|
+
...options.dev ? [DEV[manager]] : [],
|
|
424
|
+
...specs
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
function stepFor(manager, manifest, packages, options) {
|
|
428
|
+
const pending = packages.filter((entry) => !entry.satisfied);
|
|
429
|
+
const specs = (pending.length === 0 ? packages : pending).map(
|
|
430
|
+
(entry) => `${entry.name}@${entry.version}`
|
|
431
|
+
);
|
|
432
|
+
return {
|
|
433
|
+
manifest,
|
|
434
|
+
packages,
|
|
435
|
+
command: addCommand(manager, options, specs),
|
|
436
|
+
satisfied: pending.length === 0
|
|
437
|
+
};
|
|
438
|
+
}
|
|
299
439
|
function planInstall(root, version = engineVersion()) {
|
|
300
440
|
const manager = detectPackageManager(root);
|
|
301
441
|
const lockfile = LOCKFILES.find(
|
|
302
442
|
([name, file]) => name === manager && (0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, file))
|
|
303
443
|
)?.[1];
|
|
304
|
-
const
|
|
305
|
-
const
|
|
444
|
+
const workspaceRoot = manager === "pnpm" && isPnpmWorkspaceRoot(root);
|
|
445
|
+
const runtime = declaredIn(root, RUNTIME_PACKAGE);
|
|
446
|
+
const zod = declaredIn(root, SCHEMA_PACKAGE);
|
|
306
447
|
const packages = [
|
|
307
448
|
{
|
|
308
449
|
name: RUNTIME_PACKAGE,
|
|
309
450
|
version,
|
|
310
|
-
...
|
|
311
|
-
satisfied:
|
|
451
|
+
...runtime === void 0 ? {} : { declared: runtime.version },
|
|
452
|
+
satisfied: runtime?.version === version
|
|
312
453
|
},
|
|
313
454
|
{
|
|
314
455
|
name: SCHEMA_PACKAGE,
|
|
315
456
|
version: schemaPackageVersion(),
|
|
316
|
-
...
|
|
457
|
+
...zod === void 0 ? {} : { declared: zod.version },
|
|
317
458
|
// Any declared zod counts: which zod a project uses is the project's
|
|
318
459
|
// decision, and penv is here to make sure there is one, not to move it.
|
|
319
|
-
satisfied:
|
|
460
|
+
satisfied: zod !== void 0
|
|
320
461
|
}
|
|
321
462
|
];
|
|
322
463
|
const pending = packages.filter((entry) => !entry.satisfied);
|
|
323
|
-
const
|
|
324
|
-
(
|
|
325
|
-
|
|
464
|
+
const steps = [
|
|
465
|
+
stepFor(manager, "package.json", packages, {
|
|
466
|
+
workspaceRoot,
|
|
467
|
+
dev: runtime?.dev === true && pending.every((entry) => entry.name === RUNTIME_PACKAGE) && pending.length > 0
|
|
468
|
+
})
|
|
469
|
+
];
|
|
470
|
+
for (const dir of workspaceMembers(root, RUNTIME_PACKAGE)) {
|
|
471
|
+
const declared = declaredIn(dir, RUNTIME_PACKAGE);
|
|
472
|
+
steps.push(
|
|
473
|
+
stepFor(
|
|
474
|
+
manager,
|
|
475
|
+
manifestPathOf(root, dir),
|
|
476
|
+
[
|
|
477
|
+
{
|
|
478
|
+
name: RUNTIME_PACKAGE,
|
|
479
|
+
version,
|
|
480
|
+
declared: declared.version,
|
|
481
|
+
satisfied: declared.version === version
|
|
482
|
+
}
|
|
483
|
+
],
|
|
484
|
+
{
|
|
485
|
+
filter: `./${(0, import_node_path2.relative)(root, dir).split(import_node_path2.sep).join("/")}`,
|
|
486
|
+
workspaceRoot: false,
|
|
487
|
+
dev: declared.dev
|
|
488
|
+
}
|
|
489
|
+
)
|
|
490
|
+
);
|
|
491
|
+
}
|
|
326
492
|
return {
|
|
327
493
|
root,
|
|
328
494
|
manager,
|
|
329
|
-
|
|
330
|
-
command: [...ADD[manager], ...specs],
|
|
495
|
+
steps,
|
|
331
496
|
...lockfile === void 0 ? {} : { lockfile },
|
|
332
|
-
satisfied:
|
|
497
|
+
satisfied: steps.every((step) => step.satisfied)
|
|
333
498
|
};
|
|
334
499
|
}
|
|
335
500
|
function describe(entry) {
|
|
336
501
|
return `${entry.name} ${entry.version}`;
|
|
337
502
|
}
|
|
338
|
-
function
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const pending = plan2.packages.filter((entry) => !entry.satisfied);
|
|
503
|
+
function installedPackages(plan2) {
|
|
504
|
+
const pending = plan2.steps.flatMap((step) => step.packages).filter((entry) => !entry.satisfied);
|
|
505
|
+
return [...new Map(pending.map((entry) => [entry.name, entry])).values()];
|
|
506
|
+
}
|
|
507
|
+
function renderStep(step) {
|
|
508
|
+
const pending = step.packages.filter((entry) => !entry.satisfied);
|
|
345
509
|
const added = pending.filter((entry) => entry.declared === void 0);
|
|
346
510
|
const replaced = pending.filter((entry) => entry.declared !== void 0);
|
|
347
511
|
return [
|
|
348
|
-
|
|
512
|
+
step.manifest,
|
|
349
513
|
...added.length === 0 ? [] : [
|
|
350
514
|
' + "dependencies": {',
|
|
351
515
|
...added.map((entry) => ` + "${entry.name}": "${entry.version}"`),
|
|
@@ -354,29 +518,49 @@ function renderInstallPlan(plan2) {
|
|
|
354
518
|
...replaced.flatMap((entry) => [
|
|
355
519
|
` - "${entry.name}": "${entry.declared}"`,
|
|
356
520
|
` + "${entry.name}": "${entry.version}"`
|
|
357
|
-
])
|
|
358
|
-
|
|
521
|
+
])
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
function renderInstallPlan(plan2) {
|
|
525
|
+
if (plan2.satisfied) {
|
|
526
|
+
const packages = plan2.steps[0]?.packages ?? [];
|
|
527
|
+
return [
|
|
528
|
+
`package.json already has ${packages.map(describe).join(" and ")} \u2014 nothing to install.`
|
|
529
|
+
];
|
|
530
|
+
}
|
|
531
|
+
const pending = plan2.steps.filter((step) => !step.satisfied);
|
|
532
|
+
const [first, ...rest] = pending.map((step) => step.command.join(" "));
|
|
533
|
+
const landing = installedPackages(plan2).map((entry) => ` + ${entry.name}@${entry.version}`);
|
|
534
|
+
return [
|
|
535
|
+
...pending.flatMap(renderStep),
|
|
536
|
+
...plan2.lockfile === void 0 ? [] : [plan2.lockfile, ...landing],
|
|
359
537
|
"",
|
|
360
|
-
`Run with: ${
|
|
538
|
+
`Run with: ${first ?? ""}`,
|
|
539
|
+
...rest.map((command) => ` then ${command}`)
|
|
361
540
|
];
|
|
362
541
|
}
|
|
363
542
|
var installWithPackageManager = async (plan2) => {
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
543
|
+
for (const step of plan2.steps) {
|
|
544
|
+
if (step.satisfied) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
const child = startChild({
|
|
548
|
+
command: step.command,
|
|
549
|
+
env: process.env,
|
|
550
|
+
cwd: plan2.root,
|
|
551
|
+
purpose: `install ${step.packages.map(describe).join(" and ")} in ${step.manifest}`
|
|
552
|
+
});
|
|
553
|
+
const ended = await child.ended;
|
|
554
|
+
if (ended.exitCode !== 0 || ended.signal !== null) {
|
|
555
|
+
throw installFailed(plan2, step);
|
|
556
|
+
}
|
|
373
557
|
}
|
|
374
558
|
};
|
|
375
|
-
function installFailed(plan2) {
|
|
559
|
+
function installFailed(plan2, step) {
|
|
376
560
|
return new import_core2.PenvError(
|
|
377
561
|
"INIT_INSTALL_FAILED",
|
|
378
|
-
`${
|
|
379
|
-
`
|
|
562
|
+
`${step.command.join(" ")} did not finish, so penv migrated nothing`,
|
|
563
|
+
`Read what ${plan2.manager} printed above \u2014 it names what it refused. Fix that and run this command again; your dotenv files are exactly where they were.`
|
|
380
564
|
);
|
|
381
565
|
}
|
|
382
566
|
|
|
@@ -906,7 +1090,7 @@ function writeError(lines) {
|
|
|
906
1090
|
}
|
|
907
1091
|
}
|
|
908
1092
|
function reportError(error) {
|
|
909
|
-
if (
|
|
1093
|
+
if ((0, import_core6.isPenvErrorLike)(error)) {
|
|
910
1094
|
process.stderr.write(`${err.red(CROSS)} ${error.summary}
|
|
911
1095
|
`);
|
|
912
1096
|
if (error.remedy !== void 0) {
|
|
@@ -4441,8 +4625,8 @@ function exportsSchema(file) {
|
|
|
4441
4625
|
/export\s*\{[^}]*\bschema\b[^}]*\}/.test(source)
|
|
4442
4626
|
);
|
|
4443
4627
|
}
|
|
4444
|
-
function occupied(cwd,
|
|
4445
|
-
const file = (0, import_node_path11.join)(cwd, ...
|
|
4628
|
+
function occupied(cwd, relative6) {
|
|
4629
|
+
const file = (0, import_node_path11.join)(cwd, ...relative6.split("/"));
|
|
4446
4630
|
return (0, import_node_fs11.existsSync)(file) && !exportsSchema(file);
|
|
4447
4631
|
}
|
|
4448
4632
|
function schemaFileFor(cwd) {
|
|
@@ -4864,7 +5048,7 @@ function environmentsFromFlag(flag) {
|
|
|
4864
5048
|
function configOf(decisions) {
|
|
4865
5049
|
return { environments: decisions.environments, providers: {}, schemaFile: decisions.schemaFile };
|
|
4866
5050
|
}
|
|
4867
|
-
function
|
|
5051
|
+
function declaredIn2(root) {
|
|
4868
5052
|
const file = (0, import_node_path13.join)(root, CONFIG_FILE);
|
|
4869
5053
|
if (!(0, import_node_fs13.existsSync)(file)) {
|
|
4870
5054
|
return void 0;
|
|
@@ -4872,7 +5056,7 @@ function declaredIn(root) {
|
|
|
4872
5056
|
return (0, import_core25.loadConfigFrom)(file);
|
|
4873
5057
|
}
|
|
4874
5058
|
function planInit(root, flags = {}) {
|
|
4875
|
-
const declared =
|
|
5059
|
+
const declared = declaredIn2(root);
|
|
4876
5060
|
const detected = detectFramework(root);
|
|
4877
5061
|
const notes = [];
|
|
4878
5062
|
if (declared !== void 0) {
|
|
@@ -5539,7 +5723,7 @@ function scaffold(root, fields, draft, decisions = DEFAULT_DECISIONS, framework
|
|
|
5539
5723
|
return seam === void 0 ? steps : [...steps, seam];
|
|
5540
5724
|
}
|
|
5541
5725
|
function scaffoldPaths(root, decisions = DEFAULT_DECISIONS, framework = detectFramework(root)?.name) {
|
|
5542
|
-
const fileAt = (
|
|
5726
|
+
const fileAt = (relative6) => (0, import_node_path13.join)(root, ...relative6.split("/"));
|
|
5543
5727
|
const seam = decisions.inject ? seamFor(framework, {
|
|
5544
5728
|
alias: decisions.alias,
|
|
5545
5729
|
srcDir: srcPrefix(root),
|
|
@@ -5586,7 +5770,7 @@ function planCutover(input) {
|
|
|
5586
5770
|
"Run `penv init` again and choose the files penv should adopt."
|
|
5587
5771
|
);
|
|
5588
5772
|
}
|
|
5589
|
-
const declared =
|
|
5773
|
+
const declared = declaredIn2(root);
|
|
5590
5774
|
const named = environmentsDeclaredBy(selected);
|
|
5591
5775
|
const chosen = named.length > 0 ? named : [requireEnvironment(input)];
|
|
5592
5776
|
const environments = declared === void 0 ? chosen : declared.environments;
|
|
@@ -5837,7 +6021,11 @@ function renderCutover(result2) {
|
|
|
5837
6021
|
const glyph = step.action === "conflicted" ? WARN : step.action === "info" ? "\u2192" : CHECK;
|
|
5838
6022
|
return step.note === void 0 ? { glyph, text: step.text } : { glyph, text: step.text, note: step.note };
|
|
5839
6023
|
}),
|
|
5840
|
-
...plan2.install
|
|
6024
|
+
...installedPackages(plan2.install).map((entry) => ({
|
|
6025
|
+
glyph: CHECK,
|
|
6026
|
+
text: `Installed ${entry.name}`,
|
|
6027
|
+
note: entry.version
|
|
6028
|
+
})),
|
|
5841
6029
|
{
|
|
5842
6030
|
glyph: CHECK,
|
|
5843
6031
|
text: `Imported ${plan2.fields.length} parameters`,
|
|
@@ -5997,7 +6185,7 @@ async function cutoverInteractively(root, base, adoption) {
|
|
|
5997
6185
|
write(renderCutover(await applyCutover({ ...plan2, decisions: { ...plan2.decisions, inject } })));
|
|
5998
6186
|
}
|
|
5999
6187
|
function offeredEnvironment(root) {
|
|
6000
|
-
const declared =
|
|
6188
|
+
const declared = declaredIn2(root);
|
|
6001
6189
|
if (declared === void 0) {
|
|
6002
6190
|
return DEVELOPMENT;
|
|
6003
6191
|
}
|