feat(cli): add tinyforge terminal client
New zero-dependency Go CLI (cmd/cli) that drives the existing HTTP API: login/logout, apps list, deploy (synchronous, --timeout), logs (one-shot + -f SSE follow), and status. Caches a 24h JWT in ~/.tinyforge/config.json (0600, Chmod-enforced on overwrite); Bearer-header auth keeps the token out of server/proxy logs; no-echo password prompt (kernel32 on Windows, stty elsewhere). Server/token resolved via flags, TINYFORGE_URL/TINYFORGE_TOKEN env, or config. README CLI section + root-anchored .gitignore entries for the build output.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// enableEchoInput is the Windows console mode bit that echoes typed input.
|
||||
const enableEchoInput = 0x0004
|
||||
|
||||
// promptPassword reads a password from the console with echo disabled, using
|
||||
// kernel32 directly so no third-party dependency is needed. If the console
|
||||
// mode cannot be changed (e.g. piped stdin), it falls back to an echoed read.
|
||||
func promptPassword(label string) (string, error) {
|
||||
fmt.Fprint(os.Stderr, label)
|
||||
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
getConsoleMode := kernel32.NewProc("GetConsoleMode")
|
||||
setConsoleMode := kernel32.NewProc("SetConsoleMode")
|
||||
handle := syscall.Handle(os.Stdin.Fd())
|
||||
|
||||
var mode uint32
|
||||
echoDisabled := false
|
||||
if r, _, _ := getConsoleMode.Call(uintptr(handle), uintptr(unsafe.Pointer(&mode))); r != 0 {
|
||||
if ret, _, _ := setConsoleMode.Call(uintptr(handle), uintptr(mode&^enableEchoInput)); ret != 0 {
|
||||
echoDisabled = true
|
||||
defer setConsoleMode.Call(uintptr(handle), uintptr(mode))
|
||||
}
|
||||
}
|
||||
|
||||
line, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
if echoDisabled {
|
||||
fmt.Fprintln(os.Stderr) // the Enter keystroke was not echoed
|
||||
}
|
||||
if err != nil && line == "" {
|
||||
return "", fmt.Errorf("read password: %w", err)
|
||||
}
|
||||
return strings.TrimRight(line, "\r\n"), nil
|
||||
}
|
||||
Reference in New Issue
Block a user