{"_id":"@billy_mcdowell/mfx","name":"@billy_mcdowell/mfx","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@billy_mcdowell/mfx","version":"0.2.0","description":"Terminal-native market dashboard CLI (Ink + React)","license":"MIT","repository":{"type":"git","url":"git+https://github.com/billymcdowell/mfx.git"},"bugs":{"url":"https://github.com/billymcdowell/mfx/issues"},"homepage":"https://github.com/billymcdowell/mfx#readme","publishConfig":{"access":"public"},"bin":{"mfx":"dist/source/cli.js"},"type":"module","engines":{"node":">=22"},"scripts":{"build":"tsc && tsc-alias -p tsconfig.json -f","dev":"tsx watch source/cli.tsx","build:watch":"tsc --watch --preserveWatchOutput","test":"npm run build && ava","lint":"prettier --check . && xo","prepublishOnly":"npm run build","release":"npm run build && changeset publish","changeset":"changeset","version-packages":"changeset version"},"dependencies":{"cli-spinners":"^2.9.2","figlet":"^1.11.0","glob":"^13.0.6","ink":"^7.0.3","marked":"^18.0.3","meow":"^11.0.0","mnemonist":"^0.40.4","react":"^19.2.0","simple-ascii-chart":"^5.4.0","strip-ansi":"^7.2.0"},"devDependencies":{"@changesets/changelog-github":"^0.5.2","@changesets/cli":"^2.29.8","@sindresorhus/tsconfig":"^3.0.1","@types/react":"^19.0.32","@vdemedes/prettier-config":"^2.0.1","ava":"^5.2.0","chalk":"^5.2.0","eslint-config-xo-react":"^0.27.0","eslint-plugin-react":"^7.32.2","eslint-plugin-react-hooks":"^4.6.0","ink-testing-library":"^3.0.0","prettier":"^2.8.7","ts-node":"^10.9.1","tsc-alias":"^1.8.17","tsx":"^4.19.4","typescript":"^5.0.3","xo":"^0.53.1"},"ava":{"files":["test/**/*.mjs"],"extensions":{"js":true,"mjs":true},"nodeArguments":[]},"xo":{"extends":"xo-react","prettier":true,"rules":{"react/prop-types":"off","import/extensions":"off","import/no-named-as-default":"off","react/react-in-jsx-scope":"off","react/prefer-read-only-props":"off","react/function-component-definition":"off","react/hook-use-state":"off","react/state-in-constructor":"off","@typescript-eslint/consistent-type-definitions":"off","@typescript-eslint/member-ordering":"off","@typescript-eslint/no-empty-function":"off","@typescript-eslint/no-implicit-any-catch":"off","@typescript-eslint/no-floating-promises":"off","@typescript-eslint/no-unsafe-assignment":"off","@typescript-eslint/no-unsafe-call":"off","@typescript-eslint/prefer-nullish-coalescing":"off","@typescript-eslint/prefer-optional-chain":"off","@typescript-eslint/restrict-plus-operands":"off","@typescript-eslint/restrict-template-expressions":"off","react/boolean-prop-naming":"off","n/prefer-global/process":"off","n/prefer-global/buffer":"off","react/no-array-index-key":"off","react/no-unused-prop-types":"off","react/require-default-props":"off","no-bitwise":"off","no-new-func":"off","no-multi-assign":"off","func-names":"off","unicorn/no-array-callback-reference":"off","unicorn/prefer-spread":"off","unicorn/prefer-top-level-await":"off","unicorn/prevent-abbreviations":"off"},"overrides":[{"files":["**/*.ts","**/*.tsx"],"rules":{"@typescript-eslint/naming-convention":"off"}}]},"prettier":"@vdemedes/prettier-config","overrides":{"eslint-plugin-unicorn":"^52.0.0"},"_id":"@billy_mcdowell/mfx@0.2.0","gitHead":"a6606b52b77ea13c136159db8e7fca7373d0ba4a","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-Ka6ZAg/yHWzn5y+oFYUI4dzE3vrqC52Ut58bwxltPHLxkBxCf0YrDy4q72On46shEuxeydCCaqAmK6qeJnIzQg==","shasum":"a3a41824d840d859085540821792369ee2f9d49f","tarball":"https://registry.npmjs.org/@billy_mcdowell/mfx/-/mfx-0.2.0.tgz","fileCount":163,"unpackedSize":457199,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIExS9sSBSYOqB0P8IlBqBsXEhxFGg7nLgdh7pH1JYSL3AiBWY8w2gBRXDCnFV9P0ubuLNjYRxnQB2F5OncrA9l+fzg=="}]},"_npmUser":{"name":"billy_mcdowell","email":"wilgemcdowell@gmail.com"},"directories":{},"maintainers":[{"name":"billy_mcdowell","email":"wilgemcdowell@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mfx_0.2.0_1779369973588_0.8011220315117922"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-21T13:26:13.460Z","0.2.0":"2026-05-21T13:26:13.735Z","modified":"2026-05-21T13:26:13.899Z"},"maintainers":[{"name":"billy_mcdowell","email":"wilgemcdowell@gmail.com"}],"description":"Terminal-native market dashboard CLI (Ink + React)","homepage":"https://github.com/billymcdowell/mfx#readme","repository":{"type":"git","url":"git+https://github.com/billymcdowell/mfx.git"},"bugs":{"url":"https://github.com/billymcdowell/mfx/issues"},"license":"MIT","readme":"# MFX\n\n**MFX** is a terminal-native market dashboard: live-style commodity and forex quotes, market news, bookmarks, and a watchlist — all rendered in your shell with keyboard-driven navigation. It is a demo/prototype built to show how far you can push a rich product UI inside the terminal using React and [Ink](https://github.com/vadimdemedes/ink).\n\n## Screenshots\n\n### Login\n\n![MFX login screen](images/login.jpg)\n\nSign in with any email and any password (except the literal string `wrong`, which triggers a mock auth error). Session state is stored locally so you stay signed in between runs.\n\n### Prices\n\n![MFX prices list with sparklines](images/prices.jpg)\n\nBrowse commodities (gold, silver, oil, gas) and forex pairs with spot, bid/ask, 24h change, and inline sparklines. Filter by asset class, search symbols, star favorites into a watchlist, and refresh on demand.\n\n### Price detail\n\n![MFX price detail with chart](images/price.jpg)\n\nDrill into a single instrument for a larger ASCII chart, quote strip, and history context.\n\n### News\n\n![MFX market news feed](images/news.jpg)\n\nScroll a tagged news feed, open full articles, and save stories to bookmarks for later.\n\n## The idea\n\nMost trading and market tools assume a browser or desktop app. MFX explores the opposite: **stay in the terminal** for quick checks — prices, headlines, saved articles — without leaving your workflow. The data is mocked (seeded instruments and articles that jitter on a timer), but the interaction model is real: auth gate, first-run setup, sidebar navigation, overlays, search, and persistent config on disk.\n\nUse it as:\n\n- A reference Ink + React terminal app with multiple screens and themes\n- A playground for the shared UI component library under `components/ui/`\n- A starting point if you later wire real price/news APIs\n\n## Stack\n\n| Layer         | Technology                                                                                            |\n| ------------- | ----------------------------------------------------------------------------------------------------- |\n| Runtime       | Node.js 22+ (ES modules; matches Ink 7)                                                               |\n| CLI           | [meow](https://github.com/sindresorhus/meow) — flags and help                                         |\n| Terminal UI   | [Ink](https://github.com/vadimdemedes/ink) 7 — React for the command line                             |\n| UI framework  | React 19                                                                                              |\n| Language      | TypeScript (compiled to `dist/`)                                                                      |\n| Charts        | [simple-ascii-chart](https://www.npmjs.com/package/simple-ascii-chart) — sparklines and detail charts |\n| Markdown      | [marked](https://marked.js.org/) — article bodies in the terminal                                     |\n| Testing       | [AVA](https://github.com/avajs/ava)                                                                   |\n| Lint / format | [XO](https://github.com/xojs/xo) + Prettier                                                           |\n\nThe app uses the terminal **alternate screen** (`\\u001B[?1049h`) so the full UI owns the viewport and restores your shell on exit.\n\n## Features\n\n- **Authentication** — mock login with token persisted in config; logout from settings\n- **First-run setup** — pick a color theme from several terminal palettes (Catppuccin, Dracula, Tokyo Night, Gruvbox, Nord, One Dark, Solarized, Kanagawa, and more)\n- **Prices** — list, filter, search, watchlist (`s` / `v`), manual refresh (`r`), detail view with chart\n- **News** — feed, search, article detail, bookmark from an article\n- **Bookmarks** — saved articles stored in `bookmarks.json`\n- **Settings** — theme, refresh intervals, logout, reset demo data\n- **Keyboard-first** — `j`/`k` navigation, `/` search, `Esc` back, shortcuts help in the shell\n\n## Requirements\n\n- A TTY terminal (macOS Terminal, iTerm2, Windows Terminal, etc.)\n- Node.js **22** or newer (Ink 7 requires Node ≥22)\n\n## Install & run\n\nFrom [npm](https://www.npmjs.com/package/@billy_mcdowell/mfx):\n\n```bash\nnpx @billy_mcdowell/mfx\n```\n\nOr install globally (the CLI command stays `mfx`):\n\n```bash\nnpm install -g @billy_mcdowell/mfx\nmfx\n```\n\nFrom the repository:\n\n```bash\nnpm install\nnpm run dev\n```\n\nOr build and run the compiled CLI:\n\n```bash\nnpm run build\nnode dist/source/cli.js\n```\n\nLink globally during development:\n\n```bash\nnpm link\nmfx\n```\n\n## CLI\n\n```bash\nmfx                 # start the app (alternate screen when stdout is a TTY)\nmfx --reset-config  # delete local config, bookmarks, and price favorites, then start\n```\n\n## Configuration\n\nState is written under:\n\n- **macOS / Linux:** `~/.config/mfx/`\n- **Windows:** `%APPDATA%\\mfx\\`\n\nOverride the directory with `MFX_CONFIG_DIR`.\n\n| File                   | Purpose                                          |\n| ---------------------- | ------------------------------------------------ |\n| `config.json`          | Auth token, theme, refresh intervals, setup flag |\n| `bookmarks.json`       | Saved news articles                              |\n| `price-favorites.json` | Watchlist symbols                                |\n\n## Project layout\n\n```\nsource/\n  cli.tsx              # Entry: meow flags, alternate screen, Ink render\n  app.tsx              # Providers and auth/setup/shell routing\n  screens/             # Login, setup, prices, news, bookmarks, settings, details\n  context/             # Auth, config, router, prices, news, bookmarks, viewport\n  mocks/market.ts      # Seed instruments & articles; price jitter\n  lib/                 # Paths, storage, formatting, spark trends\ncomponents/ui/         # Reusable Ink UI primitives (tables, charts, sidebar, etc.)\nlib/terminal-themes/   # Theme token definitions\nimages/                # Screenshots for this readme\n```\n\n## Development\n\n```bash\nnpm run dev          # tsx watch — fastest iteration\nnpm run build        # tsc + path alias rewrite\nnpm test             # build then AVA\nnpm run lint         # Prettier + XO\n```\n\n### Releases & versioning ([Changesets](https://github.com/changesets/changesets))\n\nWhen a pull request should produce an npm release after it merges to `main`, add a changeset:\n\n```bash\nnpm run changeset\n```\n\nPick **patch**, **minor**, or **major** and write a short summary; skip adding a changeset if the PR should not bump the published version.\n\nAfter merge, GitHub Actions opens or updates a **Version Packages** PR; merging that PR publishes `@billy_mcdowell/mfx` and updates `CHANGELOG.md`.\n\n**Maintainers:** configure an npm automation token as the repository secret `NPM_TOKEN` (GitHub → Settings → Secrets and variables → Actions) so the release workflow can publish.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","readmeFilename":"readme.md","_rev":"1-9a885e14197a2838ce7d93cbc0eb9b26"}