@penvhq/cli 0.3.1 → 0.4.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 +376 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -1
- package/dist/index.d.ts +41 -1
- package/dist/index.js +375 -70
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -376,29 +376,61 @@ function permitsAbsence(node) {
|
|
|
376
376
|
}
|
|
377
377
|
return void 0;
|
|
378
378
|
}
|
|
379
|
-
function leaves(node, path, inherited,
|
|
379
|
+
function leaves(node, path, inherited, out2) {
|
|
380
380
|
const own = permitsAbsence(node);
|
|
381
381
|
const absencePermitted = inherited === true || own === true ? true : combine(inherited, own);
|
|
382
382
|
const shape = shapeOf(unwrap(node));
|
|
383
383
|
if (shape === void 0) {
|
|
384
384
|
if (path.length > 0) {
|
|
385
|
-
|
|
385
|
+
out2.push({ path, absencePermitted, node });
|
|
386
386
|
}
|
|
387
387
|
return;
|
|
388
388
|
}
|
|
389
389
|
for (const key of Object.keys(shape)) {
|
|
390
|
-
leaves(shape[key], [...path, key], absencePermitted,
|
|
390
|
+
leaves(shape[key], [...path, key], absencePermitted, out2);
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
function combine(left, right) {
|
|
394
394
|
return left === void 0 || right === void 0 ? void 0 : false;
|
|
395
395
|
}
|
|
396
396
|
function declaredLeaves(schema) {
|
|
397
|
-
const
|
|
398
|
-
leaves(schema, [], false,
|
|
399
|
-
return
|
|
397
|
+
const out2 = [];
|
|
398
|
+
leaves(schema, [], false, out2);
|
|
399
|
+
return out2;
|
|
400
400
|
}
|
|
401
|
-
|
|
401
|
+
function defaultValueOf(node) {
|
|
402
|
+
let current = node;
|
|
403
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
404
|
+
const def = defOf(current);
|
|
405
|
+
if (def === void 0) {
|
|
406
|
+
return void 0;
|
|
407
|
+
}
|
|
408
|
+
if (typeOf(current) === "default" || typeOf(current) === "prefault") {
|
|
409
|
+
let value = def.defaultValue;
|
|
410
|
+
if (typeof value === "function") {
|
|
411
|
+
try {
|
|
412
|
+
value = value();
|
|
413
|
+
} catch {
|
|
414
|
+
return void 0;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (typeof value === "string") {
|
|
418
|
+
return JSON.stringify(value);
|
|
419
|
+
}
|
|
420
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
421
|
+
return String(value);
|
|
422
|
+
}
|
|
423
|
+
return void 0;
|
|
424
|
+
}
|
|
425
|
+
const inner = def.innerType;
|
|
426
|
+
if (inner === void 0) {
|
|
427
|
+
return void 0;
|
|
428
|
+
}
|
|
429
|
+
current = inner;
|
|
430
|
+
}
|
|
431
|
+
return void 0;
|
|
432
|
+
}
|
|
433
|
+
var EMPTY_DRIFT = { declared: [], undeclared: [], optional: [] };
|
|
402
434
|
function hasValue(resolution) {
|
|
403
435
|
return resolution.winner !== void 0;
|
|
404
436
|
}
|
|
@@ -406,23 +438,39 @@ function computeDrift(input) {
|
|
|
406
438
|
const { schema, resolutions, config, environment } = input;
|
|
407
439
|
const valued = new Set(resolutions.filter(hasValue).map((resolution) => resolution.parameter));
|
|
408
440
|
const declared = [];
|
|
441
|
+
const optional = [];
|
|
409
442
|
for (const leaf of declaredLeaves(schema)) {
|
|
410
|
-
if (leaf.absencePermitted
|
|
443
|
+
if (leaf.absencePermitted === void 0) {
|
|
411
444
|
continue;
|
|
412
445
|
}
|
|
413
446
|
const path = leaf.path.join(".");
|
|
414
447
|
const ref = refFromAccessPath2(leaf.path);
|
|
448
|
+
const renameRemedy = `Rename the \`${path}\` key in .penv/env.ts \u2014 a parameter name is lower-case, hyphenated, and never a reserved token, so no value file reaches this key.`;
|
|
415
449
|
if (ref === void 0 || isReservedToken2(ref.name, config)) {
|
|
416
|
-
|
|
417
|
-
subject: path,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
450
|
+
if (leaf.absencePermitted) {
|
|
451
|
+
optional.push({ subject: path, remedy: renameRemedy });
|
|
452
|
+
} else {
|
|
453
|
+
declared.push({
|
|
454
|
+
subject: path,
|
|
455
|
+
remedy: renameRemedy,
|
|
456
|
+
detail: "declared, no filename reaches it"
|
|
457
|
+
});
|
|
458
|
+
}
|
|
421
459
|
continue;
|
|
422
460
|
}
|
|
423
461
|
if (valued.has(parameterId2(ref))) {
|
|
424
462
|
continue;
|
|
425
463
|
}
|
|
464
|
+
if (leaf.absencePermitted) {
|
|
465
|
+
const defaultValue = defaultValueOf(leaf.node);
|
|
466
|
+
optional.push({
|
|
467
|
+
subject: parameterId2(ref),
|
|
468
|
+
ref,
|
|
469
|
+
...defaultValue === void 0 ? {} : { defaultValue },
|
|
470
|
+
remedy: `penv set ${[...ref.namespace, ref.name].join("/")} --env ${environment}`
|
|
471
|
+
});
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
426
474
|
declared.push({
|
|
427
475
|
subject: parameterId2(ref),
|
|
428
476
|
ref,
|
|
@@ -440,28 +488,91 @@ function computeDrift(input) {
|
|
|
440
488
|
variable: variableName(resolution.ref, config)
|
|
441
489
|
});
|
|
442
490
|
}
|
|
443
|
-
return { declared, undeclared };
|
|
491
|
+
return { declared, undeclared, optional };
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// src/style.ts
|
|
495
|
+
function supportsColor(stream) {
|
|
496
|
+
const env = process.env;
|
|
497
|
+
if (env.NO_COLOR !== void 0 && env.NO_COLOR !== "") {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
if (env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "" && env.FORCE_COLOR !== "0") {
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
if (env.TERM === "dumb") {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
return stream.isTTY === true;
|
|
507
|
+
}
|
|
508
|
+
var ESC = `${String.fromCharCode(27)}[`;
|
|
509
|
+
var identity = (text) => text;
|
|
510
|
+
function sgr(open, close, on) {
|
|
511
|
+
if (!on) {
|
|
512
|
+
return identity;
|
|
513
|
+
}
|
|
514
|
+
const opener = `${ESC}${open}m`;
|
|
515
|
+
const closer = `${ESC}${close}m`;
|
|
516
|
+
return (text) => `${opener}${text}${closer}`;
|
|
517
|
+
}
|
|
518
|
+
function paletteFor(stream) {
|
|
519
|
+
const on = supportsColor(stream);
|
|
520
|
+
return {
|
|
521
|
+
enabled: on,
|
|
522
|
+
bold: sgr(1, 22, on),
|
|
523
|
+
dim: sgr(2, 22, on),
|
|
524
|
+
red: sgr(31, 39, on),
|
|
525
|
+
green: sgr(32, 39, on),
|
|
526
|
+
yellow: sgr(33, 39, on),
|
|
527
|
+
cyan: sgr(36, 39, on),
|
|
528
|
+
magenta: sgr(35, 39, on)
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
var out = paletteFor(process.stdout);
|
|
532
|
+
var err = paletteFor(process.stderr);
|
|
533
|
+
var STYLE_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
534
|
+
function visibleWidth(text) {
|
|
535
|
+
return text.replace(STYLE_PATTERN, "").length;
|
|
536
|
+
}
|
|
537
|
+
function padVisible(text, width) {
|
|
538
|
+
const missing = width - visibleWidth(text);
|
|
539
|
+
return missing > 0 ? text + " ".repeat(missing) : text;
|
|
444
540
|
}
|
|
445
541
|
|
|
446
542
|
// src/ui.ts
|
|
447
543
|
import { PenvError as PenvError3 } from "@penvhq/core";
|
|
448
544
|
var CHECK = "\u2713";
|
|
449
545
|
var WARN = "\u26A0";
|
|
546
|
+
var CROSS = "\u2717";
|
|
450
547
|
var UNKNOWN = "?";
|
|
548
|
+
function paintGlyph(glyph) {
|
|
549
|
+
switch (glyph) {
|
|
550
|
+
case CHECK:
|
|
551
|
+
return out.green(glyph);
|
|
552
|
+
case WARN:
|
|
553
|
+
return out.yellow(glyph);
|
|
554
|
+
case CROSS:
|
|
555
|
+
return out.red(glyph);
|
|
556
|
+
case UNKNOWN:
|
|
557
|
+
return out.dim(glyph);
|
|
558
|
+
default:
|
|
559
|
+
return glyph;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
451
562
|
var NOTE_COLUMN = 29;
|
|
452
563
|
function widest(values) {
|
|
453
|
-
return values.reduce((max, value) => Math.max(max, value
|
|
564
|
+
return values.reduce((max, value) => Math.max(max, visibleWidth(value)), 0);
|
|
454
565
|
}
|
|
455
566
|
function formatRows(rows) {
|
|
456
567
|
const labelWidth = widest(rows.map((row) => row.label)) + 2;
|
|
457
568
|
const detailed = rows.filter((row) => row.detail !== void 0);
|
|
458
569
|
const subjectWidth = widest(detailed.map((row) => row.subject ?? "")) + 1;
|
|
459
570
|
return rows.map((row) => {
|
|
460
|
-
const head = `${row.glyph} ${row.label
|
|
571
|
+
const head = `${paintGlyph(row.glyph)} ${padVisible(row.label, labelWidth)}`;
|
|
461
572
|
if (row.detail === void 0) {
|
|
462
573
|
return `${head}${row.subject ?? ""}`.trimEnd();
|
|
463
574
|
}
|
|
464
|
-
return `${head}${(row.subject ?? ""
|
|
575
|
+
return `${head}${padVisible(row.subject ?? "", subjectWidth)}${out.dim(row.detail)}`.trimEnd();
|
|
465
576
|
});
|
|
466
577
|
}
|
|
467
578
|
function columns(rows, gap = 2) {
|
|
@@ -471,18 +582,31 @@ function columns(rows, gap = 2) {
|
|
|
471
582
|
widths.push(widest(rows.map((row) => row[column] ?? "")) + gap);
|
|
472
583
|
}
|
|
473
584
|
return rows.map(
|
|
474
|
-
(row) => row.map(
|
|
585
|
+
(row) => row.map(
|
|
586
|
+
(cell, index) => index === row.length - 1 ? cell : padVisible(cell, widths[index] ?? 0)
|
|
587
|
+
).join("").trimEnd()
|
|
475
588
|
);
|
|
476
589
|
}
|
|
477
590
|
function formatSteps(steps) {
|
|
478
591
|
return steps.map((step) => {
|
|
479
592
|
if (step.note === void 0) {
|
|
480
|
-
return `${step.glyph} ${step.text}`;
|
|
593
|
+
return `${paintGlyph(step.glyph)} ${step.text}`;
|
|
481
594
|
}
|
|
482
|
-
const text = step.text
|
|
483
|
-
return `${step.glyph} ${text}${step.note}`;
|
|
595
|
+
const text = visibleWidth(step.text) >= NOTE_COLUMN ? `${step.text} ` : padVisible(step.text, NOTE_COLUMN);
|
|
596
|
+
return `${paintGlyph(step.glyph)} ${text}${out.dim(step.note)}`;
|
|
484
597
|
});
|
|
485
598
|
}
|
|
599
|
+
function heading(command, context) {
|
|
600
|
+
return context === void 0 ? out.bold(command) : `${out.bold(command)} ${out.dim(`\xB7 ${context}`)}`;
|
|
601
|
+
}
|
|
602
|
+
function tip(text) {
|
|
603
|
+
return ` ${out.cyan("\u2192")} ${text}`;
|
|
604
|
+
}
|
|
605
|
+
function prompt(subject, context) {
|
|
606
|
+
const head = `${out.cyan("?")} ${out.bold(subject)}`;
|
|
607
|
+
const tail = out.dim("\u203A ");
|
|
608
|
+
return context === void 0 ? `${head} ${tail}` : `${head} ${out.dim(`\xB7 ${context}`)} ${tail}`;
|
|
609
|
+
}
|
|
486
610
|
function write(lines) {
|
|
487
611
|
for (const line of lines) {
|
|
488
612
|
process.stdout.write(`${line}
|
|
@@ -491,13 +615,26 @@ function write(lines) {
|
|
|
491
615
|
}
|
|
492
616
|
function reportError(error) {
|
|
493
617
|
if (error instanceof PenvError3) {
|
|
494
|
-
|
|
618
|
+
const suffix = error.remedy === void 0 ? void 0 : `
|
|
619
|
+
${error.remedy}`;
|
|
620
|
+
const message = suffix !== void 0 && error.message.endsWith(suffix) ? error.message.slice(0, -suffix.length) : error.message;
|
|
621
|
+
process.stderr.write(`${err.red(CROSS)} ${message}
|
|
495
622
|
`);
|
|
623
|
+
if (error.remedy !== void 0) {
|
|
624
|
+
process.stderr.write(` ${err.cyan("\u2192")} ${error.remedy}
|
|
625
|
+
`);
|
|
626
|
+
}
|
|
496
627
|
} else if (error instanceof Error) {
|
|
497
|
-
process.stderr.write(`${
|
|
628
|
+
process.stderr.write(`${err.red(CROSS)} ${error.message}
|
|
498
629
|
`);
|
|
630
|
+
const stack = error.stack;
|
|
631
|
+
const frames = stack?.startsWith(`${error.name}: ${error.message}`) ? stack.slice(`${error.name}: ${error.message}`.length).replace(/^\n/, "") : stack;
|
|
632
|
+
if (frames !== void 0 && frames !== "") {
|
|
633
|
+
process.stderr.write(`${err.dim(frames)}
|
|
634
|
+
`);
|
|
635
|
+
}
|
|
499
636
|
} else {
|
|
500
|
-
process.stderr.write(`${String(error)}
|
|
637
|
+
process.stderr.write(`${err.red(CROSS)} ${String(error)}
|
|
501
638
|
`);
|
|
502
639
|
}
|
|
503
640
|
process.exitCode = 1;
|
|
@@ -688,6 +825,7 @@ import {
|
|
|
688
825
|
PenvError as PenvError5,
|
|
689
826
|
ReservedTokenError as ReservedTokenError2,
|
|
690
827
|
resolveAll,
|
|
828
|
+
SCHEMA_HARVEST_ENV,
|
|
691
829
|
schemaFileOf,
|
|
692
830
|
validateConfig
|
|
693
831
|
} from "@penvhq/core";
|
|
@@ -772,7 +910,9 @@ function loadSchema(project, environment) {
|
|
|
772
910
|
async function loadSchemaExclusively(file, schemaPath, environment) {
|
|
773
911
|
const jiti = jitiFor(file);
|
|
774
912
|
const previous = process.env.PENV_ENV;
|
|
913
|
+
const previousHarvest = process.env[SCHEMA_HARVEST_ENV];
|
|
775
914
|
process.env.PENV_ENV = environment;
|
|
915
|
+
process.env[SCHEMA_HARVEST_ENV] = "1";
|
|
776
916
|
let loaded;
|
|
777
917
|
try {
|
|
778
918
|
loaded = await jiti.import(file);
|
|
@@ -798,6 +938,11 @@ async function loadSchemaExclusively(file, schemaPath, environment) {
|
|
|
798
938
|
} else {
|
|
799
939
|
process.env.PENV_ENV = previous;
|
|
800
940
|
}
|
|
941
|
+
if (previousHarvest === void 0) {
|
|
942
|
+
delete process.env[SCHEMA_HARVEST_ENV];
|
|
943
|
+
} else {
|
|
944
|
+
process.env[SCHEMA_HARVEST_ENV] = previousHarvest;
|
|
945
|
+
}
|
|
801
946
|
}
|
|
802
947
|
const exported = typeof loaded === "object" && loaded !== null ? loaded[SCHEMA_EXPORT] : void 0;
|
|
803
948
|
if (!isZodType(exported)) {
|
|
@@ -897,18 +1042,26 @@ function renderValidate(result2) {
|
|
|
897
1042
|
]);
|
|
898
1043
|
}
|
|
899
1044
|
const rows = result2.issues.map((issue) => ({
|
|
900
|
-
glyph:
|
|
1045
|
+
glyph: CROSS,
|
|
901
1046
|
label: LABELS[issue.kind],
|
|
902
1047
|
subject: issue.subject,
|
|
903
1048
|
detail: issue.message
|
|
904
1049
|
}));
|
|
905
1050
|
const lines = formatRows(rows);
|
|
906
|
-
const remedies = [...new Set(result2.issues.map((issue) => issue.remedy))]
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1051
|
+
const remedies = [...new Set(result2.issues.map((issue) => issue.remedy))].filter(
|
|
1052
|
+
(remedy) => remedy !== void 0
|
|
1053
|
+
);
|
|
1054
|
+
if (remedies.length > 0) {
|
|
1055
|
+
lines.push("");
|
|
1056
|
+
for (const remedy of remedies) {
|
|
1057
|
+
lines.push(tip(remedy));
|
|
910
1058
|
}
|
|
911
1059
|
}
|
|
1060
|
+
const count = result2.issues.length;
|
|
1061
|
+
lines.push(
|
|
1062
|
+
"",
|
|
1063
|
+
`${out.red(CROSS)} ${count} ${count === 1 ? "issue" : "issues"} for environment ${result2.environment}`
|
|
1064
|
+
);
|
|
912
1065
|
return lines;
|
|
913
1066
|
}
|
|
914
1067
|
var validateCommand = defineCommand2({
|
|
@@ -1663,22 +1816,51 @@ async function providerDriftFindings(project, environment, override) {
|
|
|
1663
1816
|
}
|
|
1664
1817
|
];
|
|
1665
1818
|
}
|
|
1819
|
+
var GLYPHS = {
|
|
1820
|
+
pass: CHECK,
|
|
1821
|
+
warning: WARN,
|
|
1822
|
+
failure: CROSS,
|
|
1823
|
+
unknown: UNKNOWN
|
|
1824
|
+
};
|
|
1825
|
+
function summarize(report) {
|
|
1826
|
+
const counts = { pass: 0, warning: 0, failure: 0, unknown: 0 };
|
|
1827
|
+
for (const finding of report.findings) {
|
|
1828
|
+
counts[finding.severity] += 1;
|
|
1829
|
+
}
|
|
1830
|
+
const parts = [out.green(`${counts.pass} passed`)];
|
|
1831
|
+
if (counts.warning > 0) {
|
|
1832
|
+
parts.push(out.yellow(`${counts.warning} ${counts.warning === 1 ? "warning" : "warnings"}`));
|
|
1833
|
+
}
|
|
1834
|
+
if (counts.failure > 0) {
|
|
1835
|
+
parts.push(out.red(`${counts.failure} ${counts.failure === 1 ? "failure" : "failures"}`));
|
|
1836
|
+
}
|
|
1837
|
+
if (counts.unknown > 0) {
|
|
1838
|
+
parts.push(out.dim(`${counts.unknown} could not be checked`));
|
|
1839
|
+
}
|
|
1840
|
+
const verdict = report.ok ? out.green(CHECK) : out.red(CROSS);
|
|
1841
|
+
return `${verdict} ${report.findings.length} checks: ${parts.join(out.dim(" \xB7 "))}`;
|
|
1842
|
+
}
|
|
1666
1843
|
function renderDoctor(report) {
|
|
1667
1844
|
const rows = report.findings.map((finding) => ({
|
|
1668
|
-
glyph: finding.severity
|
|
1845
|
+
glyph: GLYPHS[finding.severity],
|
|
1669
1846
|
label: finding.label,
|
|
1670
1847
|
...finding.subject === void 0 ? {} : { subject: finding.subject },
|
|
1671
1848
|
...finding.detail === void 0 ? {} : { detail: finding.detail }
|
|
1672
1849
|
}));
|
|
1673
|
-
const lines =
|
|
1850
|
+
const lines = [heading("penv doctor", `environment ${report.environment}`), ""];
|
|
1851
|
+
lines.push(...formatRows(rows));
|
|
1674
1852
|
const remedies = [
|
|
1675
1853
|
...new Set(
|
|
1676
1854
|
report.findings.filter((finding) => finding.severity !== "pass").map((finding) => finding.remedy).filter((remedy) => remedy !== void 0)
|
|
1677
1855
|
)
|
|
1678
1856
|
];
|
|
1679
|
-
|
|
1680
|
-
lines.push(
|
|
1857
|
+
if (remedies.length > 0) {
|
|
1858
|
+
lines.push("");
|
|
1859
|
+
for (const remedy of remedies) {
|
|
1860
|
+
lines.push(tip(remedy));
|
|
1861
|
+
}
|
|
1681
1862
|
}
|
|
1863
|
+
lines.push("", summarize(report));
|
|
1682
1864
|
return lines;
|
|
1683
1865
|
}
|
|
1684
1866
|
var doctorCommand = defineCommand3({
|
|
@@ -1976,9 +2158,52 @@ var decryptCommand = defineCommand5({
|
|
|
1976
2158
|
});
|
|
1977
2159
|
|
|
1978
2160
|
// src/commands/fill.ts
|
|
1979
|
-
import { createInterface } from "readline/promises";
|
|
1980
2161
|
import { PenvError as PenvError8 } from "@penvhq/core";
|
|
1981
2162
|
import { defineCommand as defineCommand6 } from "citty";
|
|
2163
|
+
|
|
2164
|
+
// src/input.ts
|
|
2165
|
+
import { createInterface } from "readline";
|
|
2166
|
+
function lineReader(input = process.stdin, output = process.stdout) {
|
|
2167
|
+
const rl = createInterface({ input, output });
|
|
2168
|
+
const buffered = [];
|
|
2169
|
+
const waiting = [];
|
|
2170
|
+
let closed = false;
|
|
2171
|
+
rl.on("line", (line) => {
|
|
2172
|
+
const next = waiting.shift();
|
|
2173
|
+
if (next === void 0) {
|
|
2174
|
+
buffered.push(line);
|
|
2175
|
+
} else {
|
|
2176
|
+
next(line);
|
|
2177
|
+
}
|
|
2178
|
+
});
|
|
2179
|
+
rl.on("close", () => {
|
|
2180
|
+
closed = true;
|
|
2181
|
+
for (const next of waiting.splice(0)) {
|
|
2182
|
+
next(void 0);
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2185
|
+
return {
|
|
2186
|
+
ask(question) {
|
|
2187
|
+
const early = buffered.shift();
|
|
2188
|
+
if (early !== void 0) {
|
|
2189
|
+
return Promise.resolve(early);
|
|
2190
|
+
}
|
|
2191
|
+
if (closed) {
|
|
2192
|
+
return Promise.resolve(void 0);
|
|
2193
|
+
}
|
|
2194
|
+
rl.setPrompt(question);
|
|
2195
|
+
rl.prompt();
|
|
2196
|
+
return new Promise((resolve7) => {
|
|
2197
|
+
waiting.push(resolve7);
|
|
2198
|
+
});
|
|
2199
|
+
},
|
|
2200
|
+
close() {
|
|
2201
|
+
rl.close();
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
// src/commands/fill.ts
|
|
1982
2207
|
var BLOCKING = /* @__PURE__ */ new Set(["config", "collision", "reserved"]);
|
|
1983
2208
|
async function runFill(options) {
|
|
1984
2209
|
const validation = await runValidate({
|
|
@@ -2000,6 +2225,7 @@ ${detail}`,
|
|
|
2000
2225
|
}
|
|
2001
2226
|
const written = [];
|
|
2002
2227
|
const skipped2 = [];
|
|
2228
|
+
const kept = [];
|
|
2003
2229
|
const unreachable = [];
|
|
2004
2230
|
for (const drift of validation.drift.declared) {
|
|
2005
2231
|
if (drift.ref === void 0) {
|
|
@@ -2008,7 +2234,12 @@ ${detail}`,
|
|
|
2008
2234
|
}
|
|
2009
2235
|
const ref = drift.ref;
|
|
2010
2236
|
const key = [...ref.namespace, ref.name].join("/");
|
|
2011
|
-
const value = await options.ask({
|
|
2237
|
+
const value = await options.ask({
|
|
2238
|
+
parameter: key,
|
|
2239
|
+
environment,
|
|
2240
|
+
secret: false,
|
|
2241
|
+
optional: false
|
|
2242
|
+
});
|
|
2012
2243
|
if (value === void 0 || value === "") {
|
|
2013
2244
|
skipped2.push(drift.subject);
|
|
2014
2245
|
continue;
|
|
@@ -2020,17 +2251,45 @@ ${detail}`,
|
|
|
2020
2251
|
encrypted: result2.encrypted
|
|
2021
2252
|
});
|
|
2022
2253
|
}
|
|
2023
|
-
|
|
2254
|
+
for (const item of validation.drift.optional) {
|
|
2255
|
+
if (item.ref === void 0) {
|
|
2256
|
+
unreachable.push({ subject: item.subject, remedy: item.remedy });
|
|
2257
|
+
continue;
|
|
2258
|
+
}
|
|
2259
|
+
const ref = item.ref;
|
|
2260
|
+
const key = [...ref.namespace, ref.name].join("/");
|
|
2261
|
+
const value = await options.ask({
|
|
2262
|
+
parameter: key,
|
|
2263
|
+
environment,
|
|
2264
|
+
secret: false,
|
|
2265
|
+
optional: true,
|
|
2266
|
+
...item.defaultValue === void 0 ? {} : { defaultValue: item.defaultValue }
|
|
2267
|
+
});
|
|
2268
|
+
if (value === void 0 || value === "") {
|
|
2269
|
+
kept.push(item.subject);
|
|
2270
|
+
continue;
|
|
2271
|
+
}
|
|
2272
|
+
const result2 = await runSet({ cwd: options.cwd, key, value, environment });
|
|
2273
|
+
written.push({
|
|
2274
|
+
parameter: item.subject,
|
|
2275
|
+
location: result2.location,
|
|
2276
|
+
encrypted: result2.encrypted
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
return { environment, written, skipped: skipped2, kept, unreachable };
|
|
2024
2280
|
}
|
|
2025
2281
|
function summaryLine(result2) {
|
|
2026
2282
|
const filled = result2.written.length;
|
|
2027
|
-
if (filled === 0 && result2.skipped.length === 0 && result2.unreachable.length === 0) {
|
|
2028
|
-
return
|
|
2283
|
+
if (filled === 0 && result2.skipped.length === 0 && result2.kept.length === 0 && result2.unreachable.length === 0) {
|
|
2284
|
+
return `${out.green(CHECK)} Nothing to fill for environment ${result2.environment}: every declared parameter has a value`;
|
|
2029
2285
|
}
|
|
2030
2286
|
const parts = [`${filled} written`];
|
|
2031
2287
|
if (result2.skipped.length > 0) {
|
|
2032
2288
|
parts.push(`${result2.skipped.length} skipped`);
|
|
2033
2289
|
}
|
|
2290
|
+
if (result2.kept.length > 0) {
|
|
2291
|
+
parts.push(`${result2.kept.length} left to the schema's defaults`);
|
|
2292
|
+
}
|
|
2034
2293
|
if (result2.unreachable.length > 0) {
|
|
2035
2294
|
parts.push(`${result2.unreachable.length} unreachable`);
|
|
2036
2295
|
}
|
|
@@ -2051,6 +2310,16 @@ function renderFill(result2) {
|
|
|
2051
2310
|
lines.push(summaryLine(result2));
|
|
2052
2311
|
return lines;
|
|
2053
2312
|
}
|
|
2313
|
+
function contextFor(prompt2) {
|
|
2314
|
+
if (!prompt2.optional) {
|
|
2315
|
+
return `${prompt2.environment}, Enter to skip`;
|
|
2316
|
+
}
|
|
2317
|
+
if (prompt2.defaultValue === void 0) {
|
|
2318
|
+
return `${prompt2.environment} \xB7 optional, Enter leaves it unset`;
|
|
2319
|
+
}
|
|
2320
|
+
const shown = prompt2.defaultValue.length > 24 ? `${prompt2.defaultValue.slice(0, 23)}\u2026` : prompt2.defaultValue;
|
|
2321
|
+
return `${prompt2.environment} \xB7 optional, Enter keeps ${shown}`;
|
|
2322
|
+
}
|
|
2054
2323
|
var fillCommand = defineCommand6({
|
|
2055
2324
|
meta: {
|
|
2056
2325
|
name: "fill",
|
|
@@ -2061,8 +2330,8 @@ var fillCommand = defineCommand6({
|
|
|
2061
2330
|
},
|
|
2062
2331
|
run({ args }) {
|
|
2063
2332
|
return guard(async () => {
|
|
2064
|
-
const
|
|
2065
|
-
const ask = (
|
|
2333
|
+
const reader = lineReader();
|
|
2334
|
+
const ask = (prompt2) => reader.ask(prompt(prompt2.parameter, contextFor(prompt2)));
|
|
2066
2335
|
try {
|
|
2067
2336
|
write(
|
|
2068
2337
|
renderFill(
|
|
@@ -2074,7 +2343,7 @@ var fillCommand = defineCommand6({
|
|
|
2074
2343
|
)
|
|
2075
2344
|
);
|
|
2076
2345
|
} finally {
|
|
2077
|
-
|
|
2346
|
+
reader.close();
|
|
2078
2347
|
}
|
|
2079
2348
|
});
|
|
2080
2349
|
}
|
|
@@ -2243,12 +2512,14 @@ async function runExplain(options) {
|
|
|
2243
2512
|
function renderExplain(explanation) {
|
|
2244
2513
|
const target = explanation.location === void 0 ? "nothing" : `${PENV_DIR}/${explanation.location}`;
|
|
2245
2514
|
const rows = explanation.candidates.map((candidate) => [
|
|
2246
|
-
candidate.location,
|
|
2247
|
-
candidate.wins ? "present, wins" :
|
|
2515
|
+
candidate.wins ? candidate.location : out.dim(candidate.location),
|
|
2516
|
+
candidate.wins ? out.green("present, wins") : out.dim(
|
|
2517
|
+
candidate.present ? candidate.skipped ?? "present" : candidate.skipped ?? "absent"
|
|
2518
|
+
)
|
|
2248
2519
|
]);
|
|
2249
2520
|
return [
|
|
2250
|
-
`${explanation.parameter} resolves to ${target} for environment ${explanation.environment}`,
|
|
2251
|
-
...explanation.undecryptable === void 0 ? [] : [` penv cannot decrypt it: ${explanation.undecryptable}`],
|
|
2521
|
+
`${out.bold(explanation.parameter)} resolves to ${target} for environment ${explanation.environment}`,
|
|
2522
|
+
...explanation.undecryptable === void 0 ? [] : [` ${out.red(CROSS)} penv cannot decrypt it: ${explanation.undecryptable}`],
|
|
2252
2523
|
"",
|
|
2253
2524
|
...columns(rows).map((line) => ` ${line}`)
|
|
2254
2525
|
];
|
|
@@ -2553,23 +2824,27 @@ function planInit(root, flags = {}) {
|
|
|
2553
2824
|
function renderPlan(plan2) {
|
|
2554
2825
|
const rows = [];
|
|
2555
2826
|
rows.push([
|
|
2556
|
-
"
|
|
2557
|
-
plan2.suggestedEnvironments.length === 0 ? "" : `[${plan2.suggestedEnvironments.join(", ")}]
|
|
2558
|
-
|
|
2827
|
+
` ${out.dim("environments")}`,
|
|
2828
|
+
plan2.suggestedEnvironments.length === 0 ? "" : out.cyan(`[${plan2.suggestedEnvironments.join(", ")}]`),
|
|
2829
|
+
out.dim(
|
|
2830
|
+
plan2.suggestedEnvironments.length === 0 ? "\u2190 name them, or Enter to leave the whitelist empty" : "\u2190 from your .env files; edit, or Enter to accept"
|
|
2831
|
+
)
|
|
2559
2832
|
]);
|
|
2560
2833
|
rows.push([
|
|
2561
|
-
"
|
|
2834
|
+
` ${out.dim("schemaFile")}`,
|
|
2562
2835
|
plan2.decisions.schemaFile,
|
|
2563
|
-
plan2.decisions.schemaFile === DEFAULT_SCHEMA_FILE2 ? "" : `(default: ${DEFAULT_SCHEMA_FILE2})`
|
|
2836
|
+
plan2.decisions.schemaFile === DEFAULT_SCHEMA_FILE2 ? "" : out.dim(`(default: ${DEFAULT_SCHEMA_FILE2})`)
|
|
2564
2837
|
]);
|
|
2565
2838
|
for (const prefix of plan2.decisions.publicPrefixes) {
|
|
2566
|
-
rows.push(["
|
|
2839
|
+
rows.push([` ${out.dim("publicPrefix")}`, prefix, ""]);
|
|
2567
2840
|
}
|
|
2568
|
-
const headline =
|
|
2841
|
+
const headline = out.bold(
|
|
2842
|
+
plan2.detected === void 0 ? "No framework detected in package.json." : `Detected ${plan2.detected.name}.`
|
|
2843
|
+
);
|
|
2569
2844
|
return [headline, "", ...columns(rows), ""];
|
|
2570
2845
|
}
|
|
2571
2846
|
function environmentsHint(plan2) {
|
|
2572
|
-
return plan2.suggestedEnvironments.length === 0 ? "environments
|
|
2847
|
+
return plan2.suggestedEnvironments.length === 0 ? prompt("environments", "comma-separated, Enter for none") : prompt("environments", 'Enter to accept, "none" for an empty whitelist');
|
|
2573
2848
|
}
|
|
2574
2849
|
async function promptForDecisions(plan2, io) {
|
|
2575
2850
|
for (const line of renderPlan(plan2)) {
|
|
@@ -2584,7 +2859,7 @@ async function promptForDecisions(plan2, io) {
|
|
|
2584
2859
|
);
|
|
2585
2860
|
io.write("");
|
|
2586
2861
|
}
|
|
2587
|
-
const proceed = (await io.ask("Proceed?
|
|
2862
|
+
const proceed = (await io.ask(prompt("Proceed?", "Y/n"))).trim().toLowerCase();
|
|
2588
2863
|
if (proceed.length > 0 && proceed !== "y" && proceed !== "yes") {
|
|
2589
2864
|
return void 0;
|
|
2590
2865
|
}
|
|
@@ -2989,7 +3264,8 @@ function renderInit(result2) {
|
|
|
2989
3264
|
return [
|
|
2990
3265
|
...formatSteps(steps),
|
|
2991
3266
|
"",
|
|
2992
|
-
|
|
3267
|
+
`${out.green(CHECK)} ${out.bold("Done.")} Declare your parameters in ${result2.decisions.schemaFile}, then:`,
|
|
3268
|
+
tip(out.cyan("penv set <key>")),
|
|
2993
3269
|
...result2.decisions.environments.length === 0 ? [
|
|
2994
3270
|
`Then declare your environments in ${CONFIG_FILE}: penv leaves the whitelist empty rather than inventing one, and every command needs it.`
|
|
2995
3271
|
] : []
|
|
@@ -3458,20 +3734,28 @@ function runKeyCreate(options) {
|
|
|
3458
3734
|
function renderKeyCreate(result2) {
|
|
3459
3735
|
if (result2.source === "keychain") {
|
|
3460
3736
|
return [
|
|
3461
|
-
|
|
3737
|
+
`${out.green(CHECK)} A new key for environment ${result2.environment}, stored in your OS keychain as \`${result2.id}\`.`,
|
|
3462
3738
|
"",
|
|
3463
|
-
|
|
3464
|
-
|
|
3739
|
+
out.dim(
|
|
3740
|
+
"penv kept no copy. Anything sealed under it is unreadable without your keychain, and running"
|
|
3741
|
+
),
|
|
3742
|
+
out.dim(
|
|
3743
|
+
"`penv key create` again would replace it \u2014 so it lives in exactly one place, on this machine."
|
|
3744
|
+
)
|
|
3465
3745
|
];
|
|
3466
3746
|
}
|
|
3467
3747
|
return [
|
|
3468
|
-
|
|
3748
|
+
`${out.green(CHECK)} A new key for environment ${result2.environment}. penv did not store it.`,
|
|
3469
3749
|
"",
|
|
3470
|
-
` ${result2.variable}=${result2.key}`,
|
|
3750
|
+
` ${out.cyan(`${result2.variable}=${result2.key}`)}`,
|
|
3471
3751
|
"",
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3752
|
+
out.dim(
|
|
3753
|
+
"Export it where penv runs, and put it wherever this environment's secrets already live \u2014"
|
|
3754
|
+
),
|
|
3755
|
+
out.dim(
|
|
3756
|
+
"a KMS, your CI's secret store, a password manager. Anything sealed under it is unreadable"
|
|
3757
|
+
),
|
|
3758
|
+
out.dim("without it, and penv keeps no copy to fall back on.")
|
|
3475
3759
|
];
|
|
3476
3760
|
}
|
|
3477
3761
|
var keyCommand = defineCommand11({
|
|
@@ -3539,11 +3823,31 @@ async function runList(options) {
|
|
|
3539
3823
|
}
|
|
3540
3824
|
return { environment, parameters };
|
|
3541
3825
|
}
|
|
3826
|
+
function paintScope(entry) {
|
|
3827
|
+
if (entry.scope === "absent" || entry.viaUnscopedFallback) {
|
|
3828
|
+
return out.yellow(entry.scope);
|
|
3829
|
+
}
|
|
3830
|
+
return out.green(entry.scope);
|
|
3831
|
+
}
|
|
3542
3832
|
function renderList(result2) {
|
|
3543
3833
|
if (result2.parameters.length === 0) {
|
|
3544
|
-
return [
|
|
3834
|
+
return [
|
|
3835
|
+
`No parameters in ${PENV_DIR}/ for environment ${result2.environment}.`,
|
|
3836
|
+
tip(`penv set <key> --env ${result2.environment}`)
|
|
3837
|
+
];
|
|
3545
3838
|
}
|
|
3546
|
-
|
|
3839
|
+
const header = ["parameter", "scope", "variable", ""].map((cell) => out.dim(cell));
|
|
3840
|
+
const rows = result2.parameters.map((entry) => [
|
|
3841
|
+
entry.parameter,
|
|
3842
|
+
paintScope(entry),
|
|
3843
|
+
entry.variable,
|
|
3844
|
+
entry.encrypted ? out.dim("encrypted") : ""
|
|
3845
|
+
]);
|
|
3846
|
+
return [
|
|
3847
|
+
heading("penv list", `environment ${result2.environment}`),
|
|
3848
|
+
"",
|
|
3849
|
+
...columns([header, ...rows])
|
|
3850
|
+
];
|
|
3547
3851
|
}
|
|
3548
3852
|
var listCommand = defineCommand12({
|
|
3549
3853
|
meta: { name: "list", description: "List parameters" },
|
|
@@ -3691,8 +3995,9 @@ function renderMove(result2) {
|
|
|
3691
3995
|
const lines = formatRows(rows);
|
|
3692
3996
|
lines.push(
|
|
3693
3997
|
"",
|
|
3694
|
-
|
|
3695
|
-
|
|
3998
|
+
tip(
|
|
3999
|
+
`.penv/env.ts still declares \`${result2.schema.was}\` \u2014 rename it to \`${result2.schema.now}\`, or \`penv validate\` will report the value as unused and the declaration as unset.`
|
|
4000
|
+
)
|
|
3696
4001
|
);
|
|
3697
4002
|
return lines;
|
|
3698
4003
|
}
|
|
@@ -4227,9 +4532,9 @@ function renderDrift(drift, environment) {
|
|
|
4227
4532
|
if (rows.length === 0) {
|
|
4228
4533
|
return [];
|
|
4229
4534
|
}
|
|
4230
|
-
const lines = ["", `Schema and tree differ for ${environment}
|
|
4535
|
+
const lines = ["", out.bold(`Schema and tree differ for ${environment}:`), ...formatRows(rows)];
|
|
4231
4536
|
for (const remedy of new Set(drift.declared.map((item) => item.remedy))) {
|
|
4232
|
-
lines.push(
|
|
4537
|
+
lines.push(tip(remedy));
|
|
4233
4538
|
}
|
|
4234
4539
|
return lines;
|
|
4235
4540
|
}
|
|
@@ -4260,7 +4565,7 @@ var watchCommand = defineCommand17({
|
|
|
4260
4565
|
process.exitCode = previous;
|
|
4261
4566
|
}
|
|
4262
4567
|
});
|
|
4263
|
-
write([
|
|
4568
|
+
write([`Watching .penv/ and penv.config.ts. ${out.dim("Ctrl-C to stop.")}`]);
|
|
4264
4569
|
await new Promise((resolve7) => {
|
|
4265
4570
|
process.once("SIGINT", () => {
|
|
4266
4571
|
handle.close();
|