vexp-cli 2.7.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ import { Writable } from "node:stream";
2
+ import * as readline from "node:readline";
3
+ export function mutableOutput(base) {
4
+ let muted = false;
5
+ const stream = new Writable({
6
+ write(chunk, enc, cb) {
7
+ if (!muted)
8
+ base.write(chunk);
9
+ cb();
10
+ },
11
+ });
12
+ // readline consults these to decide how to render; without them it treats
13
+ // the wrapper as a dumb pipe and the prompt never appears.
14
+ Object.defineProperty(stream, "isTTY", { get: () => base.isTTY === true });
15
+ Object.defineProperty(stream, "columns", { get: () => base.columns });
16
+ Object.defineProperty(stream, "rows", { get: () => base.rows });
17
+ return { stream, setMuted: (m) => { muted = m; } };
18
+ }
19
+ /** Prompt for a secret on a fresh readline interface. */
20
+ export async function promptSecret(promptText, io) {
21
+ const { input, output, isTTY } = io;
22
+ if (!isTTY) {
23
+ // Piped: read the line with terminal mode OFF so readline cannot echo it.
24
+ const rl = readline.createInterface({ input, terminal: false });
25
+ output.write(promptText);
26
+ const line = await new Promise((resolve) => {
27
+ let settled = false;
28
+ rl.once("line", (l) => { settled = true; resolve(l); });
29
+ rl.once("close", () => { if (!settled)
30
+ resolve(""); });
31
+ });
32
+ rl.close();
33
+ output.write("\n");
34
+ return line;
35
+ }
36
+ const ctl = mutableOutput(output);
37
+ const rl = readline.createInterface({ input, output: ctl.stream, terminal: true });
38
+ try {
39
+ return await askSecretOn(rl, promptText, ctl, output);
40
+ }
41
+ finally {
42
+ rl.close();
43
+ }
44
+ }
45
+ /**
46
+ * Prompt for a secret on an EXISTING interface — the interactive shell owns
47
+ * one readline for the whole session and closing it exits the process, so the
48
+ * shell mutes its own output instead of building a second one.
49
+ *
50
+ * The interface must have been created over `ctl.stream`.
51
+ */
52
+ export async function askSecretOn(rl, promptText, ctl, output) {
53
+ const answer = await new Promise((resolve) => {
54
+ // question() writes the prompt synchronously, so muting immediately after
55
+ // hides the keystrokes and nothing else.
56
+ rl.question(promptText, (a) => resolve(a));
57
+ ctl.setMuted(true);
58
+ });
59
+ ctl.setMuted(false);
60
+ output.write("\n");
61
+ return answer;
62
+ }