diff --git a/README.md b/README.md index 7362258..c7f8253 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ Register domains, manage DNS, and run your entire domain portfolio — without l --- +![Registering a domain with namecom](docs/demo.gif) + +*Recorded against the sandbox API with [vhs](https://github.com/charmbracelet/vhs) — see [`docs/demo.tape`](docs/demo.tape) for the script.* + ``` $ namecom status @@ -209,7 +213,15 @@ namecom domain list --quiet # one domain per line, for scripting ## Configuration -Credentials live at `~/.config/namecom/config.yaml` after `namecom auth login`. Multiple profiles are supported for managing separate accounts: +Credentials are written by `namecom auth login` to your platform's user config directory: + +| Platform | Location | +|---|---| +| macOS | `~/Library/Application Support/namecom/config.yaml` | +| Linux | `$XDG_CONFIG_HOME/namecom/config.yaml`, or `~/.config/namecom/config.yaml` | +| Windows | `%AppData%\namecom\config.yaml` | + +`namecom auth status` prints the path in use. An older `~/.namecom/config.yaml` is still read if the current location has no config, and `NAMECOM_CONFIG` overrides both. Multiple profiles are supported for managing separate accounts: ```bash namecom auth login --profile work @@ -231,7 +243,7 @@ export NAMECOM_USERNAME=yourname export NAMECOM_TOKEN=yourtoken export NAMECOM_SANDBOX=true # target sandbox API export NAMECOM_PROFILE=staging # select a profile -export NAMECOM_CONFIG=~/.config/namecom/ci.yaml # alternate config file +export NAMECOM_CONFIG=~/namecom-ci.yaml # use this file instead of the default namecom domain list ``` diff --git a/docs/demo.gif b/docs/demo.gif new file mode 100644 index 0000000..77920fc Binary files /dev/null and b/docs/demo.gif differ diff --git a/docs/demo.tape b/docs/demo.tape new file mode 100644 index 0000000..e3962b6 --- /dev/null +++ b/docs/demo.tape @@ -0,0 +1,101 @@ +# Demo recording script for the namecom CLI. To record it: install vhs +# (https://github.com/charmbracelet/vhs) plus its ffmpeg/ttyd runtime deps, +# then from the repository root: +# +# make build && vhs docs/demo.tape +# +# `make build` matters. The recorded shell puts the repository first on PATH +# so `namecom` resolves to ./namecom, the binary just built from this working +# tree. Without that it resolves to whatever `namecom` is installed system-wide +# — on a machine with a Homebrew install, that is a released build, and the +# demo would show an older version's output while looking current. Note +# `make install` does not help: `go install` names the binary after the module +# path, so it lands as `namecom-cli`, not `namecom`. +# +# THIS RECORDS AGAINST THE SANDBOX (api.dev.name.com), never production. +# Registering a domain for real spends real money. The tape sets no --profile +# and no NAMECOM_PROFILE: it records whatever the ACTIVE profile is, so before +# recording, confirm that profile is a sandbox one: +# +# namecom auth status # Environment must read "sandbox" +# +# That check is deliberately not a step in the tape, because `auth status` +# prints the account username, which does not belong in a GIF on a README. +# Set sandbox credentials up once with: +# +# namecom auth login --profile sandbox --sandbox +# +# Log in BEFORE recording, never during — the token prompt must not land in a +# frame. +# +# RE-RECORDING: the registration is real within the sandbox account, so once +# this succeeds the domain below is taken and the next run stops at "not +# available". Pick a fresh name, verify it first with `namecom domain check`, +# and update every occurrence in this file. +# +# Keep this in sync: re-run it whenever a change touches what these commands +# print (flags, output formatting, hints, prompts, sample values). + +Output docs/demo.gif + +Require namecom + +Env NAMECOM_ICONS "1" + +Set Shell "bash" +Set FontSize 20 +Set Width 1200 +Set Height 640 +Set Theme "Dracula" +Set TypingSpeed 40ms +Set Padding 20 + +# Hidden setup. Neither of these belongs on screen: +# - a bare prompt, because the default bash prompt puts the recording +# machine's hostname and working directory in every frame +# - the repository first on PATH, so `namecom` is ./namecom from this tree +Hide +Type `export PS1="$ "` +Enter +Type `export PATH="$PWD:$PATH"` +Enter +Type "clear" +Enter +Show + +Sleep 600ms + +# The whole demo is one command. `domain check` prints availability and price, +# then — in an interactive terminal — offers to register it inline, so there is +# no second command to type. +# +# SLEEP BUDGET. The two sleeps that follow a keystroke-consuming prompt are +# sized against measured sandbox latency, not guessed: a keystroke sent while a +# prompt is still waiting gets eaten by the prompt instead of reaching the +# shell, which is exactly how an earlier take ended up running "amecom". +# Measured: domain check 0.46s, inline registration 2.86s, dns create 0.31s. +# The rest is reading time. Re-measure before shortening these further. +Type "namecom domain check driftwoodco.com" +Sleep 300ms +Enter + +# Availability table, then the "Register …?" confirm. 1.5s covers a 0.46s call. +Sleep 1500ms + +# Answer the confirm. huh renders Yes/No with No selected; "y" picks Yes. +Type "y" +Sleep 400ms +Enter + +# Registration plus its hints. 4.5s over a measured 2.86s — the tightest +# margin in the tape, and the one that breaks the recording if it is wrong. +Sleep 4500ms + +# Point the new domain somewhere. Nothing is typed after this, so the trailing +# sleep is purely for reading and can be trimmed freely. +Type "namecom dns create driftwoodco.com --type A --answer 1.2.3.4" +Sleep 300ms +Enter +Sleep 2s + +Sleep 1s diff --git a/internal/config/config.go b/internal/config/config.go index f55b1e4..02b2b13 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -73,9 +73,14 @@ type Credentials struct { // source. Callers in TTY mode may offer to run `namecom auth login`. var ErrNoCredentials = errors.New("no credentials configured") -// Path returns the config file path, honoring NAMECOM_CONFIG, then XDG -// (~/.config/namecom/config.yaml). The returned path is where new config is -// written; see resolveReadPath for read-time legacy fallback. +// Path returns the config file path, honoring NAMECOM_CONFIG, then the +// platform user config directory. That directory is NOT ~/.config everywhere: +// os.UserConfigDir gives ~/Library/Application Support on darwin, +// $XDG_CONFIG_HOME (or ~/.config) on unix, and %AppData% on windows. Saying +// "XDG" here previously read as a promise of ~/.config on every platform, +// which sent people looking for their credentials in a directory macOS never +// uses. The returned path is where new config is written; see resolveReadPath +// for the read-time legacy fallback. func Path() (string, error) { if p := os.Getenv("NAMECOM_CONFIG"); p != "" { return p, nil