From 6c01ac1c1bc91d7b839cb207c92f2a45627ee544 Mon Sep 17 00:00:00 2001 From: Harvmaster Date: Mon, 11 May 2026 10:41:41 +0000 Subject: [PATCH] Add currency settings, Settings service, and dialog to select fiat currency. Add support for non Official currencies like DOGE when using rates. --- src/cli/README.md | 18 +- src/cli/autocomplete/complete.ts | 11 +- src/cli/autocomplete/completions.ts | 5 + src/cli/autocomplete/scripts/bash.sh | 11 + src/cli/autocomplete/scripts/fish.fish | 1 + src/cli/autocomplete/scripts/zsh.zsh | 11 + src/cli/commands/index.ts | 1 + src/cli/commands/settings.ts | 131 ++++++++++++ src/cli/index.ts | 36 +++- src/services/app.ts | 14 +- src/services/rates.ts | 28 ++- src/services/settings.ts | 194 ++++++++++++++++++ .../components/CurrencySelectionDialog.tsx | 188 +++++++++++++++++ src/tui/components/VariableInputField.tsx | 2 +- src/tui/hooks/useSatoshisConversion.tsx | 37 +++- src/tui/screens/WalletState.tsx | 121 ++++++++++- .../action-wizard/steps/InputsStep.tsx | 2 +- .../action-wizard/steps/ReviewStep.tsx | 2 +- .../screens/invitations/InvitationScreen.tsx | 2 +- .../steps/InputsSelectStep.tsx | 2 +- .../steps/PreviewInvitationStep.tsx | 2 +- .../invitation-import/steps/ReviewStep.tsx | 2 +- src/utils/paths.ts | 11 +- src/utils/rates/base-rates.ts | 29 ++- src/utils/rates/rates-oracles.ts | 70 ++++++- tests/cli/commands/settings.test.ts | 83 ++++++++ tests/cli/rates-format.test.ts | 40 ++++ tests/cli/settings.test.ts | 96 +++++++++ 28 files changed, 1102 insertions(+), 48 deletions(-) create mode 100644 src/cli/commands/settings.ts create mode 100644 src/services/settings.ts create mode 100644 src/tui/components/CurrencySelectionDialog.tsx create mode 100644 tests/cli/commands/settings.test.ts create mode 100644 tests/cli/rates-format.test.ts create mode 100644 tests/cli/settings.test.ts diff --git a/src/cli/README.md b/src/cli/README.md index 9da17ef..cfcaeb7 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -15,7 +15,7 @@ Wallet state lives under **`~/.config/xo-cli/`** (XDG-style), so you can run com | ----------------------------- | ----------------------------------------------------------------------- | | `~/.config/xo-cli/mnemonics/` | Mnemonic files (`mnemonic-*`) | | `~/.config/xo-cli/data/` | Engine DB (`xo-wallet.db`) and invitation storage (`xo-invitations.db`) | -| `~/.config/xo-cli/.wallet` | Last-used mnemonic reference (so `-m` can be omitted) | +| `~/.config/xo-cli/.wallet` | JSON settings (`default-mnemonic`, `currency`) | **Local to your shell’s current directory:** template JSON paths, invitation JSON you create/import, and any path you pass explicitly (e.g. `-m /abs/path/to/file`). @@ -67,7 +67,10 @@ xo-cli mnemonic list ### Wallet Persistence -The first time you pass `-m `, that reference is saved to `~/.config/xo-cli/.wallet`. Later runs can omit `-m`. +The first time you pass `-m `, that reference is saved as +`default-mnemonic` in `~/.config/xo-cli/.wallet`. Later runs can omit `-m`. + +`currency` controls the fiat unit used when showing BCH/sats conversions in the TUI. Mnemonic resolution order: @@ -85,6 +88,7 @@ xo-cli resource list | Flag | Description | | ------------------------------ | --------------------------------------------------- | | `-m`, `--mnemonic-file ` | Mnemonic file (basename, cwd-relative, or absolute) | +| `--currency ` | Fiat display currency (e.g. `USD`, `AUD`) | | `-o`, `--output ` | Output filename (used by `mnemonic create`/`import`) | | `-v`, `--verbose` | Verbose output | | `-h`, `--help` | Help | @@ -126,6 +130,16 @@ xo-cli resource unreserve xo-cli resource unreserve-all ``` +### `settings` — Manage Persisted Settings + +```bash +xo-cli settings show +xo-cli settings get currency +xo-cli settings get default-mnemonic +xo-cli settings set currency AUD +xo-cli settings set default-mnemonic mnemonic-nuclear +``` + ### `receive` — Generate a Receiving Address ```bash diff --git a/src/cli/autocomplete/complete.ts b/src/cli/autocomplete/complete.ts index cd3bcdb..7e7e969 100644 --- a/src/cli/autocomplete/complete.ts +++ b/src/cli/autocomplete/complete.ts @@ -23,7 +23,7 @@ * 1 - Error (no output, fails silently for shell integration) */ -import { existsSync, readdirSync, readFileSync } from "node:fs"; +import { existsSync, readdirSync } from "node:fs"; import { join } from "node:path"; import { createHash } from "node:crypto"; @@ -34,6 +34,7 @@ import { } from "../../utils/paths.js"; import { loadMnemonic } from "../mnemonic.js"; import { Storage } from "../../services/storage.js"; +import { SettingsService } from "../../services/settings.js"; import { COMMAND_TREE } from "./completions.js"; // Lazy-loaded modules (only loaded when needed for dynamic completions) @@ -103,12 +104,8 @@ function listSubcommands(command: string, prefix?: string): void { */ function getCurrentMnemonic(): string | null { try { - const walletConfigPath = getWalletConfigPath(); - if (!existsSync(walletConfigPath)) { - return null; - } - - const mnemonicFile = readFileSync(walletConfigPath, "utf8").trim(); + const settings = new SettingsService(getWalletConfigPath()); + const mnemonicFile = settings.getDefaultMnemonic(); if (!mnemonicFile) { return null; } diff --git a/src/cli/autocomplete/completions.ts b/src/cli/autocomplete/completions.ts index 24fcb1f..01d1ebe 100644 --- a/src/cli/autocomplete/completions.ts +++ b/src/cli/autocomplete/completions.ts @@ -37,6 +37,7 @@ import { homedir } from "node:os"; * - template.ts: import, list, inspect, set-default * - invitation.ts: create, append, sign, broadcast, requirements, import, inspect, list * - resource.ts: list, unreserve, unreserve-all + * - settings.ts: show, get, set */ /** Subcommands for the mnemonic command */ @@ -56,6 +57,8 @@ const INVITATION_SUBS = [ ]; /** Subcommands for the resource command */ const RESOURCE_SUBS = ["list", "unreserve", "unreserve-all"]; +/** Subcommands for the settings command */ +const SETTINGS_SUBS = ["show", "get", "set"]; /** Subcommands for the completions command */ const COMPLETIONS_SUBS = ["bash", "zsh", "fish"]; @@ -65,6 +68,7 @@ export const COMMAND_TREE = { invitation: INVITATION_SUBS, receive: [], resource: RESOURCE_SUBS, + settings: SETTINGS_SUBS, help: [], completions: COMPLETIONS_SUBS, } as const; @@ -77,6 +81,7 @@ const GLOBAL_OPTIONS = [ "--verbose", "-m", "--mnemonic-file", + "--currency", "-o", "--output", ]; diff --git a/src/cli/autocomplete/scripts/bash.sh b/src/cli/autocomplete/scripts/bash.sh index 7c12ef4..45ad873 100644 --- a/src/cli/autocomplete/scripts/bash.sh +++ b/src/cli/autocomplete/scripts/bash.sh @@ -201,6 +201,17 @@ _{{FUNC_NAME}}_completions() { fi ;; + settings) + if [[ -z "${subcmd}" ]]; then + COMPREPLY=($(compgen -W "show get set" -- "${cur}")) + elif [[ "${subcmd}" == "get" || "${subcmd}" == "set" ]]; then + local pos=$((cword - subcmd_idx)) + if [[ $pos -eq 1 ]]; then + COMPREPLY=($(compgen -W "currency default-mnemonic" -- "${cur}")) + fi + fi + ;; + receive) # receive