@fgv/ks 5.1.0-25 → 5.1.0-27
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/.rush/temp/88c339ed20995b7c33d5d2136a7b86a910e004e0.tar.log +42 -0
- package/.rush/temp/chunked-rush-logs/ks.build.chunks.jsonl +7 -0
- package/.rush/temp/operation/build/all.log +7 -0
- package/.rush/temp/operation/build/log-chunks.jsonl +7 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +634 -0
- package/lib/app.d.ts +7 -0
- package/lib/app.d.ts.map +1 -0
- package/lib/app.js +448 -0
- package/lib/app.js.map +1 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +6 -0
- package/lib/cli.js.map +1 -0
- package/lib/help.d.ts +5 -0
- package/lib/help.d.ts.map +1 -0
- package/lib/help.js +104 -0
- package/lib/help.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +32 -0
- package/lib/index.js.map +1 -0
- package/lib/io.d.ts +10 -0
- package/lib/io.d.ts.map +1 -0
- package/lib/io.js +211 -0
- package/lib/io.js.map +1 -0
- package/lib/keystore.d.ts +21 -0
- package/lib/keystore.d.ts.map +1 -0
- package/lib/keystore.js +133 -0
- package/lib/keystore.js.map +1 -0
- package/lib/template.d.ts +5 -0
- package/lib/template.d.ts.map +1 -0
- package/lib/template.js +51 -0
- package/lib/template.js.map +1 -0
- package/package.json +16 -16
- package/rush-logs/ks.build.cache.log +3 -0
- package/rush-logs/ks.build.log +7 -0
- package/temp/build/lint/_eslint-5eVG3S6w.json +34 -0
- package/temp/build/typescript/ts_l9Fw4VUO.json +1 -0
package/lib/app.d.ts
ADDED
package/lib/app.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAqRA,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;;IAOtB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,OAAO,CAAC,cAAc;CAiTvB"}
|
package/lib/app.js
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.KsCli = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
9
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
10
|
+
const io_1 = require("./io");
|
|
11
|
+
const help_1 = require("./help");
|
|
12
|
+
const keystore_1 = require("./keystore");
|
|
13
|
+
const template_1 = require("./template");
|
|
14
|
+
function stripTrailingNewline(value) {
|
|
15
|
+
return value.replace(/\r?\n$/, '');
|
|
16
|
+
}
|
|
17
|
+
function hasExplicitPasswordSource(options) {
|
|
18
|
+
return Boolean(options.passwordEnv || options.passwordFile || options.passwordStdin);
|
|
19
|
+
}
|
|
20
|
+
async function readPasswordFromSource(options) {
|
|
21
|
+
var _a;
|
|
22
|
+
if (options.passwordFile) {
|
|
23
|
+
const fileResult = await (0, io_1.readTextFile)(options.passwordFile);
|
|
24
|
+
if (fileResult.isFailure()) {
|
|
25
|
+
return (0, ts_utils_1.fail)(fileResult.message);
|
|
26
|
+
}
|
|
27
|
+
return (0, ts_utils_1.succeed)(stripTrailingNewline(fileResult.value));
|
|
28
|
+
}
|
|
29
|
+
if (options.passwordStdin) {
|
|
30
|
+
const stdinResult = await (0, io_1.readAllFromStdin)();
|
|
31
|
+
if (stdinResult.isFailure()) {
|
|
32
|
+
return (0, ts_utils_1.fail)(stdinResult.message);
|
|
33
|
+
}
|
|
34
|
+
return (0, ts_utils_1.succeed)(stripTrailingNewline(stdinResult.value));
|
|
35
|
+
}
|
|
36
|
+
if (options.passwordEnv) {
|
|
37
|
+
const envValue = process.env[options.passwordEnv];
|
|
38
|
+
if (envValue === undefined || envValue.length === 0) {
|
|
39
|
+
return (0, ts_utils_1.fail)(`Environment variable '${options.passwordEnv}' is not set`);
|
|
40
|
+
}
|
|
41
|
+
return (0, ts_utils_1.succeed)(envValue);
|
|
42
|
+
}
|
|
43
|
+
const defaultEnv = (_a = process.env.FGV_KS_PASSWORD) !== null && _a !== void 0 ? _a : process.env.KS_PASSWORD;
|
|
44
|
+
if (defaultEnv !== undefined && defaultEnv.length > 0) {
|
|
45
|
+
return (0, ts_utils_1.succeed)(defaultEnv);
|
|
46
|
+
}
|
|
47
|
+
return (0, ts_utils_1.fail)('Password not provided');
|
|
48
|
+
}
|
|
49
|
+
async function resolvePassword(options, label) {
|
|
50
|
+
const source = await readPasswordFromSource(options);
|
|
51
|
+
if (source.isSuccess()) {
|
|
52
|
+
return source;
|
|
53
|
+
}
|
|
54
|
+
// If an explicit source was configured and failed, surface the error rather than prompting
|
|
55
|
+
if (hasExplicitPasswordSource(options)) {
|
|
56
|
+
return source;
|
|
57
|
+
}
|
|
58
|
+
const prompted = await (0, io_1.promptHidden)(`${label}: `);
|
|
59
|
+
if (prompted.isFailure()) {
|
|
60
|
+
return (0, ts_utils_1.fail)(prompted.message);
|
|
61
|
+
}
|
|
62
|
+
return (0, ts_utils_1.succeed)(prompted.value);
|
|
63
|
+
}
|
|
64
|
+
async function resolveSecretName(positionalName, options) {
|
|
65
|
+
if (options.name !== undefined && options.name.length > 0) {
|
|
66
|
+
return (0, ts_utils_1.succeed)(options.name);
|
|
67
|
+
}
|
|
68
|
+
if (positionalName !== undefined && positionalName.length > 0) {
|
|
69
|
+
return (0, ts_utils_1.succeed)(positionalName);
|
|
70
|
+
}
|
|
71
|
+
const prompted = await (0, io_1.promptVisible)('Secret name: ');
|
|
72
|
+
if (prompted.isFailure()) {
|
|
73
|
+
return (0, ts_utils_1.fail)(prompted.message);
|
|
74
|
+
}
|
|
75
|
+
if (prompted.value.length === 0) {
|
|
76
|
+
return (0, ts_utils_1.fail)('Secret name cannot be empty');
|
|
77
|
+
}
|
|
78
|
+
return (0, ts_utils_1.succeed)(prompted.value);
|
|
79
|
+
}
|
|
80
|
+
async function resolvePasswordConfirmed(options, label) {
|
|
81
|
+
// Only skip confirmation when password comes from an explicit non-interactive source.
|
|
82
|
+
// Ambient env vars (FGV_KS_PASSWORD/KS_PASSWORD) are for reading the current password
|
|
83
|
+
// and must not silently bypass confirmation when setting a new one.
|
|
84
|
+
if (hasExplicitPasswordSource(options)) {
|
|
85
|
+
return resolvePassword(options, label);
|
|
86
|
+
}
|
|
87
|
+
const first = await (0, io_1.promptHidden)(`${label}: `);
|
|
88
|
+
if (first.isFailure()) {
|
|
89
|
+
return (0, ts_utils_1.fail)(first.message);
|
|
90
|
+
}
|
|
91
|
+
const second = await (0, io_1.promptHidden)(`${label} (confirm): `);
|
|
92
|
+
if (second.isFailure()) {
|
|
93
|
+
return (0, ts_utils_1.fail)(second.message);
|
|
94
|
+
}
|
|
95
|
+
if (first.value !== second.value) {
|
|
96
|
+
return (0, ts_utils_1.fail)('Passwords do not match');
|
|
97
|
+
}
|
|
98
|
+
return (0, ts_utils_1.succeed)(first.value);
|
|
99
|
+
}
|
|
100
|
+
async function resolveSecretValue(options) {
|
|
101
|
+
if (options.file && options.stdin) {
|
|
102
|
+
return (0, ts_utils_1.fail)('Use either --file or --stdin, not both');
|
|
103
|
+
}
|
|
104
|
+
if (options.file) {
|
|
105
|
+
const fileResult = await (0, io_1.readTextFile)(options.file);
|
|
106
|
+
if (fileResult.isFailure()) {
|
|
107
|
+
return (0, ts_utils_1.fail)(fileResult.message);
|
|
108
|
+
}
|
|
109
|
+
return (0, ts_utils_1.succeed)(stripTrailingNewline(fileResult.value));
|
|
110
|
+
}
|
|
111
|
+
if (options.stdin) {
|
|
112
|
+
const stdinResult = await (0, io_1.readAllFromStdin)();
|
|
113
|
+
if (stdinResult.isFailure()) {
|
|
114
|
+
return (0, ts_utils_1.fail)(stdinResult.message);
|
|
115
|
+
}
|
|
116
|
+
return (0, ts_utils_1.succeed)(stripTrailingNewline(stdinResult.value));
|
|
117
|
+
}
|
|
118
|
+
const prompted = await (0, io_1.promptHidden)('Secret value: ');
|
|
119
|
+
if (prompted.isFailure()) {
|
|
120
|
+
return (0, ts_utils_1.fail)(prompted.message);
|
|
121
|
+
}
|
|
122
|
+
return (0, ts_utils_1.succeed)(prompted.value);
|
|
123
|
+
}
|
|
124
|
+
async function readTemplate(options) {
|
|
125
|
+
if (options.templateFile && options.templateString) {
|
|
126
|
+
return (0, ts_utils_1.fail)('Use either --template-file or --template-string, not both');
|
|
127
|
+
}
|
|
128
|
+
if (options.templateFile) {
|
|
129
|
+
const fileResult = await (0, io_1.readTextFile)((0, io_1.resolvePath)(options.templateFile));
|
|
130
|
+
if (fileResult.isFailure()) {
|
|
131
|
+
return (0, ts_utils_1.fail)(fileResult.message);
|
|
132
|
+
}
|
|
133
|
+
return (0, ts_utils_1.succeed)(fileResult.value);
|
|
134
|
+
}
|
|
135
|
+
if (options.templateString !== undefined) {
|
|
136
|
+
return (0, ts_utils_1.succeed)(options.templateString);
|
|
137
|
+
}
|
|
138
|
+
return (0, ts_utils_1.fail)('Specify either --template-file or --template-string');
|
|
139
|
+
}
|
|
140
|
+
async function collectTemplateContext(keystore, template) {
|
|
141
|
+
const variablesResult = (0, template_1.extractTemplateVariables)(template);
|
|
142
|
+
if (variablesResult.isFailure()) {
|
|
143
|
+
return (0, ts_utils_1.fail)(variablesResult.message);
|
|
144
|
+
}
|
|
145
|
+
const secretListResult = keystore.listSecrets();
|
|
146
|
+
if (secretListResult.isFailure()) {
|
|
147
|
+
return (0, ts_utils_1.fail)(`Failed to list secrets: ${secretListResult.message}`);
|
|
148
|
+
}
|
|
149
|
+
const knownSecrets = new Set(secretListResult.value);
|
|
150
|
+
const context = Object.create(null);
|
|
151
|
+
const missing = [];
|
|
152
|
+
for (const variable of variablesResult.value) {
|
|
153
|
+
const secretResult = keystore.getApiKey(variable);
|
|
154
|
+
if (secretResult.isSuccess()) {
|
|
155
|
+
context[variable] = secretResult.value;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (knownSecrets.has(variable)) {
|
|
159
|
+
return (0, ts_utils_1.fail)(`Secret '${variable}' exists but is not an API key: ${secretResult.message}`);
|
|
160
|
+
}
|
|
161
|
+
const promptResult = await (0, io_1.promptHidden)(`Secret '${variable}' is missing. Enter value: `);
|
|
162
|
+
if (promptResult.isFailure()) {
|
|
163
|
+
return (0, ts_utils_1.fail)(promptResult.message);
|
|
164
|
+
}
|
|
165
|
+
context[variable] = promptResult.value;
|
|
166
|
+
missing.push([variable, promptResult.value]);
|
|
167
|
+
}
|
|
168
|
+
return (0, ts_utils_1.succeed)({ context, missing });
|
|
169
|
+
}
|
|
170
|
+
class KsCli {
|
|
171
|
+
constructor() {
|
|
172
|
+
this._program = new commander_1.Command();
|
|
173
|
+
this._setupCommands();
|
|
174
|
+
}
|
|
175
|
+
async run(argv) {
|
|
176
|
+
await this._program.parseAsync(argv);
|
|
177
|
+
}
|
|
178
|
+
_setupCommands() {
|
|
179
|
+
this._program.name('ks').description('Manage ts-extras keystore files').version(package_json_1.default.version);
|
|
180
|
+
this._program.addHelpCommand(false);
|
|
181
|
+
this._program
|
|
182
|
+
.command('help [topic]')
|
|
183
|
+
.description('Show overview, commands, password, or template help')
|
|
184
|
+
.action((topic) => {
|
|
185
|
+
const help = (0, help_1.getHelpText)(topic, this._program);
|
|
186
|
+
if (help.isFailure()) {
|
|
187
|
+
console.error(`Error: ${help.message}`);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
console.log(help.value);
|
|
191
|
+
});
|
|
192
|
+
this._program
|
|
193
|
+
.command('init')
|
|
194
|
+
.description('Initialize a new keystore')
|
|
195
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
196
|
+
.option('--password-env <name>', 'Environment variable to read the password from')
|
|
197
|
+
.option('--password-file <path>', 'Read the password from a file')
|
|
198
|
+
.option('--password-stdin', 'Read the password from stdin', false)
|
|
199
|
+
.action(async (options) => {
|
|
200
|
+
const password = await resolvePasswordConfirmed(options, 'New keystore password');
|
|
201
|
+
if (password.isFailure()) {
|
|
202
|
+
console.error(`Error: ${password.message}`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
const created = await (0, keystore_1.createKeystore)(options.keystore, password.value);
|
|
206
|
+
if (created.isFailure()) {
|
|
207
|
+
console.error(`Error: ${created.message}`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
this._program
|
|
212
|
+
.command('password')
|
|
213
|
+
.description('Change the keystore password')
|
|
214
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
215
|
+
.option('--password-env <name>', 'Environment variable to read the current password from')
|
|
216
|
+
.option('--password-file <path>', 'Read the current password from a file')
|
|
217
|
+
.option('--password-stdin', 'Read the current password from stdin', false)
|
|
218
|
+
.option('--new-password-env <name>', 'Environment variable to read the new password from')
|
|
219
|
+
.option('--new-password-file <path>', 'Read the new password from a file')
|
|
220
|
+
.option('--new-password-stdin', 'Read the new password from stdin', false)
|
|
221
|
+
.action(async (options) => {
|
|
222
|
+
const currentPassword = await resolvePassword(options, 'Current keystore password');
|
|
223
|
+
if (currentPassword.isFailure()) {
|
|
224
|
+
console.error(`Error: ${currentPassword.message}`);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
const newPasswordOptions = {
|
|
228
|
+
keystore: options.keystore,
|
|
229
|
+
passwordEnv: options.newPasswordEnv,
|
|
230
|
+
passwordFile: options.newPasswordFile,
|
|
231
|
+
passwordStdin: options.newPasswordStdin
|
|
232
|
+
};
|
|
233
|
+
const nextPassword = await resolvePasswordConfirmed(newPasswordOptions, 'New keystore password');
|
|
234
|
+
if (nextPassword.isFailure()) {
|
|
235
|
+
console.error(`Error: ${nextPassword.message}`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
const changed = await (0, keystore_1.changeKeystorePassword)(options.keystore, currentPassword.value, nextPassword.value);
|
|
239
|
+
if (changed.isFailure()) {
|
|
240
|
+
console.error(`Error: ${changed.message}`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
this._program
|
|
245
|
+
.command('put [name]')
|
|
246
|
+
.description('Store a secret in the keystore from stdin, a file, or interactive prompts')
|
|
247
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
248
|
+
.option('--password-env <name>', 'Environment variable to read the password from')
|
|
249
|
+
.option('--password-file <path>', 'Read the password from a file')
|
|
250
|
+
.option('--password-stdin', 'Read the password from stdin', false)
|
|
251
|
+
.option('--name <name>', 'Secret name')
|
|
252
|
+
.option('--stdin', 'Read the secret from stdin', false)
|
|
253
|
+
.option('--file <path>', 'Read the secret from a file')
|
|
254
|
+
.option('--description <text>', 'Optional secret description')
|
|
255
|
+
.option('--replace', 'Replace an existing secret', false)
|
|
256
|
+
.action(async (positionalName, options) => {
|
|
257
|
+
const name = await resolveSecretName(positionalName, options);
|
|
258
|
+
if (name.isFailure()) {
|
|
259
|
+
console.error(`Error: ${name.message}`);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
const password = await resolvePassword(options, 'Keystore password');
|
|
263
|
+
if (password.isFailure()) {
|
|
264
|
+
console.error(`Error: ${password.message}`);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
const secret = await resolveSecretValue(options);
|
|
268
|
+
if (secret.isFailure()) {
|
|
269
|
+
console.error(`Error: ${secret.message}`);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
}
|
|
272
|
+
const stored = await (0, keystore_1.storeSecret)(options.keystore, password.value, name.value, secret.value, {
|
|
273
|
+
description: options.description,
|
|
274
|
+
replace: options.replace
|
|
275
|
+
});
|
|
276
|
+
if (stored.isFailure()) {
|
|
277
|
+
console.error(`Error: ${stored.message}`);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
this._program
|
|
282
|
+
.command('get <name>')
|
|
283
|
+
.description('Read a secret from the keystore')
|
|
284
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
285
|
+
.option('--password-env <name>', 'Environment variable to read the password from')
|
|
286
|
+
.option('--password-file <path>', 'Read the password from a file')
|
|
287
|
+
.option('--password-stdin', 'Read the password from stdin', false)
|
|
288
|
+
.option('--clipboard', 'Copy the secret to the clipboard', false)
|
|
289
|
+
.action(async (name, options) => {
|
|
290
|
+
const password = await resolvePassword(options, 'Keystore password');
|
|
291
|
+
if (password.isFailure()) {
|
|
292
|
+
console.error(`Error: ${password.message}`);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
const secret = await (0, keystore_1.readSecret)(options.keystore, password.value, name);
|
|
296
|
+
if (secret.isFailure()) {
|
|
297
|
+
console.error(`Error: ${secret.message}`);
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
if (options.clipboard) {
|
|
301
|
+
const copied = await (0, io_1.copyTextToClipboard)(secret.value);
|
|
302
|
+
if (copied.isFailure()) {
|
|
303
|
+
console.error(`Error: ${copied.message}`);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
console.log(secret.value);
|
|
309
|
+
});
|
|
310
|
+
this._program
|
|
311
|
+
.command('list')
|
|
312
|
+
.description('List secrets in the keystore')
|
|
313
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
314
|
+
.option('--password-env <name>', 'Environment variable to read the password from')
|
|
315
|
+
.option('--password-file <path>', 'Read the password from a file')
|
|
316
|
+
.option('--password-stdin', 'Read the password from stdin', false)
|
|
317
|
+
.action(async (options) => {
|
|
318
|
+
const password = await resolvePassword(options, 'Keystore password');
|
|
319
|
+
if (password.isFailure()) {
|
|
320
|
+
console.error(`Error: ${password.message}`);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
const names = await (0, keystore_1.listSecrets)(options.keystore, password.value);
|
|
324
|
+
if (names.isFailure()) {
|
|
325
|
+
console.error(`Error: ${names.message}`);
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
for (const name of names.value) {
|
|
329
|
+
console.log(name);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
this._program
|
|
333
|
+
.command('remove <name>')
|
|
334
|
+
.description('Remove a secret from the keystore')
|
|
335
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
336
|
+
.option('--password-env <name>', 'Environment variable to read the password from')
|
|
337
|
+
.option('--password-file <path>', 'Read the password from a file')
|
|
338
|
+
.option('--password-stdin', 'Read the password from stdin', false)
|
|
339
|
+
.action(async (name, options) => {
|
|
340
|
+
const password = await resolvePassword(options, 'Keystore password');
|
|
341
|
+
if (password.isFailure()) {
|
|
342
|
+
console.error(`Error: ${password.message}`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
const removed = await (0, keystore_1.removeSecret)(options.keystore, password.value, name);
|
|
346
|
+
if (removed.isFailure()) {
|
|
347
|
+
console.error(`Error: ${removed.message}`);
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
this._program
|
|
352
|
+
.command('export')
|
|
353
|
+
.description('Render a shell template using secrets from the keystore')
|
|
354
|
+
.option('--keystore <path>', 'Keystore file path', (0, io_1.defaultKeystorePath)())
|
|
355
|
+
.option('--password-env <name>', 'Environment variable to read the password from')
|
|
356
|
+
.option('--password-file <path>', 'Read the password from a file')
|
|
357
|
+
.option('--password-stdin', 'Read the password from stdin', false)
|
|
358
|
+
.option('--template-file <path>', 'Read the shell template from a file')
|
|
359
|
+
.option('--template-string <text>', 'Use the supplied shell template string')
|
|
360
|
+
.option('--clipboard', 'Copy the rendered output to the clipboard', false)
|
|
361
|
+
.option('--persist-missing', 'Persist prompted secrets back to the keystore', false)
|
|
362
|
+
.action(async (options) => {
|
|
363
|
+
const password = await resolvePassword(options, 'Keystore password');
|
|
364
|
+
if (password.isFailure()) {
|
|
365
|
+
console.error(`Error: ${password.message}`);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
const template = await readTemplate(options);
|
|
369
|
+
if (template.isFailure()) {
|
|
370
|
+
console.error(`Error: ${template.message}`);
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
const opened = await (0, keystore_1.openKeystore)(options.keystore, password.value);
|
|
374
|
+
if (opened.isFailure()) {
|
|
375
|
+
console.error(`Error: ${opened.message}`);
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
const contextResult = await collectTemplateContext(opened.value.keystore, template.value);
|
|
379
|
+
if (contextResult.isFailure()) {
|
|
380
|
+
console.error(`Error: ${contextResult.message}`);
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
const rendered = (0, template_1.renderShellTemplate)(template.value, contextResult.value.context);
|
|
384
|
+
if (rendered.isFailure()) {
|
|
385
|
+
console.error(`Error: ${rendered.message}`);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
if (options.persistMissing && contextResult.value.missing.length > 0) {
|
|
389
|
+
for (const [name, value] of contextResult.value.missing) {
|
|
390
|
+
const stored = await opened.value.keystore.importApiKey(name, value, { replace: true });
|
|
391
|
+
if (stored.isFailure()) {
|
|
392
|
+
console.error(`Error: Failed to persist missing secret '${name}': ${stored.message}`);
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const saved = await opened.value.keystore.save(password.value);
|
|
397
|
+
if (saved.isFailure()) {
|
|
398
|
+
console.error(`Error: ${saved.message}`);
|
|
399
|
+
process.exit(1);
|
|
400
|
+
}
|
|
401
|
+
const persisted = await (0, keystore_1.saveKeystoreFile)(opened.value.path, saved.value);
|
|
402
|
+
if (persisted.isFailure()) {
|
|
403
|
+
console.error(`Error: ${persisted.message}`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (options.clipboard) {
|
|
408
|
+
const copied = await (0, io_1.copyTextToClipboard)(rendered.value);
|
|
409
|
+
if (copied.isFailure()) {
|
|
410
|
+
console.error(`Error: ${copied.message}`);
|
|
411
|
+
process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
console.log(rendered.value);
|
|
416
|
+
});
|
|
417
|
+
this._program
|
|
418
|
+
.command('session')
|
|
419
|
+
.description('Prompt for a password and emit a shell export statement')
|
|
420
|
+
.option('--var <name>', 'Environment variable name to emit', 'FGV_KS_PASSWORD')
|
|
421
|
+
.option('--clipboard', 'Copy the export statement to the clipboard', false)
|
|
422
|
+
.action(async (options) => {
|
|
423
|
+
var _a;
|
|
424
|
+
const varName = (_a = options.var) !== null && _a !== void 0 ? _a : 'FGV_KS_PASSWORD';
|
|
425
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(varName)) {
|
|
426
|
+
console.error(`Error: '--var' value '${varName}' is not a valid shell identifier`);
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
const password = await (0, io_1.promptHidden)('Keystore password: ');
|
|
430
|
+
if (password.isFailure()) {
|
|
431
|
+
console.error(`Error: ${password.message}`);
|
|
432
|
+
process.exit(1);
|
|
433
|
+
}
|
|
434
|
+
const output = `export ${varName}=${(0, template_1.shellQuote)(password.value)}`;
|
|
435
|
+
if (options.clipboard) {
|
|
436
|
+
const copied = await (0, io_1.copyTextToClipboard)(output);
|
|
437
|
+
if (copied.isFailure()) {
|
|
438
|
+
console.error(`Error: ${copied.message}`);
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
console.log(output);
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
exports.KsCli = KsCli;
|
|
448
|
+
//# sourceMappingURL=app.js.map
|
package/lib/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command } from 'commander';\nimport pkg from '../package.json';\n\nimport { CryptoUtils } from '@fgv/ts-extras';\nimport { Result, fail, succeed } from '@fgv/ts-utils';\n\nimport {\n copyTextToClipboard,\n defaultKeystorePath,\n promptHidden,\n promptVisible,\n readAllFromStdin,\n readTextFile,\n resolvePath\n} from './io';\nimport { getHelpText } from './help';\nimport {\n changeKeystorePassword,\n createKeystore,\n listSecrets,\n readSecret,\n openKeystore,\n removeSecret,\n saveKeystoreFile,\n storeSecret\n} from './keystore';\nimport { extractTemplateVariables, renderShellTemplate, shellQuote } from './template';\n\ninterface IKeystoreCommandOptions {\n keystore?: string;\n passwordEnv?: string;\n passwordFile?: string;\n passwordStdin?: boolean;\n}\n\ninterface ISecretValueOptions {\n stdin?: boolean;\n file?: string;\n}\n\ninterface IPutCommandOptions extends IKeystoreCommandOptions, ISecretValueOptions {\n name?: string;\n description?: string;\n replace?: boolean;\n}\n\ninterface IGetCommandOptions extends IKeystoreCommandOptions {\n clipboard?: boolean;\n}\n\ninterface IExportCommandOptions extends IKeystoreCommandOptions {\n templateFile?: string;\n templateString?: string;\n clipboard?: boolean;\n persistMissing?: boolean;\n}\n\ninterface IPasswordChangeOptions extends IKeystoreCommandOptions {\n newPasswordEnv?: string;\n newPasswordFile?: string;\n newPasswordStdin?: boolean;\n}\n\nfunction stripTrailingNewline(value: string): string {\n return value.replace(/\\r?\\n$/, '');\n}\n\nfunction hasExplicitPasswordSource(options: IKeystoreCommandOptions | IPasswordChangeOptions): boolean {\n return Boolean(options.passwordEnv || options.passwordFile || options.passwordStdin);\n}\n\nasync function readPasswordFromSource(\n options: IKeystoreCommandOptions | IPasswordChangeOptions\n): Promise<Result<string>> {\n if (options.passwordFile) {\n const fileResult = await readTextFile(options.passwordFile);\n if (fileResult.isFailure()) {\n return fail(fileResult.message);\n }\n return succeed(stripTrailingNewline(fileResult.value));\n }\n\n if (options.passwordStdin) {\n const stdinResult = await readAllFromStdin();\n if (stdinResult.isFailure()) {\n return fail(stdinResult.message);\n }\n return succeed(stripTrailingNewline(stdinResult.value));\n }\n\n if (options.passwordEnv) {\n const envValue = process.env[options.passwordEnv];\n if (envValue === undefined || envValue.length === 0) {\n return fail(`Environment variable '${options.passwordEnv}' is not set`);\n }\n return succeed(envValue);\n }\n\n const defaultEnv = process.env.FGV_KS_PASSWORD ?? process.env.KS_PASSWORD;\n if (defaultEnv !== undefined && defaultEnv.length > 0) {\n return succeed(defaultEnv);\n }\n\n return fail('Password not provided');\n}\n\nasync function resolvePassword(\n options: IKeystoreCommandOptions | IPasswordChangeOptions,\n label: string\n): Promise<Result<string>> {\n const source = await readPasswordFromSource(options);\n if (source.isSuccess()) {\n return source;\n }\n\n // If an explicit source was configured and failed, surface the error rather than prompting\n if (hasExplicitPasswordSource(options)) {\n return source;\n }\n\n const prompted = await promptHidden(`${label}: `);\n if (prompted.isFailure()) {\n return fail(prompted.message);\n }\n\n return succeed(prompted.value);\n}\n\nasync function resolveSecretName(\n positionalName: string | undefined,\n options: IPutCommandOptions\n): Promise<Result<string>> {\n if (options.name !== undefined && options.name.length > 0) {\n return succeed(options.name);\n }\n\n if (positionalName !== undefined && positionalName.length > 0) {\n return succeed(positionalName);\n }\n\n const prompted = await promptVisible('Secret name: ');\n if (prompted.isFailure()) {\n return fail(prompted.message);\n }\n\n if (prompted.value.length === 0) {\n return fail('Secret name cannot be empty');\n }\n\n return succeed(prompted.value);\n}\n\nasync function resolvePasswordConfirmed(\n options: IKeystoreCommandOptions | IPasswordChangeOptions,\n label: string\n): Promise<Result<string>> {\n // Only skip confirmation when password comes from an explicit non-interactive source.\n // Ambient env vars (FGV_KS_PASSWORD/KS_PASSWORD) are for reading the current password\n // and must not silently bypass confirmation when setting a new one.\n if (hasExplicitPasswordSource(options)) {\n return resolvePassword(options, label);\n }\n\n const first = await promptHidden(`${label}: `);\n if (first.isFailure()) {\n return fail(first.message);\n }\n\n const second = await promptHidden(`${label} (confirm): `);\n if (second.isFailure()) {\n return fail(second.message);\n }\n\n if (first.value !== second.value) {\n return fail('Passwords do not match');\n }\n\n return succeed(first.value);\n}\n\nasync function resolveSecretValue(options: ISecretValueOptions): Promise<Result<string>> {\n if (options.file && options.stdin) {\n return fail('Use either --file or --stdin, not both');\n }\n\n if (options.file) {\n const fileResult = await readTextFile(options.file);\n if (fileResult.isFailure()) {\n return fail(fileResult.message);\n }\n return succeed(stripTrailingNewline(fileResult.value));\n }\n\n if (options.stdin) {\n const stdinResult = await readAllFromStdin();\n if (stdinResult.isFailure()) {\n return fail(stdinResult.message);\n }\n return succeed(stripTrailingNewline(stdinResult.value));\n }\n\n const prompted = await promptHidden('Secret value: ');\n if (prompted.isFailure()) {\n return fail(prompted.message);\n }\n\n return succeed(prompted.value);\n}\n\nasync function readTemplate(\n options: Pick<IExportCommandOptions, 'templateFile' | 'templateString'>\n): Promise<Result<string>> {\n if (options.templateFile && options.templateString) {\n return fail('Use either --template-file or --template-string, not both');\n }\n\n if (options.templateFile) {\n const fileResult = await readTextFile(resolvePath(options.templateFile));\n if (fileResult.isFailure()) {\n return fail(fileResult.message);\n }\n return succeed(fileResult.value);\n }\n\n if (options.templateString !== undefined) {\n return succeed(options.templateString);\n }\n\n return fail('Specify either --template-file or --template-string');\n}\n\ninterface ITemplateContextResult {\n readonly context: Record<string, string>;\n readonly missing: readonly [string, string][];\n}\n\nasync function collectTemplateContext(\n keystore: CryptoUtils.KeyStore.KeyStore,\n template: string\n): Promise<Result<ITemplateContextResult>> {\n const variablesResult = extractTemplateVariables(template);\n if (variablesResult.isFailure()) {\n return fail(variablesResult.message);\n }\n\n const secretListResult = keystore.listSecrets();\n if (secretListResult.isFailure()) {\n return fail(`Failed to list secrets: ${secretListResult.message}`);\n }\n const knownSecrets = new Set(secretListResult.value);\n\n const context = Object.create(null) as Record<string, string>;\n const missing: Array<[string, string]> = [];\n\n for (const variable of variablesResult.value) {\n const secretResult = keystore.getApiKey(variable);\n if (secretResult.isSuccess()) {\n context[variable] = secretResult.value;\n continue;\n }\n\n if (knownSecrets.has(variable)) {\n return fail(`Secret '${variable}' exists but is not an API key: ${secretResult.message}`);\n }\n\n const promptResult = await promptHidden(`Secret '${variable}' is missing. Enter value: `);\n if (promptResult.isFailure()) {\n return fail(promptResult.message);\n }\n\n context[variable] = promptResult.value;\n missing.push([variable, promptResult.value]);\n }\n\n return succeed({ context, missing });\n}\n\nexport class KsCli {\n private readonly _program: Command;\n\n public constructor() {\n this._program = new Command();\n this._setupCommands();\n }\n\n public async run(argv: string[]): Promise<void> {\n await this._program.parseAsync(argv);\n }\n\n private _setupCommands(): void {\n this._program.name('ks').description('Manage ts-extras keystore files').version(pkg.version);\n this._program.addHelpCommand(false);\n\n this._program\n .command('help [topic]')\n .description('Show overview, commands, password, or template help')\n .action((topic: string | undefined) => {\n const help = getHelpText(topic, this._program);\n if (help.isFailure()) {\n console.error(`Error: ${help.message}`);\n process.exit(1);\n }\n\n console.log(help.value);\n });\n\n this._program\n .command('init')\n .description('Initialize a new keystore')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the password from')\n .option('--password-file <path>', 'Read the password from a file')\n .option('--password-stdin', 'Read the password from stdin', false)\n .action(async (options: IKeystoreCommandOptions) => {\n const password = await resolvePasswordConfirmed(options, 'New keystore password');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const created = await createKeystore(options.keystore, password.value);\n if (created.isFailure()) {\n console.error(`Error: ${created.message}`);\n process.exit(1);\n }\n });\n\n this._program\n .command('password')\n .description('Change the keystore password')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the current password from')\n .option('--password-file <path>', 'Read the current password from a file')\n .option('--password-stdin', 'Read the current password from stdin', false)\n .option('--new-password-env <name>', 'Environment variable to read the new password from')\n .option('--new-password-file <path>', 'Read the new password from a file')\n .option('--new-password-stdin', 'Read the new password from stdin', false)\n .action(async (options: IPasswordChangeOptions) => {\n const currentPassword = await resolvePassword(options, 'Current keystore password');\n if (currentPassword.isFailure()) {\n console.error(`Error: ${currentPassword.message}`);\n process.exit(1);\n }\n\n const newPasswordOptions: IPasswordChangeOptions = {\n keystore: options.keystore,\n passwordEnv: options.newPasswordEnv,\n passwordFile: options.newPasswordFile,\n passwordStdin: options.newPasswordStdin\n };\n const nextPassword = await resolvePasswordConfirmed(newPasswordOptions, 'New keystore password');\n if (nextPassword.isFailure()) {\n console.error(`Error: ${nextPassword.message}`);\n process.exit(1);\n }\n\n const changed = await changeKeystorePassword(\n options.keystore,\n currentPassword.value,\n nextPassword.value\n );\n if (changed.isFailure()) {\n console.error(`Error: ${changed.message}`);\n process.exit(1);\n }\n });\n\n this._program\n .command('put [name]')\n .description('Store a secret in the keystore from stdin, a file, or interactive prompts')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the password from')\n .option('--password-file <path>', 'Read the password from a file')\n .option('--password-stdin', 'Read the password from stdin', false)\n .option('--name <name>', 'Secret name')\n .option('--stdin', 'Read the secret from stdin', false)\n .option('--file <path>', 'Read the secret from a file')\n .option('--description <text>', 'Optional secret description')\n .option('--replace', 'Replace an existing secret', false)\n .action(async (positionalName: string | undefined, options: IPutCommandOptions) => {\n const name = await resolveSecretName(positionalName, options);\n if (name.isFailure()) {\n console.error(`Error: ${name.message}`);\n process.exit(1);\n }\n\n const password = await resolvePassword(options, 'Keystore password');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const secret = await resolveSecretValue(options);\n if (secret.isFailure()) {\n console.error(`Error: ${secret.message}`);\n process.exit(1);\n }\n\n const stored = await storeSecret(options.keystore, password.value, name.value, secret.value, {\n description: options.description,\n replace: options.replace\n });\n if (stored.isFailure()) {\n console.error(`Error: ${stored.message}`);\n process.exit(1);\n }\n });\n\n this._program\n .command('get <name>')\n .description('Read a secret from the keystore')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the password from')\n .option('--password-file <path>', 'Read the password from a file')\n .option('--password-stdin', 'Read the password from stdin', false)\n .option('--clipboard', 'Copy the secret to the clipboard', false)\n .action(async (name: string, options: IGetCommandOptions) => {\n const password = await resolvePassword(options, 'Keystore password');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const secret = await readSecret(options.keystore, password.value, name);\n if (secret.isFailure()) {\n console.error(`Error: ${secret.message}`);\n process.exit(1);\n }\n\n if (options.clipboard) {\n const copied = await copyTextToClipboard(secret.value);\n if (copied.isFailure()) {\n console.error(`Error: ${copied.message}`);\n process.exit(1);\n }\n return;\n }\n\n console.log(secret.value);\n });\n\n this._program\n .command('list')\n .description('List secrets in the keystore')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the password from')\n .option('--password-file <path>', 'Read the password from a file')\n .option('--password-stdin', 'Read the password from stdin', false)\n .action(async (options: IKeystoreCommandOptions) => {\n const password = await resolvePassword(options, 'Keystore password');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const names = await listSecrets(options.keystore, password.value);\n if (names.isFailure()) {\n console.error(`Error: ${names.message}`);\n process.exit(1);\n }\n\n for (const name of names.value) {\n console.log(name);\n }\n });\n\n this._program\n .command('remove <name>')\n .description('Remove a secret from the keystore')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the password from')\n .option('--password-file <path>', 'Read the password from a file')\n .option('--password-stdin', 'Read the password from stdin', false)\n .action(async (name: string, options: IKeystoreCommandOptions) => {\n const password = await resolvePassword(options, 'Keystore password');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const removed = await removeSecret(options.keystore, password.value, name);\n if (removed.isFailure()) {\n console.error(`Error: ${removed.message}`);\n process.exit(1);\n }\n });\n\n this._program\n .command('export')\n .description('Render a shell template using secrets from the keystore')\n .option('--keystore <path>', 'Keystore file path', defaultKeystorePath())\n .option('--password-env <name>', 'Environment variable to read the password from')\n .option('--password-file <path>', 'Read the password from a file')\n .option('--password-stdin', 'Read the password from stdin', false)\n .option('--template-file <path>', 'Read the shell template from a file')\n .option('--template-string <text>', 'Use the supplied shell template string')\n .option('--clipboard', 'Copy the rendered output to the clipboard', false)\n .option('--persist-missing', 'Persist prompted secrets back to the keystore', false)\n .action(async (options: IExportCommandOptions) => {\n const password = await resolvePassword(options, 'Keystore password');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const template = await readTemplate(options);\n if (template.isFailure()) {\n console.error(`Error: ${template.message}`);\n process.exit(1);\n }\n\n const opened = await openKeystore(options.keystore, password.value);\n if (opened.isFailure()) {\n console.error(`Error: ${opened.message}`);\n process.exit(1);\n }\n\n const contextResult = await collectTemplateContext(opened.value.keystore, template.value);\n if (contextResult.isFailure()) {\n console.error(`Error: ${contextResult.message}`);\n process.exit(1);\n }\n\n const rendered = renderShellTemplate(template.value, contextResult.value.context);\n if (rendered.isFailure()) {\n console.error(`Error: ${rendered.message}`);\n process.exit(1);\n }\n\n if (options.persistMissing && contextResult.value.missing.length > 0) {\n for (const [name, value] of contextResult.value.missing) {\n const stored = await opened.value.keystore.importApiKey(name, value, { replace: true });\n if (stored.isFailure()) {\n console.error(`Error: Failed to persist missing secret '${name}': ${stored.message}`);\n process.exit(1);\n }\n }\n\n const saved = await opened.value.keystore.save(password.value);\n if (saved.isFailure()) {\n console.error(`Error: ${saved.message}`);\n process.exit(1);\n }\n\n const persisted = await saveKeystoreFile(opened.value.path, saved.value);\n if (persisted.isFailure()) {\n console.error(`Error: ${persisted.message}`);\n process.exit(1);\n }\n }\n\n if (options.clipboard) {\n const copied = await copyTextToClipboard(rendered.value);\n if (copied.isFailure()) {\n console.error(`Error: ${copied.message}`);\n process.exit(1);\n }\n return;\n }\n\n console.log(rendered.value);\n });\n\n this._program\n .command('session')\n .description('Prompt for a password and emit a shell export statement')\n .option('--var <name>', 'Environment variable name to emit', 'FGV_KS_PASSWORD')\n .option('--clipboard', 'Copy the export statement to the clipboard', false)\n .action(async (options: { var?: string; clipboard?: boolean }) => {\n const varName = options.var ?? 'FGV_KS_PASSWORD';\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(varName)) {\n console.error(`Error: '--var' value '${varName}' is not a valid shell identifier`);\n process.exit(1);\n }\n\n const password = await promptHidden('Keystore password: ');\n if (password.isFailure()) {\n console.error(`Error: ${password.message}`);\n process.exit(1);\n }\n\n const output = `export ${varName}=${shellQuote(password.value)}`;\n if (options.clipboard) {\n const copied = await copyTextToClipboard(output);\n if (copied.isFailure()) {\n console.error(`Error: ${copied.message}`);\n process.exit(1);\n }\n return;\n }\n\n console.log(output);\n });\n }\n}\n"]}
|
package/lib/cli.d.ts
ADDED
package/lib/cli.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC"}
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KsCli = void 0;
|
|
4
|
+
var app_1 = require("./app");
|
|
5
|
+
Object.defineProperty(exports, "KsCli", { enumerable: true, get: function () { return app_1.KsCli; } });
|
|
6
|
+
//# sourceMappingURL=cli.js.map
|
package/lib/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAAA,6BAA8B;AAArB,4FAAA,KAAK,OAAA","sourcesContent":["export { KsCli } from './app';\n"]}
|
package/lib/help.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Result } from '@fgv/ts-utils';
|
|
3
|
+
export type HelpTopic = 'overview' | 'commands' | 'password' | 'template';
|
|
4
|
+
export declare function getHelpText(topic?: string | undefined, program?: Command): Result<string>;
|
|
5
|
+
//# sourceMappingURL=help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAQ,MAAM,EAAW,MAAM,eAAe,CAAC;AAEtD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAkF1E,wBAAgB,WAAW,CAAC,KAAK,GAAE,MAAM,GAAG,SAAqB,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CA6BpG"}
|