@penvhq/cli 0.2.0 → 0.3.1
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 +286 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -1
- package/dist/index.d.ts +71 -1
- package/dist/index.js +208 -61
- package/dist/index.js.map +1 -1
- package/package.json +10 -7
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { setKeychain } from "@penvhq/core";
|
|
3
|
-
import { runMain as cittyRunMain, defineCommand as
|
|
3
|
+
import { runMain as cittyRunMain, defineCommand as defineCommand18 } from "citty";
|
|
4
4
|
|
|
5
5
|
// src/commands/doctor.ts
|
|
6
6
|
import {
|
|
@@ -26,12 +26,14 @@ import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
|
26
26
|
import {
|
|
27
27
|
candidatesFor,
|
|
28
28
|
formatValueFile,
|
|
29
|
+
isCanonicalSegment,
|
|
29
30
|
isReservedToken,
|
|
30
31
|
loadConfig,
|
|
31
32
|
openValue,
|
|
32
33
|
PenvError as PenvError2,
|
|
33
34
|
parameterId,
|
|
34
35
|
ReservedTokenError,
|
|
36
|
+
refFromAccessPath,
|
|
35
37
|
resolveEnvironment,
|
|
36
38
|
resolveKeySource
|
|
37
39
|
} from "@penvhq/core";
|
|
@@ -43,13 +45,20 @@ import { dirname, resolve } from "path";
|
|
|
43
45
|
import { pathToFileURL } from "url";
|
|
44
46
|
import { PenvError } from "@penvhq/core";
|
|
45
47
|
import { createFilesystemProvider } from "@penvhq/provider-filesystem";
|
|
48
|
+
import { createKubernetesProvider } from "@penvhq/provider-kubernetes";
|
|
46
49
|
import { createMockProvider } from "@penvhq/provider-mock";
|
|
50
|
+
import { createSsmProvider } from "@penvhq/provider-ssm";
|
|
47
51
|
import { createVaultProvider } from "@penvhq/provider-vault";
|
|
48
52
|
var PLUGIN_FACTORY_EXPORT = "penvProviderFactory";
|
|
49
53
|
var LOCAL_TREE_TYPE = "filesystem";
|
|
50
54
|
var REGISTRY = /* @__PURE__ */ new Map([
|
|
51
55
|
[LOCAL_TREE_TYPE, ({ root, config }) => createFilesystemProvider({ root, config })],
|
|
52
56
|
["vault", ({ providerConfig }) => createVaultProvider({ path: providerConfig?.path ?? "penv" })],
|
|
57
|
+
["ssm", ({ providerConfig }) => createSsmProvider({ path: providerConfig?.path ?? "penv" })],
|
|
58
|
+
[
|
|
59
|
+
"kubernetes",
|
|
60
|
+
({ providerConfig }) => createKubernetesProvider(kubernetesOptions(providerConfig))
|
|
61
|
+
],
|
|
53
62
|
["mock", ({ root }) => createMockProvider({ storePath: resolve(root, ".penv-mock.json") })]
|
|
54
63
|
]);
|
|
55
64
|
var CONTRACT_METHODS = [
|
|
@@ -152,6 +161,14 @@ function assertSatisfiesContract(provider, specifier) {
|
|
|
152
161
|
}
|
|
153
162
|
}
|
|
154
163
|
}
|
|
164
|
+
function kubernetesOptions(providerConfig) {
|
|
165
|
+
const path = providerConfig?.path ?? "penv";
|
|
166
|
+
const slash = path.indexOf("/");
|
|
167
|
+
if (slash === -1) return { secretName: path };
|
|
168
|
+
const namespace = path.slice(0, slash);
|
|
169
|
+
const secretName = path.slice(slash + 1) || "penv";
|
|
170
|
+
return namespace === "" ? { secretName } : { namespace, secretName };
|
|
171
|
+
}
|
|
155
172
|
function unknownProvider(type, environment, specifier) {
|
|
156
173
|
const known = [...REGISTRY.keys()].map((name) => `\`${name}\``).join(", ");
|
|
157
174
|
const where = environment === void 0 ? "" : ` for environment ${environment}`;
|
|
@@ -220,6 +237,26 @@ function refFromKey(key, config) {
|
|
|
220
237
|
}
|
|
221
238
|
return { namespace: segments.slice(0, -1), name };
|
|
222
239
|
}
|
|
240
|
+
function assertWritableKey(key) {
|
|
241
|
+
const segments = key.split(KEY_SEPARATOR).filter((s) => s.length > 0);
|
|
242
|
+
if (segments.length === 0 || segments.every((s) => isCanonicalSegment(s))) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const ref = refFromAccessPath(segments);
|
|
246
|
+
if (ref !== void 0) {
|
|
247
|
+
const suggestion = [...ref.namespace, ref.name].join("/");
|
|
248
|
+
throw new PenvError2(
|
|
249
|
+
"PARAMETER_KEY_CASING",
|
|
250
|
+
`\`${key}\` is not a canonical parameter name`,
|
|
251
|
+
`Parameter files are lower-case and hyphenated. Did you mean \`${suggestion}\`? That is the file that backs the \`${key}\` key in your schema.`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
throw new PenvError2(
|
|
255
|
+
"PARAMETER_KEY_UNREACHABLE",
|
|
256
|
+
`No value file can be named that reaches \`${key}\``,
|
|
257
|
+
"Parameter files are lower-case and hyphenated, and this key maps to no such file \u2014 a run of capitals like `apiURL` cannot be reached (use `api-url`, which the schema reads as `apiUrl`). Run `penv validate` or `penv fill` to see the names penv expects."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
223
260
|
function keySourceFor(project, environment) {
|
|
224
261
|
return resolveKeySource(project.config, environment);
|
|
225
262
|
}
|
|
@@ -266,7 +303,7 @@ import {
|
|
|
266
303
|
accessPath,
|
|
267
304
|
isReservedToken as isReservedToken2,
|
|
268
305
|
parameterId as parameterId2,
|
|
269
|
-
refFromAccessPath,
|
|
306
|
+
refFromAccessPath as refFromAccessPath2,
|
|
270
307
|
variableName
|
|
271
308
|
} from "@penvhq/core";
|
|
272
309
|
function defOf(node) {
|
|
@@ -374,7 +411,7 @@ function computeDrift(input) {
|
|
|
374
411
|
continue;
|
|
375
412
|
}
|
|
376
413
|
const path = leaf.path.join(".");
|
|
377
|
-
const ref =
|
|
414
|
+
const ref = refFromAccessPath2(leaf.path);
|
|
378
415
|
if (ref === void 0 || isReservedToken2(ref.name, config)) {
|
|
379
416
|
declared.push({
|
|
380
417
|
subject: path,
|
|
@@ -646,6 +683,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
|
|
|
646
683
|
import {
|
|
647
684
|
accessPath as accessPath2,
|
|
648
685
|
checkNameCollisions as checkNameCollisions2,
|
|
686
|
+
jitiFor,
|
|
649
687
|
NameCollisionError,
|
|
650
688
|
PenvError as PenvError5,
|
|
651
689
|
ReservedTokenError as ReservedTokenError2,
|
|
@@ -654,7 +692,6 @@ import {
|
|
|
654
692
|
validateConfig
|
|
655
693
|
} from "@penvhq/core";
|
|
656
694
|
import { defineCommand as defineCommand2 } from "citty";
|
|
657
|
-
import { createJiti } from "jiti";
|
|
658
695
|
var SCHEMA_EXPORT = "schema";
|
|
659
696
|
var LABELS = {
|
|
660
697
|
config: "Config",
|
|
@@ -733,7 +770,7 @@ function loadSchema(project, environment) {
|
|
|
733
770
|
return exclusively(() => loadSchemaExclusively(file, schemaPath, environment));
|
|
734
771
|
}
|
|
735
772
|
async function loadSchemaExclusively(file, schemaPath, environment) {
|
|
736
|
-
const jiti =
|
|
773
|
+
const jiti = jitiFor(file);
|
|
737
774
|
const previous = process.env.PENV_ENV;
|
|
738
775
|
process.env.PENV_ENV = environment;
|
|
739
776
|
let loaded;
|
|
@@ -1735,6 +1772,7 @@ async function sealAwareWrite(options) {
|
|
|
1735
1772
|
}
|
|
1736
1773
|
async function runSet(options) {
|
|
1737
1774
|
const project = openProject(options.cwd);
|
|
1775
|
+
assertWritableKey(options.key);
|
|
1738
1776
|
const ref = refFromKey(options.key, project.config);
|
|
1739
1777
|
const scope = targetScope(project, options, options.key);
|
|
1740
1778
|
const environment = policyEnvironment(project, options);
|
|
@@ -1937,18 +1975,123 @@ var decryptCommand = defineCommand5({
|
|
|
1937
1975
|
}
|
|
1938
1976
|
});
|
|
1939
1977
|
|
|
1978
|
+
// src/commands/fill.ts
|
|
1979
|
+
import { createInterface } from "readline/promises";
|
|
1980
|
+
import { PenvError as PenvError8 } from "@penvhq/core";
|
|
1981
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
1982
|
+
var BLOCKING = /* @__PURE__ */ new Set(["config", "collision", "reserved"]);
|
|
1983
|
+
async function runFill(options) {
|
|
1984
|
+
const validation = await runValidate({
|
|
1985
|
+
cwd: options.cwd,
|
|
1986
|
+
...options.environment === void 0 ? {} : { environment: options.environment }
|
|
1987
|
+
});
|
|
1988
|
+
const environment = validation.environment;
|
|
1989
|
+
const blockers = validation.issues.filter((issue) => BLOCKING.has(issue.kind));
|
|
1990
|
+
if (blockers.length > 0) {
|
|
1991
|
+
const detail = blockers.map(
|
|
1992
|
+
(issue) => ` - ${issue.message}${issue.remedy === void 0 ? "" : ` (${issue.remedy})`}`
|
|
1993
|
+
).join("\n");
|
|
1994
|
+
throw new PenvError8(
|
|
1995
|
+
"FILL_BLOCKED",
|
|
1996
|
+
`penv fill cannot run: environment ${environment} has ${blockers.length} unresolved configuration ${blockers.length === 1 ? "issue" : "issues"}:
|
|
1997
|
+
${detail}`,
|
|
1998
|
+
`Fix these \u2014 \`penv validate\` reports them \u2014 then run \`penv fill\`. If you have not written a schema yet, declare the required parameters in ${PENV_DIR}/env.ts.`
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
const written = [];
|
|
2002
|
+
const skipped2 = [];
|
|
2003
|
+
const unreachable = [];
|
|
2004
|
+
for (const drift of validation.drift.declared) {
|
|
2005
|
+
if (drift.ref === void 0) {
|
|
2006
|
+
unreachable.push({ subject: drift.subject, remedy: drift.remedy });
|
|
2007
|
+
continue;
|
|
2008
|
+
}
|
|
2009
|
+
const ref = drift.ref;
|
|
2010
|
+
const key = [...ref.namespace, ref.name].join("/");
|
|
2011
|
+
const value = await options.ask({ parameter: key, environment, secret: false });
|
|
2012
|
+
if (value === void 0 || value === "") {
|
|
2013
|
+
skipped2.push(drift.subject);
|
|
2014
|
+
continue;
|
|
2015
|
+
}
|
|
2016
|
+
const result2 = await runSet({ cwd: options.cwd, key, value, environment });
|
|
2017
|
+
written.push({
|
|
2018
|
+
parameter: drift.subject,
|
|
2019
|
+
location: result2.location,
|
|
2020
|
+
encrypted: result2.encrypted
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
return { environment, written, skipped: skipped2, unreachable };
|
|
2024
|
+
}
|
|
2025
|
+
function summaryLine(result2) {
|
|
2026
|
+
const filled = result2.written.length;
|
|
2027
|
+
if (filled === 0 && result2.skipped.length === 0 && result2.unreachable.length === 0) {
|
|
2028
|
+
return `Nothing to fill for environment ${result2.environment}: every declared parameter has a value`;
|
|
2029
|
+
}
|
|
2030
|
+
const parts = [`${filled} written`];
|
|
2031
|
+
if (result2.skipped.length > 0) {
|
|
2032
|
+
parts.push(`${result2.skipped.length} skipped`);
|
|
2033
|
+
}
|
|
2034
|
+
if (result2.unreachable.length > 0) {
|
|
2035
|
+
parts.push(`${result2.unreachable.length} unreachable`);
|
|
2036
|
+
}
|
|
2037
|
+
return `${parts.join(", ")} for environment ${result2.environment}`;
|
|
2038
|
+
}
|
|
2039
|
+
function renderFill(result2) {
|
|
2040
|
+
const rows = result2.written.map((entry) => ({
|
|
2041
|
+
glyph: CHECK,
|
|
2042
|
+
label: "Wrote",
|
|
2043
|
+
subject: `${PENV_DIR}/${entry.location}`,
|
|
2044
|
+
// Meta decided the seal, not the answer, so the line says so — as `set` does.
|
|
2045
|
+
...entry.encrypted ? { detail: "encrypted, per the parameter's meta policy" } : {}
|
|
2046
|
+
}));
|
|
2047
|
+
for (const entry of result2.unreachable) {
|
|
2048
|
+
rows.push({ glyph: WARN, label: "Unreachable", subject: entry.subject, detail: entry.remedy });
|
|
2049
|
+
}
|
|
2050
|
+
const lines = formatRows(rows);
|
|
2051
|
+
lines.push(summaryLine(result2));
|
|
2052
|
+
return lines;
|
|
2053
|
+
}
|
|
2054
|
+
var fillCommand = defineCommand6({
|
|
2055
|
+
meta: {
|
|
2056
|
+
name: "fill",
|
|
2057
|
+
description: "Prompt for each declared parameter the tree has no value for"
|
|
2058
|
+
},
|
|
2059
|
+
args: {
|
|
2060
|
+
env: { type: "string", description: "The environment to fill" }
|
|
2061
|
+
},
|
|
2062
|
+
run({ args }) {
|
|
2063
|
+
return guard(async () => {
|
|
2064
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2065
|
+
const ask = (prompt) => rl.question(`${prompt.parameter} (${prompt.environment}): `);
|
|
2066
|
+
try {
|
|
2067
|
+
write(
|
|
2068
|
+
renderFill(
|
|
2069
|
+
await runFill({
|
|
2070
|
+
cwd: process.cwd(),
|
|
2071
|
+
...args.env === void 0 ? {} : { environment: args.env },
|
|
2072
|
+
ask
|
|
2073
|
+
})
|
|
2074
|
+
)
|
|
2075
|
+
);
|
|
2076
|
+
} finally {
|
|
2077
|
+
rl.close();
|
|
2078
|
+
}
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
|
|
1940
2083
|
// src/commands/generate.ts
|
|
1941
2084
|
import { writeFileSync } from "fs";
|
|
1942
2085
|
import { isAbsolute, relative, resolve as resolve3 } from "path";
|
|
1943
2086
|
import {
|
|
1944
2087
|
checkNameCollisions as checkNameCollisions3,
|
|
1945
2088
|
effectiveMeta as effectiveMeta2,
|
|
1946
|
-
PenvError as
|
|
2089
|
+
PenvError as PenvError9,
|
|
1947
2090
|
requireValue as requireValue2,
|
|
1948
2091
|
serializeDotenv,
|
|
1949
2092
|
variableName as variableName4
|
|
1950
2093
|
} from "@penvhq/core";
|
|
1951
|
-
import { defineCommand as
|
|
2094
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
1952
2095
|
var DEFAULT_OUTPUT = ".env";
|
|
1953
2096
|
function entriesFor(project, environment, allowDecrypt) {
|
|
1954
2097
|
const keys = keySourceFor(project, environment);
|
|
@@ -1967,7 +2110,7 @@ function entriesFor(project, environment, allowDecrypt) {
|
|
|
1967
2110
|
const winner = resolution.winner;
|
|
1968
2111
|
if (winner?.file.encrypted === true) {
|
|
1969
2112
|
if (!allowDecrypt) {
|
|
1970
|
-
throw new
|
|
2113
|
+
throw new PenvError9(
|
|
1971
2114
|
"ENCRYPTED_VALUE_REFUSED",
|
|
1972
2115
|
`Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${PENV_DIR}/${winner.location}, and \`penv generate\` writes plaintext`,
|
|
1973
2116
|
`Re-run with \`--allow-decrypt\` to write the decrypted value into the artifact, or generate for an environment whose values are plaintext. The artifact is gitignored; a committed plaintext secret is a \`penv doctor\` failure.`
|
|
@@ -2025,7 +2168,7 @@ function renderGenerate(result2, cwd) {
|
|
|
2025
2168
|
}
|
|
2026
2169
|
return formatRows(rows);
|
|
2027
2170
|
}
|
|
2028
|
-
var generateCommand =
|
|
2171
|
+
var generateCommand = defineCommand7({
|
|
2029
2172
|
meta: { name: "generate", description: "Write a standard .env artifact for deploy targets" },
|
|
2030
2173
|
args: {
|
|
2031
2174
|
env: { type: "string", description: "The environment to generate for" },
|
|
@@ -2050,8 +2193,8 @@ var generateCommand = defineCommand6({
|
|
|
2050
2193
|
});
|
|
2051
2194
|
|
|
2052
2195
|
// src/commands/get.ts
|
|
2053
|
-
import { PenvError as
|
|
2054
|
-
import { defineCommand as
|
|
2196
|
+
import { PenvError as PenvError10, requireValue as requireValue3, resolveParameter } from "@penvhq/core";
|
|
2197
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2055
2198
|
async function runGet(options) {
|
|
2056
2199
|
const project = openProject(options.cwd);
|
|
2057
2200
|
const environment = targetEnvironment(project, options.environment);
|
|
@@ -2060,7 +2203,7 @@ async function runGet(options) {
|
|
|
2060
2203
|
const resolution = await resolveParameter(ref, environment, project.provider, keys);
|
|
2061
2204
|
const value = requireValue3(resolution, environment);
|
|
2062
2205
|
if (value === void 0) {
|
|
2063
|
-
throw new
|
|
2206
|
+
throw new PenvError10(
|
|
2064
2207
|
"PARAMETER_ABSENT",
|
|
2065
2208
|
`Parameter ${resolution.parameter} resolves to no value for environment ${environment}`,
|
|
2066
2209
|
`Set it with \`penv set ${options.key} --env ${environment}\`, or run \`penv get ${options.key} --env ${environment} --explain\` to see every file penv looked at.`
|
|
@@ -2110,7 +2253,7 @@ function renderExplain(explanation) {
|
|
|
2110
2253
|
...columns(rows).map((line) => ` ${line}`)
|
|
2111
2254
|
];
|
|
2112
2255
|
}
|
|
2113
|
-
var getCommand =
|
|
2256
|
+
var getCommand = defineCommand8({
|
|
2114
2257
|
meta: { name: "get", description: "Read a parameter" },
|
|
2115
2258
|
args: {
|
|
2116
2259
|
key: { type: "positional", required: true, description: "The parameter, e.g. redis/password" },
|
|
@@ -2145,7 +2288,7 @@ import {
|
|
|
2145
2288
|
isReservedToken as isReservedToken3,
|
|
2146
2289
|
loadConfigFrom as loadConfigFrom2,
|
|
2147
2290
|
lookupEnvironment,
|
|
2148
|
-
PenvError as
|
|
2291
|
+
PenvError as PenvError12,
|
|
2149
2292
|
parseDotenv,
|
|
2150
2293
|
ReservedTokenError as ReservedTokenError3,
|
|
2151
2294
|
refFromVariable,
|
|
@@ -2154,7 +2297,7 @@ import {
|
|
|
2154
2297
|
UnknownEnvironmentError,
|
|
2155
2298
|
variableName as variableName5
|
|
2156
2299
|
} from "@penvhq/core";
|
|
2157
|
-
import { defineCommand as
|
|
2300
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
2158
2301
|
|
|
2159
2302
|
// src/detect.ts
|
|
2160
2303
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -2260,18 +2403,18 @@ function hasImportsBlock(cwd) {
|
|
|
2260
2403
|
// src/commands/init.ts
|
|
2261
2404
|
import { existsSync as existsSync2, mkdirSync, readdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2262
2405
|
import { dirname as dirname3, join as join2, resolve as resolve4 } from "path";
|
|
2263
|
-
import { createInterface } from "readline/promises";
|
|
2406
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
2264
2407
|
import {
|
|
2265
2408
|
DEFAULT_SCHEMA_FILE as DEFAULT_SCHEMA_FILE2,
|
|
2266
2409
|
isLegalEnvironmentName,
|
|
2267
2410
|
loadConfigFrom,
|
|
2268
|
-
PenvError as
|
|
2411
|
+
PenvError as PenvError11,
|
|
2269
2412
|
RESERVED_TOKENS,
|
|
2270
2413
|
schemaFileOf as schemaFileOf2,
|
|
2271
2414
|
schemaInsideTree,
|
|
2272
2415
|
validateSchemaFile
|
|
2273
2416
|
} from "@penvhq/core";
|
|
2274
|
-
import { defineCommand as
|
|
2417
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
2275
2418
|
var CONFIG_FILE = "penv.config.ts";
|
|
2276
2419
|
var TSCONFIG_FILE = "tsconfig.json";
|
|
2277
2420
|
var GITIGNORE_FILE = ".gitignore";
|
|
@@ -2309,7 +2452,7 @@ function suggestEnvironments(root) {
|
|
|
2309
2452
|
return [...found].sort();
|
|
2310
2453
|
}
|
|
2311
2454
|
function emptyFlag(flag) {
|
|
2312
|
-
return new
|
|
2455
|
+
return new PenvError11(
|
|
2313
2456
|
"INIT_FLAG_EMPTY",
|
|
2314
2457
|
`\`--${flag}\` was given without a value`,
|
|
2315
2458
|
flag === "schema" ? `Name the module that exports the schema, e.g. \`--schema src/env.ts\`, or drop the flag to use ${DEFAULT_SCHEMA_FILE2}.` : "Name the environment, e.g. `--env production`, or drop the flag to leave the whitelist empty and declare it in penv.config.ts."
|
|
@@ -2372,7 +2515,7 @@ function planInit(root, flags = {}) {
|
|
|
2372
2515
|
throw emptyFlag("alias");
|
|
2373
2516
|
}
|
|
2374
2517
|
if (!ALIAS_NAME.test(alias)) {
|
|
2375
|
-
throw new
|
|
2518
|
+
throw new PenvError11(
|
|
2376
2519
|
"INIT_ALIAS_INVALID",
|
|
2377
2520
|
`\`${alias}\` is not an alias penv can write`,
|
|
2378
2521
|
`An alias is \`@name\` \u2014 a tsconfig \`paths\` entry a bundler resolves \u2014 or \`#name\`, a package.json \`imports\` entry Node resolves itself. Those are the two things a module specifier can be that is not a package.`
|
|
@@ -2659,7 +2802,7 @@ ${objectIndent}${source.slice(close)}`;
|
|
|
2659
2802
|
${entryIndent}${member},${source.slice(open + 1)}`;
|
|
2660
2803
|
}
|
|
2661
2804
|
function shapeError(what, target, alias) {
|
|
2662
|
-
return new
|
|
2805
|
+
return new PenvError11(
|
|
2663
2806
|
"TSCONFIG_SHAPE",
|
|
2664
2807
|
`penv cannot add the \`${alias}\` path alias to tsconfig.json: ${what}`,
|
|
2665
2808
|
`Add it by hand: \`{ "compilerOptions": { "paths": { "${alias}": ["${target}"] } } }\`.`
|
|
@@ -2853,7 +2996,7 @@ function renderInit(result2) {
|
|
|
2853
2996
|
];
|
|
2854
2997
|
}
|
|
2855
2998
|
async function askOnTty(plan2) {
|
|
2856
|
-
const rl =
|
|
2999
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
2857
3000
|
try {
|
|
2858
3001
|
return await promptForDecisions(plan2, {
|
|
2859
3002
|
ask: (question) => rl.question(question),
|
|
@@ -2864,7 +3007,7 @@ async function askOnTty(plan2) {
|
|
|
2864
3007
|
rl.close();
|
|
2865
3008
|
}
|
|
2866
3009
|
}
|
|
2867
|
-
var initCommand =
|
|
3010
|
+
var initCommand = defineCommand9({
|
|
2868
3011
|
meta: { name: "init", description: "Initialize a project (.penv/, env.ts, config, @env alias)" },
|
|
2869
3012
|
args: {
|
|
2870
3013
|
yes: {
|
|
@@ -2938,7 +3081,7 @@ function assertImportable(ref, variable) {
|
|
|
2938
3081
|
if (!ref.name.includes(".")) {
|
|
2939
3082
|
return;
|
|
2940
3083
|
}
|
|
2941
|
-
throw new
|
|
3084
|
+
throw new PenvError12(
|
|
2942
3085
|
"IMPORT_UNPARSEABLE_NAME",
|
|
2943
3086
|
`The variable ${variable} becomes the parameter \`${ref.name}\`, whose \`.\` would be read as a scope`,
|
|
2944
3087
|
`Filenames are split on \`.\`. Rename ${variable} in the source file, then import it again.`
|
|
@@ -2957,7 +3100,7 @@ function assertRoundTrips(ref, variable, config) {
|
|
|
2957
3100
|
return;
|
|
2958
3101
|
}
|
|
2959
3102
|
const generated = variableName5(ref, config);
|
|
2960
|
-
throw new
|
|
3103
|
+
throw new PenvError12(
|
|
2961
3104
|
"IMPORT_LOSSY_NAME",
|
|
2962
3105
|
`The variable ${variable} becomes the parameter \`${ref.name}\`, which regenerates as ${generated}`,
|
|
2963
3106
|
`\`penv generate\` would write ${generated}, so anything reading \`process.env["${variable}"]\` would read \`undefined\`. Declare the name you want in the \`names\` block of penv.config.ts \u2014 \`names: { "${ref.name}": "${variable}" }\` \u2014 then import it again. Nothing was imported.`
|
|
@@ -3041,7 +3184,7 @@ function explicitEnvironment(options, source, config) {
|
|
|
3041
3184
|
if (value.length > 0) {
|
|
3042
3185
|
return value;
|
|
3043
3186
|
}
|
|
3044
|
-
throw new
|
|
3187
|
+
throw new PenvError12(
|
|
3045
3188
|
"IMPORT_ENV_FLAG_EMPTY",
|
|
3046
3189
|
`\`--env\` for the import of ${source} names no environment`,
|
|
3047
3190
|
`Pass a declared environment \u2014 ${config.environments.map((e) => `\`${e}\``).join(", ")} \u2014 e.g. \`--env production\`, or drop \`--env\` to import ${source} as the scope that has no environment. Nothing was imported.`
|
|
@@ -3051,7 +3194,7 @@ function assertEnvironmentAgrees(derived, explicit, source) {
|
|
|
3051
3194
|
if (derived === void 0 || explicit === void 0 || derived === explicit) {
|
|
3052
3195
|
return;
|
|
3053
3196
|
}
|
|
3054
|
-
throw new
|
|
3197
|
+
throw new PenvError12(
|
|
3055
3198
|
"IMPORT_ENV_CONFLICT",
|
|
3056
3199
|
`The file ${source} is scoped to environment ${derived}, but \`--env ${explicit}\` names ${explicit}`,
|
|
3057
3200
|
`Drop \`--env\` to import ${source} as ${derived}, pass \`--env ${derived}\` to say the same thing twice, or point \`penv import\` at the file that holds ${explicit}'s values. Nothing was imported.`
|
|
@@ -3095,7 +3238,7 @@ function importDotenv(options) {
|
|
|
3095
3238
|
const cwd = resolve5(options.cwd);
|
|
3096
3239
|
const file = isAbsolute2(options.file) ? options.file : resolve5(cwd, options.file);
|
|
3097
3240
|
if (!existsSync3(file)) {
|
|
3098
|
-
throw new
|
|
3241
|
+
throw new PenvError12(
|
|
3099
3242
|
"IMPORT_FILE_MISSING",
|
|
3100
3243
|
`There is no file at ${file} to import`,
|
|
3101
3244
|
"Point `penv import` at an existing dotenv file, e.g. `penv import .env`."
|
|
@@ -3208,7 +3351,7 @@ function renderImport(result2, validation) {
|
|
|
3208
3351
|
lines.push("", "Done. .penv/ is now your source of truth.");
|
|
3209
3352
|
return lines;
|
|
3210
3353
|
}
|
|
3211
|
-
var importCommand =
|
|
3354
|
+
var importCommand = defineCommand10({
|
|
3212
3355
|
meta: {
|
|
3213
3356
|
name: "import",
|
|
3214
3357
|
description: "Import an existing dotenv file; it becomes the source of truth"
|
|
@@ -3240,8 +3383,8 @@ var importCommand = defineCommand9({
|
|
|
3240
3383
|
|
|
3241
3384
|
// src/commands/key.ts
|
|
3242
3385
|
import { randomBytes } from "crypto";
|
|
3243
|
-
import { KEY_BYTES, KEYCHAIN_SERVICE, PenvError as
|
|
3244
|
-
import { defineCommand as
|
|
3386
|
+
import { KEY_BYTES, KEYCHAIN_SERVICE, PenvError as PenvError13 } from "@penvhq/core";
|
|
3387
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
3245
3388
|
|
|
3246
3389
|
// src/keychain.ts
|
|
3247
3390
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -3273,7 +3416,7 @@ function runKeyCreate(options) {
|
|
|
3273
3416
|
const environment = targetEnvironment(project, options.environment);
|
|
3274
3417
|
const declared = project.config.keys?.[environment];
|
|
3275
3418
|
if (declared === void 0) {
|
|
3276
|
-
throw new
|
|
3419
|
+
throw new PenvError13(
|
|
3277
3420
|
"KEY_SOURCE_UNDECLARED",
|
|
3278
3421
|
`Environment ${environment} declares no key source, so penv does not know what a key for it would be`,
|
|
3279
3422
|
`Add a \`keys\` entry to penv.config.ts \u2014 e.g. \`keys: { ${environment}: { source: "env", id: "${environment}" } }\` \u2014 then run this again.`
|
|
@@ -3287,14 +3430,14 @@ function runKeyCreate(options) {
|
|
|
3287
3430
|
try {
|
|
3288
3431
|
existing = keychain.getPassword(KEYCHAIN_SERVICE, declared.id);
|
|
3289
3432
|
} catch (cause) {
|
|
3290
|
-
throw new
|
|
3433
|
+
throw new PenvError13(
|
|
3291
3434
|
"KEYCHAIN_UNAVAILABLE",
|
|
3292
3435
|
`penv could not read your OS keychain to check for an existing key \`${declared.id}\``,
|
|
3293
3436
|
`Unlock your keychain and run this again. Original error: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
3294
3437
|
);
|
|
3295
3438
|
}
|
|
3296
3439
|
if (existing !== null) {
|
|
3297
|
-
throw new
|
|
3440
|
+
throw new PenvError13(
|
|
3298
3441
|
"KEY_EXISTS",
|
|
3299
3442
|
`Environment ${environment} already has a key \`${declared.id}\` in your OS keychain`,
|
|
3300
3443
|
"Replacing it would orphan every value already sealed under it \u2014 they could never be decrypted again. Re-run with `--force` only if you are certain nothing is sealed under the current key."
|
|
@@ -3331,10 +3474,10 @@ function renderKeyCreate(result2) {
|
|
|
3331
3474
|
"without it, and penv keeps no copy to fall back on."
|
|
3332
3475
|
];
|
|
3333
3476
|
}
|
|
3334
|
-
var keyCommand =
|
|
3477
|
+
var keyCommand = defineCommand11({
|
|
3335
3478
|
meta: { name: "key", description: "Work with encryption keys" },
|
|
3336
3479
|
subCommands: {
|
|
3337
|
-
create:
|
|
3480
|
+
create: defineCommand11({
|
|
3338
3481
|
meta: { name: "create", description: "Generate a key for an environment" },
|
|
3339
3482
|
args: {
|
|
3340
3483
|
env: { type: "string", description: "The environment the key is for" },
|
|
@@ -3362,7 +3505,7 @@ var keyCommand = defineCommand10({
|
|
|
3362
3505
|
|
|
3363
3506
|
// src/commands/list.ts
|
|
3364
3507
|
import { assertNever as assertNever3, resolveAll as resolveAll3, variableName as variableName6 } from "@penvhq/core";
|
|
3365
|
-
import { defineCommand as
|
|
3508
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
3366
3509
|
function scopeLabel2(scope) {
|
|
3367
3510
|
switch (scope.kind) {
|
|
3368
3511
|
case "environment":
|
|
@@ -3402,7 +3545,7 @@ function renderList(result2) {
|
|
|
3402
3545
|
}
|
|
3403
3546
|
return columns(result2.parameters.map((entry) => [entry.parameter, entry.scope, entry.variable]));
|
|
3404
3547
|
}
|
|
3405
|
-
var listCommand =
|
|
3548
|
+
var listCommand = defineCommand12({
|
|
3406
3549
|
meta: { name: "list", description: "List parameters" },
|
|
3407
3550
|
args: {
|
|
3408
3551
|
env: { type: "string", description: "The environment to resolve against" },
|
|
@@ -3425,11 +3568,11 @@ import {
|
|
|
3425
3568
|
formatMetaFile,
|
|
3426
3569
|
formatValueFile as formatValueFile5,
|
|
3427
3570
|
openValue as openValue4,
|
|
3428
|
-
PenvError as
|
|
3571
|
+
PenvError as PenvError14,
|
|
3429
3572
|
parameterId as parameterId5,
|
|
3430
3573
|
sealValue as sealValue3
|
|
3431
3574
|
} from "@penvhq/core";
|
|
3432
|
-
import { defineCommand as
|
|
3575
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
3433
3576
|
function environmentOf2(file) {
|
|
3434
3577
|
const scope = file.scope;
|
|
3435
3578
|
return scope.kind === "environment" || scope.kind === "environment-local" ? scope.environment : void 0;
|
|
@@ -3444,7 +3587,7 @@ async function planFile(project, source, target, parameter) {
|
|
|
3444
3587
|
}
|
|
3445
3588
|
const environment = environmentOf2(source);
|
|
3446
3589
|
if (environment === void 0) {
|
|
3447
|
-
throw new
|
|
3590
|
+
throw new PenvError14(
|
|
3448
3591
|
"SECRET_SCOPE_AMBIGUOUS",
|
|
3449
3592
|
`${PENV_DIR}/${formatValueFile5(source)} is encrypted at a scope that names no environment, so penv cannot tell which key would re-seal it`,
|
|
3450
3593
|
"Keys are declared per environment in the `keys` block of penv.config.ts. Decrypt it with `penv decrypt`, move the parameter, then encrypt it again at its new address."
|
|
@@ -3453,7 +3596,7 @@ async function planFile(project, source, target, parameter) {
|
|
|
3453
3596
|
const keys = keySourceFor(project, environment);
|
|
3454
3597
|
const opened = openValue4(source, stored, keys);
|
|
3455
3598
|
if (opened.kind === "failed") {
|
|
3456
|
-
throw new
|
|
3599
|
+
throw new PenvError14(
|
|
3457
3600
|
"VALUE_UNDECRYPTABLE",
|
|
3458
3601
|
`${PENV_DIR}/${formatValueFile5(source)} could not be decrypted, so penv cannot re-seal it at its new address: ${opened.failure.detail}`,
|
|
3459
3602
|
"A sealed value is bound to the file it lives in, so moving it means opening it and sealing it again. Make the key available and run this again. Nothing has been moved."
|
|
@@ -3473,9 +3616,10 @@ function filesOf(all, ref) {
|
|
|
3473
3616
|
async function runMove(options) {
|
|
3474
3617
|
const project = openProject(options.cwd);
|
|
3475
3618
|
const from = refFromKey(options.from, project.config);
|
|
3619
|
+
assertWritableKey(options.to);
|
|
3476
3620
|
const to = refFromKey(options.to, project.config);
|
|
3477
3621
|
if (parameterId5(from) === parameterId5(to)) {
|
|
3478
|
-
throw new
|
|
3622
|
+
throw new PenvError14(
|
|
3479
3623
|
"PARAMETER_UNCHANGED",
|
|
3480
3624
|
`\`${options.from}\` and \`${options.to}\` are the same parameter`,
|
|
3481
3625
|
"Name a different destination, e.g. `penv mv redis-password redis/password`."
|
|
@@ -3485,7 +3629,7 @@ async function runMove(options) {
|
|
|
3485
3629
|
const sources = filesOf(all, from);
|
|
3486
3630
|
const meta = await project.provider.readMeta(from);
|
|
3487
3631
|
if (sources.length === 0 && meta === void 0) {
|
|
3488
|
-
throw new
|
|
3632
|
+
throw new PenvError14(
|
|
3489
3633
|
"PARAMETER_ABSENT",
|
|
3490
3634
|
`Parameter ${parameterId5(from)} has no value files and no meta, so there is nothing to move`,
|
|
3491
3635
|
`\`penv list\` shows every parameter penv holds.`
|
|
@@ -3493,7 +3637,7 @@ async function runMove(options) {
|
|
|
3493
3637
|
}
|
|
3494
3638
|
const occupied2 = filesOf(all, to);
|
|
3495
3639
|
if (occupied2.length > 0 || await project.provider.readMeta(to) !== void 0) {
|
|
3496
|
-
throw new
|
|
3640
|
+
throw new PenvError14(
|
|
3497
3641
|
"PARAMETER_EXISTS",
|
|
3498
3642
|
`Parameter ${parameterId5(to)} already exists, and penv will not merge two parameters into one`,
|
|
3499
3643
|
`Remove or rename ${parameterId5(to)} first. \`penv get ${options.to} --explain\` shows every file it holds.`
|
|
@@ -3552,7 +3696,7 @@ function renderMove(result2) {
|
|
|
3552
3696
|
);
|
|
3553
3697
|
return lines;
|
|
3554
3698
|
}
|
|
3555
|
-
var mvCommand =
|
|
3699
|
+
var mvCommand = defineCommand13({
|
|
3556
3700
|
meta: { name: "mv", description: "Rename a parameter, every scope and its meta at once" },
|
|
3557
3701
|
args: {
|
|
3558
3702
|
from: {
|
|
@@ -3574,7 +3718,7 @@ var mvCommand = defineCommand12({
|
|
|
3574
3718
|
});
|
|
3575
3719
|
|
|
3576
3720
|
// src/commands/pull.ts
|
|
3577
|
-
import { defineCommand as
|
|
3721
|
+
import { defineCommand as defineCommand14 } from "citty";
|
|
3578
3722
|
async function runPull(options) {
|
|
3579
3723
|
const project = openProject(options.cwd);
|
|
3580
3724
|
const environment = targetEnvironment(project, options.environment);
|
|
@@ -3631,7 +3775,7 @@ function renderPull(result2) {
|
|
|
3631
3775
|
}
|
|
3632
3776
|
]);
|
|
3633
3777
|
}
|
|
3634
|
-
var pullCommand =
|
|
3778
|
+
var pullCommand = defineCommand14({
|
|
3635
3779
|
meta: {
|
|
3636
3780
|
name: "pull",
|
|
3637
3781
|
description: "Materialise the local .penv tree from an environment's source-of-truth provider"
|
|
@@ -3652,7 +3796,7 @@ var pullCommand = defineCommand13({
|
|
|
3652
3796
|
|
|
3653
3797
|
// src/commands/remove.ts
|
|
3654
3798
|
import { formatValueFile as formatValueFile6 } from "@penvhq/core";
|
|
3655
|
-
import { defineCommand as
|
|
3799
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
3656
3800
|
async function runRemove(options) {
|
|
3657
3801
|
const project = openProject(options.cwd);
|
|
3658
3802
|
const ref = refFromKey(options.key);
|
|
@@ -3696,7 +3840,7 @@ function renderRemove(result2) {
|
|
|
3696
3840
|
}));
|
|
3697
3841
|
return formatRows(rows);
|
|
3698
3842
|
}
|
|
3699
|
-
var removeCommand =
|
|
3843
|
+
var removeCommand = defineCommand15({
|
|
3700
3844
|
meta: { name: "remove", description: "Delete a parameter" },
|
|
3701
3845
|
args: {
|
|
3702
3846
|
key: { type: "positional", required: true, description: "The parameter, e.g. redis/password" },
|
|
@@ -3726,11 +3870,11 @@ var removeCommand = defineCommand14({
|
|
|
3726
3870
|
import {
|
|
3727
3871
|
beginRotation,
|
|
3728
3872
|
completeRotation,
|
|
3729
|
-
PenvError as
|
|
3873
|
+
PenvError as PenvError15,
|
|
3730
3874
|
retainsPrevious,
|
|
3731
3875
|
rotationOf as rotationOf2
|
|
3732
3876
|
} from "@penvhq/core";
|
|
3733
|
-
import { defineCommand as
|
|
3877
|
+
import { defineCommand as defineCommand16 } from "citty";
|
|
3734
3878
|
function rotatingFile(ref, environment) {
|
|
3735
3879
|
return {
|
|
3736
3880
|
namespace: ref.namespace,
|
|
@@ -3755,7 +3899,7 @@ async function writeRotatedValue(project, provider, ref, environment, value) {
|
|
|
3755
3899
|
}
|
|
3756
3900
|
function requireNewValue(value, phase, key) {
|
|
3757
3901
|
if (value === void 0) {
|
|
3758
|
-
throw new
|
|
3902
|
+
throw new PenvError15(
|
|
3759
3903
|
"ROTATION_NO_VALUE",
|
|
3760
3904
|
`A ${phase} rotation of ${key} writes a new value, and none was given`,
|
|
3761
3905
|
"Pass the new value as the argument \u2014 `penv rotate <key> <value>` \u2014 or pipe it in on stdin."
|
|
@@ -3765,7 +3909,7 @@ function requireNewValue(value, phase, key) {
|
|
|
3765
3909
|
}
|
|
3766
3910
|
function requireRetaining(provider, environment) {
|
|
3767
3911
|
if (!retainsPrevious(provider)) {
|
|
3768
|
-
throw new
|
|
3912
|
+
throw new PenvError15(
|
|
3769
3913
|
"ROTATION_NOT_RETAINING",
|
|
3770
3914
|
`A dual-valid rotation needs the previous value to stay readable during the grace window, and the \`${provider.type}\` provider for environment ${environment} does not retain it`,
|
|
3771
3915
|
"Point this environment at a provider that keeps prior versions (its `readPrevious` is what penv reads during the window), or, if a momentary overlap is not required, declare the parameter `atomic-cutover` in its meta and flip it in one step."
|
|
@@ -3782,7 +3926,7 @@ async function runRotate(options) {
|
|
|
3782
3926
|
const before = await provider.readMeta(ref);
|
|
3783
3927
|
const { mechanism } = rotationOf2(before, environment);
|
|
3784
3928
|
if (mechanism === void 0) {
|
|
3785
|
-
throw new
|
|
3929
|
+
throw new PenvError15(
|
|
3786
3930
|
"ROTATION_NO_MECHANISM",
|
|
3787
3931
|
`Parameter ${options.key} declares no rotation mechanism for environment ${environment}, so penv does not know how to rotate it`,
|
|
3788
3932
|
'Set `rotationMechanism` in the parameter\'s meta to `"dual-valid"` (a grace-window overlap) or `"atomic-cutover"` (a single flip), then run `penv rotate` again.'
|
|
@@ -3792,7 +3936,7 @@ async function runRotate(options) {
|
|
|
3792
3936
|
const complete = options.complete === true;
|
|
3793
3937
|
if (mechanism === "atomic-cutover") {
|
|
3794
3938
|
if (begin || complete) {
|
|
3795
|
-
throw new
|
|
3939
|
+
throw new PenvError15(
|
|
3796
3940
|
"ROTATION_MECHANISM_MISMATCH",
|
|
3797
3941
|
`Parameter ${options.key} is atomic-cutover, which flips in one step, so \`--begin\`/\`--complete\` do not apply`,
|
|
3798
3942
|
"Run `penv rotate <key> <value>` with no phase flag to flip it. `--begin`/`--complete` bracket a dual-valid grace window, which atomic-cutover has none of."
|
|
@@ -3806,7 +3950,7 @@ async function runRotate(options) {
|
|
|
3806
3950
|
}
|
|
3807
3951
|
const retaining = requireRetaining(provider, environment);
|
|
3808
3952
|
if (begin === complete) {
|
|
3809
|
-
throw new
|
|
3953
|
+
throw new PenvError15(
|
|
3810
3954
|
"ROTATION_PHASE_REQUIRED",
|
|
3811
3955
|
`A dual-valid rotation of ${options.key} needs exactly one of \`--begin\` or \`--complete\``,
|
|
3812
3956
|
"`--begin` writes the new value and opens the grace window; `--complete` closes it once every reader has moved to the new value. Run them in that order, one at a time."
|
|
@@ -3873,7 +4017,7 @@ function renderRotate(result2) {
|
|
|
3873
4017
|
}
|
|
3874
4018
|
]);
|
|
3875
4019
|
}
|
|
3876
|
-
var rotateCommand =
|
|
4020
|
+
var rotateCommand = defineCommand16({
|
|
3877
4021
|
meta: {
|
|
3878
4022
|
name: "rotate",
|
|
3879
4023
|
description: "Rotate a parameter's value by the mechanism its meta declares"
|
|
@@ -3912,7 +4056,7 @@ var rotateCommand = defineCommand15({
|
|
|
3912
4056
|
import { existsSync as existsSync4, watch } from "fs";
|
|
3913
4057
|
import { basename as basename2, dirname as dirname4, resolve as resolve6 } from "path";
|
|
3914
4058
|
import { schemaFileOf as schemaFileOf4, schemaInsideTree as schemaInsideTree2 } from "@penvhq/core";
|
|
3915
|
-
import { defineCommand as
|
|
4059
|
+
import { defineCommand as defineCommand17 } from "citty";
|
|
3916
4060
|
var DEBOUNCE_MS = 100;
|
|
3917
4061
|
function runWatch(options) {
|
|
3918
4062
|
const project = openProject(options.cwd);
|
|
@@ -4089,7 +4233,7 @@ function renderDrift(drift, environment) {
|
|
|
4089
4233
|
}
|
|
4090
4234
|
return lines;
|
|
4091
4235
|
}
|
|
4092
|
-
var watchCommand =
|
|
4236
|
+
var watchCommand = defineCommand17({
|
|
4093
4237
|
meta: {
|
|
4094
4238
|
name: "watch",
|
|
4095
4239
|
description: "Re-validate whenever .penv/ or penv.config.ts changes"
|
|
@@ -4128,7 +4272,7 @@ var watchCommand = defineCommand16({
|
|
|
4128
4272
|
});
|
|
4129
4273
|
|
|
4130
4274
|
// src/index.ts
|
|
4131
|
-
var main =
|
|
4275
|
+
var main = defineCommand18({
|
|
4132
4276
|
meta: {
|
|
4133
4277
|
name: "penv",
|
|
4134
4278
|
description: "Configuration that shares a data model with your production secret manager"
|
|
@@ -4139,6 +4283,7 @@ var main = defineCommand17({
|
|
|
4139
4283
|
generate: generateCommand,
|
|
4140
4284
|
get: getCommand,
|
|
4141
4285
|
set: setCommand,
|
|
4286
|
+
fill: fillCommand,
|
|
4142
4287
|
mv: mvCommand,
|
|
4143
4288
|
pull: pullCommand,
|
|
4144
4289
|
push: pushCommand,
|
|
@@ -4164,6 +4309,7 @@ export {
|
|
|
4164
4309
|
insertEnvAlias,
|
|
4165
4310
|
main,
|
|
4166
4311
|
renderDoctor,
|
|
4312
|
+
renderFill,
|
|
4167
4313
|
renderMove,
|
|
4168
4314
|
renderPull,
|
|
4169
4315
|
renderPush,
|
|
@@ -4173,6 +4319,7 @@ export {
|
|
|
4173
4319
|
runDoctor,
|
|
4174
4320
|
runEncrypt,
|
|
4175
4321
|
runExplain,
|
|
4322
|
+
runFill,
|
|
4176
4323
|
runGenerate,
|
|
4177
4324
|
runGet,
|
|
4178
4325
|
runInit,
|