@penvhq/cli 0.9.4 → 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 +254 -111
- package/dist/bin.cjs.map +1 -1
- package/dist/index.cjs +182 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +125 -44
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.d.cts
CHANGED
|
@@ -57,7 +57,7 @@ declare function renderArtifactBuild(result: ArtifactBuildResult, cwd: string):
|
|
|
57
57
|
* second kind.
|
|
58
58
|
*/
|
|
59
59
|
type DoctorSeverity = "pass" | "warning" | "failure" | "unknown";
|
|
60
|
-
type DoctorCheck = "schema" | "missing" | "declared" | "weak" | "unused" | "unscoped-fallback" | "plaintext-secret" | "public-secret" | "encryption" | "rotation-overdue" | "rotation-stuck" | "provider-value-drift" | "provider" | "projection-unreachable" | "projection-name-drift" | "projection-manual-edit" | "projection-value-drift" | "environment-flag-shadow" | "artifact-in-tree";
|
|
60
|
+
type DoctorCheck = "schema" | "missing" | "declared" | "weak" | "unused" | "unscoped-fallback" | "secrecy-undeclared" | "plaintext-secret" | "public-secret" | "encryption" | "rotation-overdue" | "rotation-stuck" | "provider-value-drift" | "provider" | "projection-unreachable" | "projection-name-drift" | "projection-manual-edit" | "projection-value-drift" | "environment-flag-shadow" | "local-extension" | "artifact-in-tree";
|
|
61
61
|
interface DoctorFinding {
|
|
62
62
|
readonly check: DoctorCheck;
|
|
63
63
|
readonly severity: DoctorSeverity;
|
package/dist/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ declare function renderArtifactBuild(result: ArtifactBuildResult, cwd: string):
|
|
|
57
57
|
* second kind.
|
|
58
58
|
*/
|
|
59
59
|
type DoctorSeverity = "pass" | "warning" | "failure" | "unknown";
|
|
60
|
-
type DoctorCheck = "schema" | "missing" | "declared" | "weak" | "unused" | "unscoped-fallback" | "plaintext-secret" | "public-secret" | "encryption" | "rotation-overdue" | "rotation-stuck" | "provider-value-drift" | "provider" | "projection-unreachable" | "projection-name-drift" | "projection-manual-edit" | "projection-value-drift" | "environment-flag-shadow" | "artifact-in-tree";
|
|
60
|
+
type DoctorCheck = "schema" | "missing" | "declared" | "weak" | "unused" | "unscoped-fallback" | "secrecy-undeclared" | "plaintext-secret" | "public-secret" | "encryption" | "rotation-overdue" | "rotation-stuck" | "provider-value-drift" | "provider" | "projection-unreachable" | "projection-name-drift" | "projection-manual-edit" | "projection-value-drift" | "environment-flag-shadow" | "local-extension" | "artifact-in-tree";
|
|
61
61
|
interface DoctorFinding {
|
|
62
62
|
readonly check: DoctorCheck;
|
|
63
63
|
readonly severity: DoctorSeverity;
|
package/dist/index.js
CHANGED
|
@@ -325,7 +325,7 @@ function installFailed(plan2) {
|
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
// src/project.ts
|
|
328
|
-
import { existsSync as existsSync3, readFileSync as
|
|
328
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
329
329
|
import { dirname, join as join3 } from "path";
|
|
330
330
|
import {
|
|
331
331
|
assertMigrated,
|
|
@@ -406,10 +406,19 @@ function environmentFromShorthand(config, candidates, explicit) {
|
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
// src/registry.ts
|
|
409
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
409
410
|
import { createRequire } from "module";
|
|
410
411
|
import { resolve } from "path";
|
|
411
412
|
import { pathToFileURL } from "url";
|
|
412
|
-
import {
|
|
413
|
+
import {
|
|
414
|
+
holdsProjection,
|
|
415
|
+
LOCAL_EXTENSIONS_PATH,
|
|
416
|
+
localExtensionsFile,
|
|
417
|
+
PENV_DIR,
|
|
418
|
+
PenvError as PenvError4,
|
|
419
|
+
parseLocalExtensions,
|
|
420
|
+
recordsDir
|
|
421
|
+
} from "@penvhq/core";
|
|
413
422
|
import { createFilesystemProvider } from "@penvhq/provider-filesystem";
|
|
414
423
|
import { createMockProvider } from "@penvhq/provider-mock";
|
|
415
424
|
var PLUGIN_FACTORY_EXPORT = "penvProviderFactory";
|
|
@@ -478,16 +487,40 @@ async function loadPluginProvider(type, context) {
|
|
|
478
487
|
assertSatisfiesContract(provider, type);
|
|
479
488
|
return provider;
|
|
480
489
|
}
|
|
481
|
-
function assertProvidersRegistered(config, projectRoot) {
|
|
490
|
+
function assertProvidersRegistered(config, projectRoot, options) {
|
|
491
|
+
const local = localExtensions(projectRoot);
|
|
492
|
+
const ci = options?.ci ?? isCi(process.env.CI);
|
|
482
493
|
for (const [environment, provider] of Object.entries(config.providers)) {
|
|
483
494
|
if (isProviderRegistered(provider.type)) {
|
|
484
495
|
continue;
|
|
485
496
|
}
|
|
497
|
+
if (ci && local.includes(provider.type)) {
|
|
498
|
+
throw localExtensionInCi(provider.type, environment);
|
|
499
|
+
}
|
|
486
500
|
if (resolvePlugin(provider.type, projectRoot) === void 0) {
|
|
487
501
|
throw unknownProvider(provider.type, environment);
|
|
488
502
|
}
|
|
489
503
|
}
|
|
490
504
|
}
|
|
505
|
+
function localExtensions(projectRoot) {
|
|
506
|
+
let text;
|
|
507
|
+
try {
|
|
508
|
+
text = readFileSync2(localExtensionsFile(projectRoot), "utf8");
|
|
509
|
+
} catch {
|
|
510
|
+
return [];
|
|
511
|
+
}
|
|
512
|
+
return parseLocalExtensions(text);
|
|
513
|
+
}
|
|
514
|
+
function isCi(value) {
|
|
515
|
+
return value !== void 0 && value !== "" && value !== "0" && value.toLowerCase() !== "false";
|
|
516
|
+
}
|
|
517
|
+
function localExtensionInCi(type, environment) {
|
|
518
|
+
return new PenvError4(
|
|
519
|
+
"LOCAL_EXTENSION_IN_CI",
|
|
520
|
+
`The provider \`${type}\` for environment ${environment} is a local extension, and this is CI`,
|
|
521
|
+
`${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.`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
491
524
|
function resolvePlugin(specifier, fromDir) {
|
|
492
525
|
try {
|
|
493
526
|
const require2 = createRequire(resolve(fromDir, "noop.js"));
|
|
@@ -525,7 +558,7 @@ function unknownProvider(type, environment) {
|
|
|
525
558
|
return new PenvError4(
|
|
526
559
|
"UNKNOWN_PROVIDER",
|
|
527
560
|
`The provider \`${type}\`${where} in penv.config.ts is not installed in this project`,
|
|
528
|
-
`
|
|
561
|
+
`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.`
|
|
529
562
|
);
|
|
530
563
|
}
|
|
531
564
|
|
|
@@ -558,7 +591,7 @@ function selfContainedSchemaModule(root, schemaFile) {
|
|
|
558
591
|
if (!existsSync3(file)) {
|
|
559
592
|
return void 0;
|
|
560
593
|
}
|
|
561
|
-
const source =
|
|
594
|
+
const source = readFileSync3(file, "utf8");
|
|
562
595
|
return source.includes("PenvSchemaShape") || source.includes("z.object") ? schemaFile : void 0;
|
|
563
596
|
}
|
|
564
597
|
function schemaShapeFileOf(project) {
|
|
@@ -794,10 +827,7 @@ function writeError(lines) {
|
|
|
794
827
|
}
|
|
795
828
|
function reportError(error) {
|
|
796
829
|
if (error instanceof PenvError6) {
|
|
797
|
-
|
|
798
|
-
${error.remedy}`;
|
|
799
|
-
const message = suffix !== void 0 && error.message.endsWith(suffix) ? error.message.slice(0, -suffix.length) : error.message;
|
|
800
|
-
process.stderr.write(`${err.red(CROSS)} ${message}
|
|
830
|
+
process.stderr.write(`${err.red(CROSS)} ${error.summary}
|
|
801
831
|
`);
|
|
802
832
|
if (error.remedy !== void 0) {
|
|
803
833
|
process.stderr.write(` ${err.cyan("\u2192")} ${error.remedy}
|
|
@@ -827,7 +857,7 @@ async function guard(run) {
|
|
|
827
857
|
}
|
|
828
858
|
|
|
829
859
|
// src/commands/run.ts
|
|
830
|
-
import { existsSync as existsSync4, readFileSync as
|
|
860
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, watch } from "fs";
|
|
831
861
|
import { createRequire as createRequire2 } from "module";
|
|
832
862
|
import { basename, dirname as dirname2, join as join4, resolve as resolve2 } from "path";
|
|
833
863
|
import {
|
|
@@ -1672,7 +1702,7 @@ function packageManifest(specifier, root) {
|
|
|
1672
1702
|
const file = join4(directory, "package.json");
|
|
1673
1703
|
if (existsSync4(file)) {
|
|
1674
1704
|
try {
|
|
1675
|
-
const parsed = JSON.parse(
|
|
1705
|
+
const parsed = JSON.parse(readFileSync4(file, "utf8"));
|
|
1676
1706
|
if (isPlainObject(parsed) && parsed.name === specifier) {
|
|
1677
1707
|
return parsed;
|
|
1678
1708
|
}
|
|
@@ -1745,7 +1775,7 @@ function snapshotPath(host) {
|
|
|
1745
1775
|
}
|
|
1746
1776
|
function readSnapshot(path) {
|
|
1747
1777
|
try {
|
|
1748
|
-
return
|
|
1778
|
+
return readFileSync4(path, "utf8");
|
|
1749
1779
|
} catch {
|
|
1750
1780
|
throw new PenvError8(
|
|
1751
1781
|
"RUN_SNAPSHOT_MISSING",
|
|
@@ -2166,7 +2196,7 @@ import {
|
|
|
2166
2196
|
existsSync as existsSync5,
|
|
2167
2197
|
mkdirSync as mkdirSync2,
|
|
2168
2198
|
readdirSync as readdirSync2,
|
|
2169
|
-
readFileSync as
|
|
2199
|
+
readFileSync as readFileSync5,
|
|
2170
2200
|
renameSync,
|
|
2171
2201
|
rmSync,
|
|
2172
2202
|
writeFileSync as writeFileSync2
|
|
@@ -2210,7 +2240,7 @@ function readCutover(root) {
|
|
|
2210
2240
|
}
|
|
2211
2241
|
let parsed;
|
|
2212
2242
|
try {
|
|
2213
|
-
parsed = JSON.parse(
|
|
2243
|
+
parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
2214
2244
|
} catch {
|
|
2215
2245
|
throw unreadable("it is not JSON");
|
|
2216
2246
|
}
|
|
@@ -2357,7 +2387,7 @@ var cleanupCommand = defineCommand5({
|
|
|
2357
2387
|
});
|
|
2358
2388
|
|
|
2359
2389
|
// src/commands/doctor.ts
|
|
2360
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
2390
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
|
|
2361
2391
|
import { join as join6, relative as relative2 } from "path";
|
|
2362
2392
|
import {
|
|
2363
2393
|
ARTIFACT_BUILD_COMMAND as ARTIFACT_BUILD_COMMAND2,
|
|
@@ -2372,6 +2402,7 @@ import {
|
|
|
2372
2402
|
isSecret as isSecret3,
|
|
2373
2403
|
isStuck,
|
|
2374
2404
|
openValue as openValue2,
|
|
2405
|
+
RECORDS_PATH as RECORDS_PATH2,
|
|
2375
2406
|
resolveAll as resolveAll2,
|
|
2376
2407
|
rotationOf,
|
|
2377
2408
|
tryParseDuration,
|
|
@@ -2827,6 +2858,7 @@ async function runDoctor(options) {
|
|
|
2827
2858
|
findings.push(...unusedFindings(drift));
|
|
2828
2859
|
}
|
|
2829
2860
|
findings.push(...fallbackFindings(subjects, environment));
|
|
2861
|
+
findings.push(...secrecyFindings(subjects, environment));
|
|
2830
2862
|
findings.push(...plaintextSecretFindings(subjects, environment));
|
|
2831
2863
|
findings.push(...publicSecretFindings(subjects, environment, project.config));
|
|
2832
2864
|
findings.push(...encryptionFindings(subjects, environment));
|
|
@@ -2839,6 +2871,7 @@ async function runDoctor(options) {
|
|
|
2839
2871
|
}
|
|
2840
2872
|
findings.push(...await providerDriftFindings(project, environment, options.source));
|
|
2841
2873
|
findings.push(...await projectionFindings(project, environment, options.projection));
|
|
2874
|
+
findings.push(...localExtensionFindings(project));
|
|
2842
2875
|
findings.push(...artifactFindings(project));
|
|
2843
2876
|
findings.push({
|
|
2844
2877
|
check: "provider",
|
|
@@ -2976,6 +3009,31 @@ function fallbackFindings(subjects, environment) {
|
|
|
2976
3009
|
}
|
|
2977
3010
|
];
|
|
2978
3011
|
}
|
|
3012
|
+
function secrecyFindings(subjects, environment) {
|
|
3013
|
+
const undeclared = subjects.filter(
|
|
3014
|
+
({ meta }) => effectiveMeta(meta, environment).secret === void 0
|
|
3015
|
+
);
|
|
3016
|
+
if (undeclared.length === 0) {
|
|
3017
|
+
return [
|
|
3018
|
+
{
|
|
3019
|
+
check: "secrecy-undeclared",
|
|
3020
|
+
severity: "pass",
|
|
3021
|
+
label: "Secrecy policy",
|
|
3022
|
+
subject: subjects.length === 0 ? `no parameter resolves for ${environment}` : `every parameter declares whether it is secret for ${environment}`
|
|
3023
|
+
}
|
|
3024
|
+
];
|
|
3025
|
+
}
|
|
3026
|
+
return [
|
|
3027
|
+
{
|
|
3028
|
+
check: "secrecy-undeclared",
|
|
3029
|
+
severity: "unknown",
|
|
3030
|
+
label: "Secrecy policy",
|
|
3031
|
+
subject: `${undeclared.length} of ${subjects.length} declare neither way for ${environment}`,
|
|
3032
|
+
detail: "penv was never told which of these values must be encrypted",
|
|
3033
|
+
remedy: `declare \`"secret": true\` or \`"secret": false\` in a parameter's meta file, ${RECORDS_PATH2}/<name>.json`
|
|
3034
|
+
}
|
|
3035
|
+
];
|
|
3036
|
+
}
|
|
2979
3037
|
function plaintextSecretFindings(subjects, environment) {
|
|
2980
3038
|
const secrets = subjects.filter(({ meta }) => isSecret3(meta, environment));
|
|
2981
3039
|
const findings = [];
|
|
@@ -3296,6 +3354,29 @@ function scannableFiles(directory, out2) {
|
|
|
3296
3354
|
}
|
|
3297
3355
|
}
|
|
3298
3356
|
}
|
|
3357
|
+
function localExtensionFindings(project) {
|
|
3358
|
+
const names = localExtensions(project.root);
|
|
3359
|
+
if (names.length === 0) {
|
|
3360
|
+
return [
|
|
3361
|
+
{
|
|
3362
|
+
check: "local-extension",
|
|
3363
|
+
severity: "pass",
|
|
3364
|
+
label: "Extensions",
|
|
3365
|
+
subject: "every extension this project names is pinned"
|
|
3366
|
+
}
|
|
3367
|
+
];
|
|
3368
|
+
}
|
|
3369
|
+
return [
|
|
3370
|
+
{
|
|
3371
|
+
check: "local-extension",
|
|
3372
|
+
severity: "unknown",
|
|
3373
|
+
label: "Extensions",
|
|
3374
|
+
subject: names.join(", "),
|
|
3375
|
+
detail: "resolved from this project's node_modules \u2014 no release, no pinned bytes",
|
|
3376
|
+
remedy: `publish it and run \`penv add ${names[0]}\` when this stops being a development path`
|
|
3377
|
+
}
|
|
3378
|
+
];
|
|
3379
|
+
}
|
|
3299
3380
|
function artifactFindings(project) {
|
|
3300
3381
|
const files = [];
|
|
3301
3382
|
scannableFiles(project.root, files);
|
|
@@ -3306,7 +3387,7 @@ function artifactFindings(project) {
|
|
|
3306
3387
|
if (statSync2(file).size > ARTIFACT_SCAN_LIMIT) {
|
|
3307
3388
|
continue;
|
|
3308
3389
|
}
|
|
3309
|
-
text =
|
|
3390
|
+
text = readFileSync6(file, "utf8");
|
|
3310
3391
|
} catch {
|
|
3311
3392
|
continue;
|
|
3312
3393
|
}
|
|
@@ -4281,7 +4362,7 @@ var getCommand = defineCommand12({
|
|
|
4281
4362
|
});
|
|
4282
4363
|
|
|
4283
4364
|
// src/commands/import.ts
|
|
4284
|
-
import { copyFileSync, existsSync as existsSync9, readFileSync as
|
|
4365
|
+
import { copyFileSync, existsSync as existsSync9, readFileSync as readFileSync10 } from "fs";
|
|
4285
4366
|
import { basename as basename2, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve7 } from "path";
|
|
4286
4367
|
import {
|
|
4287
4368
|
assertNever as assertNever2,
|
|
@@ -4370,7 +4451,7 @@ function writeEntries(tree, entries, refs, scope) {
|
|
|
4370
4451
|
}
|
|
4371
4452
|
|
|
4372
4453
|
// src/detect.ts
|
|
4373
|
-
import { existsSync as existsSync6, readFileSync as
|
|
4454
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
4374
4455
|
import { join as join7 } from "path";
|
|
4375
4456
|
import { DEFAULT_SCHEMA_FILE } from "@penvhq/core";
|
|
4376
4457
|
var SIGNATURES = [
|
|
@@ -4388,7 +4469,7 @@ var SIGNATURES = [
|
|
|
4388
4469
|
function exportsSchema(file) {
|
|
4389
4470
|
let source;
|
|
4390
4471
|
try {
|
|
4391
|
-
source =
|
|
4472
|
+
source = readFileSync7(file, "utf8");
|
|
4392
4473
|
} catch {
|
|
4393
4474
|
return false;
|
|
4394
4475
|
}
|
|
@@ -4440,7 +4521,7 @@ function manifestOf2(cwd) {
|
|
|
4440
4521
|
}
|
|
4441
4522
|
let manifest;
|
|
4442
4523
|
try {
|
|
4443
|
-
manifest = JSON.parse(
|
|
4524
|
+
manifest = JSON.parse(readFileSync7(file, "utf8"));
|
|
4444
4525
|
} catch {
|
|
4445
4526
|
return void 0;
|
|
4446
4527
|
}
|
|
@@ -4535,7 +4616,7 @@ function draftFieldsAcross(sources, environments) {
|
|
|
4535
4616
|
}
|
|
4536
4617
|
|
|
4537
4618
|
// src/commands/init.ts
|
|
4538
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as
|
|
4619
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
4539
4620
|
import { dirname as dirname6, join as join9, resolve as resolve6 } from "path";
|
|
4540
4621
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
4541
4622
|
import {
|
|
@@ -4547,7 +4628,7 @@ import {
|
|
|
4547
4628
|
PenvError as PenvError18,
|
|
4548
4629
|
parameterId as parameterId6,
|
|
4549
4630
|
parseDotenv,
|
|
4550
|
-
RECORDS_PATH as
|
|
4631
|
+
RECORDS_PATH as RECORDS_PATH3,
|
|
4551
4632
|
RESERVED_TOKENS as RESERVED_TOKENS2,
|
|
4552
4633
|
ROLLBACK_DOTENV_PATH as ROLLBACK_DOTENV_PATH3,
|
|
4553
4634
|
renderStateGitignore,
|
|
@@ -4564,7 +4645,7 @@ import {
|
|
|
4564
4645
|
existsSync as existsSync7,
|
|
4565
4646
|
mkdirSync as mkdirSync3,
|
|
4566
4647
|
readdirSync as readdirSync4,
|
|
4567
|
-
readFileSync as
|
|
4648
|
+
readFileSync as readFileSync8,
|
|
4568
4649
|
rmdirSync,
|
|
4569
4650
|
statSync as statSync3,
|
|
4570
4651
|
unlinkSync,
|
|
@@ -4586,7 +4667,7 @@ function record(path, files, dirs) {
|
|
|
4586
4667
|
return;
|
|
4587
4668
|
}
|
|
4588
4669
|
if (stats.isFile()) {
|
|
4589
|
-
files.set(path,
|
|
4670
|
+
files.set(path, readFileSync8(path));
|
|
4590
4671
|
}
|
|
4591
4672
|
}
|
|
4592
4673
|
function captureScaffold(root, paths) {
|
|
@@ -5374,7 +5455,7 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5374
5455
|
text: `Created ${TSCONFIG_FILE} with the ${alias} path alias`
|
|
5375
5456
|
};
|
|
5376
5457
|
}
|
|
5377
|
-
const source =
|
|
5458
|
+
const source = readFileSync9(file, "utf8");
|
|
5378
5459
|
const edit = imports ? insertImportsAlias(source, decisions.schemaFile, alias) : insertEnvAlias(source, decisions.schemaFile, alias);
|
|
5379
5460
|
if (edit.conflict !== void 0) {
|
|
5380
5461
|
return {
|
|
@@ -5401,7 +5482,7 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
|
|
|
5401
5482
|
function writeGitignore(root, decisions = DEFAULT_DECISIONS) {
|
|
5402
5483
|
const file = join9(root, ...STATE_GITIGNORE_PATH.split("/"));
|
|
5403
5484
|
const wanted = renderStateGitignore(configOf(decisions));
|
|
5404
|
-
const existing = existsSync8(file) ?
|
|
5485
|
+
const existing = existsSync8(file) ? readFileSync9(file, "utf8") : void 0;
|
|
5405
5486
|
if (existing === wanted) {
|
|
5406
5487
|
return { target: "gitignore", action: "kept", text: `Kept ${STATE_GITIGNORE_PATH}` };
|
|
5407
5488
|
}
|
|
@@ -5427,7 +5508,7 @@ function installedPenvVersion(root) {
|
|
|
5427
5508
|
return void 0;
|
|
5428
5509
|
}
|
|
5429
5510
|
try {
|
|
5430
|
-
const version = JSON.parse(
|
|
5511
|
+
const version = JSON.parse(readFileSync9(file, "utf8")).version;
|
|
5431
5512
|
return typeof version === "string" ? version : void 0;
|
|
5432
5513
|
} catch {
|
|
5433
5514
|
return void 0;
|
|
@@ -5601,7 +5682,7 @@ function planCutover(input) {
|
|
|
5601
5682
|
const diagnostics = [];
|
|
5602
5683
|
let variables = 0;
|
|
5603
5684
|
for (const file of selected) {
|
|
5604
|
-
const parsed = parseDotenv(
|
|
5685
|
+
const parsed = parseDotenv(readFileSync9(join9(root, file.name), "utf8"));
|
|
5605
5686
|
const fileRefs = refsForEntries(parsed.entries, file.name, config);
|
|
5606
5687
|
adopted.push({ file, entries: parsed.entries, refs: fileRefs, scope: scopeOf(file) });
|
|
5607
5688
|
refs.push(...fileRefs);
|
|
@@ -5789,7 +5870,7 @@ function renderCutoverPlan(plan2) {
|
|
|
5789
5870
|
]);
|
|
5790
5871
|
rows.push([
|
|
5791
5872
|
` ${out.dim("values")}`,
|
|
5792
|
-
`${
|
|
5873
|
+
`${RECORDS_PATH3}/`,
|
|
5793
5874
|
out.dim(`\u2190 from ${plan2.variables} variables`)
|
|
5794
5875
|
]);
|
|
5795
5876
|
rows.push([
|
|
@@ -5825,7 +5906,7 @@ function renderCutover(result2) {
|
|
|
5825
5906
|
{
|
|
5826
5907
|
glyph: CHECK,
|
|
5827
5908
|
text: `Imported ${plan2.fields.length} parameters`,
|
|
5828
|
-
note: `into ${
|
|
5909
|
+
note: `into ${RECORDS_PATH3}/`
|
|
5829
5910
|
},
|
|
5830
5911
|
{ glyph: CHECK, text: `Validated ${result2.validated.join(", ")}` },
|
|
5831
5912
|
{
|
|
@@ -5850,7 +5931,7 @@ function devScript(root) {
|
|
|
5850
5931
|
return "dev";
|
|
5851
5932
|
}
|
|
5852
5933
|
try {
|
|
5853
|
-
const scripts = JSON.parse(
|
|
5934
|
+
const scripts = JSON.parse(readFileSync9(file, "utf8")).scripts;
|
|
5854
5935
|
if (scripts !== null && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
5855
5936
|
const named = Object.keys(scripts);
|
|
5856
5937
|
return ["dev", "start"].find((script) => named.includes(script)) ?? named[0] ?? "dev";
|
|
@@ -6084,7 +6165,7 @@ function runUndoAction(root, action) {
|
|
|
6084
6165
|
]),
|
|
6085
6166
|
"",
|
|
6086
6167
|
result2.missing.length === 0 ? `${out.green(CHECK)} ${out.bold("Undone.")} Your dotenv files are back exactly as they were, and ${CUTOVER_PATH3} is gone.` : `${out.yellow(WARN)} ${out.bold("Undone as far as penv could.")} Everything still in the bundle is back, and ${CUTOVER_PATH3} is gone.`,
|
|
6087
|
-
`penv's records are still in ${
|
|
6168
|
+
`penv's records are still in ${RECORDS_PATH3}/ \u2014 nothing penv scaffolded is yours to lose.`
|
|
6088
6169
|
]);
|
|
6089
6170
|
}
|
|
6090
6171
|
|
|
@@ -6226,7 +6307,7 @@ function importDotenv(options) {
|
|
|
6226
6307
|
"Point `penv import` at an existing dotenv file, e.g. `penv import .env`."
|
|
6227
6308
|
);
|
|
6228
6309
|
}
|
|
6229
|
-
const parsed = parseDotenv2(
|
|
6310
|
+
const parsed = parseDotenv2(readFileSync10(file, "utf8"));
|
|
6230
6311
|
const { config, decisions } = configInEffect(cwd, environmentNamed(file, options.environment));
|
|
6231
6312
|
const source = displayPath3(cwd, file);
|
|
6232
6313
|
const named = scopeFromFilename(file, config);
|
|
@@ -6497,7 +6578,7 @@ var keyCommand = defineCommand15({
|
|
|
6497
6578
|
});
|
|
6498
6579
|
|
|
6499
6580
|
// src/commands/list.ts
|
|
6500
|
-
import { assertNever as assertNever3, RECORDS_PATH as
|
|
6581
|
+
import { assertNever as assertNever3, RECORDS_PATH as RECORDS_PATH4, resolveAll as resolveAll3, variableName as variableName8 } from "@penvhq/core";
|
|
6501
6582
|
import { defineCommand as defineCommand16 } from "citty";
|
|
6502
6583
|
function scopeLabel2(scope) {
|
|
6503
6584
|
switch (scope.kind) {
|
|
@@ -6541,7 +6622,7 @@ function paintScope(entry) {
|
|
|
6541
6622
|
function renderList(result2) {
|
|
6542
6623
|
if (result2.parameters.length === 0) {
|
|
6543
6624
|
return [
|
|
6544
|
-
`No parameters in ${
|
|
6625
|
+
`No parameters in ${RECORDS_PATH4}/ for environment ${result2.environment}.`,
|
|
6545
6626
|
tip(`penv set <key> --env ${result2.environment}`)
|
|
6546
6627
|
];
|
|
6547
6628
|
}
|
|
@@ -6580,7 +6661,7 @@ import {
|
|
|
6580
6661
|
existsSync as existsSync10,
|
|
6581
6662
|
mkdirSync as mkdirSync5,
|
|
6582
6663
|
readdirSync as readdirSync6,
|
|
6583
|
-
readFileSync as
|
|
6664
|
+
readFileSync as readFileSync11,
|
|
6584
6665
|
renameSync as renameSync2,
|
|
6585
6666
|
rmSync as rmSync2,
|
|
6586
6667
|
writeFileSync as writeFileSync6
|
|
@@ -6592,7 +6673,7 @@ import {
|
|
|
6592
6673
|
oldLayoutEntries,
|
|
6593
6674
|
PENV_DIR as PENV_DIR3,
|
|
6594
6675
|
PenvError as PenvError22,
|
|
6595
|
-
RECORDS_PATH as
|
|
6676
|
+
RECORDS_PATH as RECORDS_PATH5,
|
|
6596
6677
|
recordsDir as recordsDir3,
|
|
6597
6678
|
renderStateGitignore as renderStateGitignore2,
|
|
6598
6679
|
STATE_GITIGNORE_PATH as STATE_GITIGNORE_PATH2
|
|
@@ -6608,13 +6689,13 @@ function planMigrate(cwd) {
|
|
|
6608
6689
|
if (collisions.length > 0) {
|
|
6609
6690
|
throw new PenvError22(
|
|
6610
6691
|
"HALF_MIGRATED",
|
|
6611
|
-
`${describe2(collisions)} in both \`${PENV_DIR3}/\` and \`${
|
|
6612
|
-
`Move what is left under \`${PENV_DIR3}/\` into \`${
|
|
6692
|
+
`${describe2(collisions)} in both \`${PENV_DIR3}/\` and \`${RECORDS_PATH5}/\`, and penv cannot tell which copy is current`,
|
|
6693
|
+
`Move what is left under \`${PENV_DIR3}/\` into \`${RECORDS_PATH5}/\` yourself, keeping the copy you want, then run \`penv validate\`.`
|
|
6613
6694
|
);
|
|
6614
6695
|
}
|
|
6615
6696
|
const creates = [];
|
|
6616
6697
|
if (entries.length > 0 && !existsSync10(tree)) {
|
|
6617
|
-
creates.push(`${
|
|
6698
|
+
creates.push(`${RECORDS_PATH5}/`);
|
|
6618
6699
|
}
|
|
6619
6700
|
if (readIfPresent(join10(root, ...STATE_GITIGNORE_PATH2.split("/"))) !== renderStateGitignore2(config)) {
|
|
6620
6701
|
creates.push(STATE_GITIGNORE_PATH2);
|
|
@@ -6623,14 +6704,14 @@ function planMigrate(cwd) {
|
|
|
6623
6704
|
root,
|
|
6624
6705
|
moves: entries.map((entry) => ({
|
|
6625
6706
|
from: `${PENV_DIR3}/${entry}`,
|
|
6626
|
-
to: `${
|
|
6707
|
+
to: `${RECORDS_PATH5}/${entry}`
|
|
6627
6708
|
})),
|
|
6628
6709
|
creates,
|
|
6629
6710
|
removes: existsSync10(join10(root, ...OLD_GITIGNORE.split("/"))) ? [OLD_GITIGNORE] : []
|
|
6630
6711
|
};
|
|
6631
6712
|
}
|
|
6632
6713
|
function readIfPresent(file) {
|
|
6633
|
-
return existsSync10(file) ?
|
|
6714
|
+
return existsSync10(file) ? readFileSync11(file, "utf8") : void 0;
|
|
6634
6715
|
}
|
|
6635
6716
|
function collidingEntries(entries, tree) {
|
|
6636
6717
|
let held;
|
|
@@ -6678,7 +6759,7 @@ function runMigrate(options) {
|
|
|
6678
6759
|
}
|
|
6679
6760
|
function renderMigrate(result2) {
|
|
6680
6761
|
if (result2.status === "current") {
|
|
6681
|
-
return [`${out.green(CHECK)} Already on ${
|
|
6762
|
+
return [`${out.green(CHECK)} Already on ${RECORDS_PATH5}/ \u2014 nothing to migrate.`];
|
|
6682
6763
|
}
|
|
6683
6764
|
const done = result2.status === "migrated";
|
|
6684
6765
|
const glyph = done ? CHECK : "\u2192";
|
|
@@ -6719,7 +6800,7 @@ async function approveOnTty() {
|
|
|
6719
6800
|
var migrateCommand = defineCommand17({
|
|
6720
6801
|
meta: {
|
|
6721
6802
|
name: "migrate",
|
|
6722
|
-
description: `Move a project written under an earlier layout to ${
|
|
6803
|
+
description: `Move a project written under an earlier layout to ${RECORDS_PATH5}/`
|
|
6723
6804
|
},
|
|
6724
6805
|
args: {
|
|
6725
6806
|
yes: { type: "boolean", description: "Apply the previewed move without asking" }
|