@soulbatical/tetra-dev-toolkit 1.20.5 → 1.20.6

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.
File without changes
@@ -8,9 +8,10 @@
8
8
  */
9
9
 
10
10
  import { createClient } from '@supabase/supabase-js'
11
- import { readFileSync, writeFileSync, existsSync } from 'fs'
11
+ import { readFileSync, writeFileSync, existsSync, openSync, closeSync } from 'fs'
12
12
  import { join, basename, dirname, resolve } from 'path'
13
13
  import { createInterface } from 'readline'
14
+ import { execSync } from 'child_process'
14
15
  import { config as dotenvConfig } from 'dotenv'
15
16
  import chalk from 'chalk'
16
17
 
@@ -204,39 +205,36 @@ export async function refresh(url, key, refreshToken) {
204
205
  }
205
206
  }
206
207
 
207
- /** Prompt for input (password is hidden) */
208
+ /** Prompt for input (password is always hidden, works through npm/doppler pipes) */
208
209
  export function promptInput(question) {
209
- const rl = createInterface({ input: process.stdin, output: process.stdout })
210
- return new Promise((resolve) => {
211
- if (question.toLowerCase().includes('password')) {
210
+ const isPassword = question.toLowerCase().includes('password')
211
+
212
+ if (isPassword) {
213
+ // Read password from /dev/tty with echo disabled.
214
+ // This bypasses npm/doppler stdin piping that breaks setRawMode.
215
+ return new Promise((resolve) => {
212
216
  process.stdout.write(question)
213
- process.stdin.setRawMode(true)
214
- process.stdin.resume()
215
- process.stdin.setEncoding('utf8')
216
- let password = ''
217
- const onData = (char) => {
218
- if (char === '\n' || char === '\r') {
219
- process.stdin.setRawMode(false)
220
- process.stdin.removeListener('data', onData)
221
- console.log('')
222
- rl.close()
223
- resolve(password)
224
- } else if (char === '\u0003') {
225
- process.exit()
226
- } else if (char === '\u007F') {
227
- if (password.length > 0) {
228
- password = password.slice(0, -1)
229
- process.stdout.write('\b \b')
230
- }
231
- } else {
232
- password += char
233
- process.stdout.write('*')
234
- }
217
+ try {
218
+ // bash -c ensures stty works even in non-interactive shells
219
+ const password = execSync(
220
+ 'bash -c \'stty -echo </dev/tty; read -r pw </dev/tty; stty echo </dev/tty; echo "$pw"\'',
221
+ { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
222
+ ).replace(/\n$/, '')
223
+ console.log('') // newline after hidden input
224
+ resolve(password)
225
+ } catch {
226
+ // Fallback for non-unix systems: readline with warning
227
+ console.warn(chalk.yellow('\n⚠️ Cannot hide password input on this system'))
228
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
229
+ rl.question(' Password: ', (answer) => { rl.close(); resolve(answer) })
235
230
  }
236
- process.stdin.on('data', onData)
237
- } else {
238
- rl.question(question, (answer) => { rl.close(); resolve(answer) })
239
- }
231
+ })
232
+ }
233
+
234
+ // Non-password input: normal readline
235
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
236
+ return new Promise((resolve) => {
237
+ rl.question(question, (answer) => { rl.close(); resolve(answer) })
240
238
  })
241
239
  }
242
240
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulbatical/tetra-dev-toolkit",
3
- "version": "1.20.5",
3
+ "version": "1.20.6",
4
4
  "publishConfig": {
5
5
  "access": "restricted"
6
6
  },