npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tealstreet/cli

v0.10.0

Published

Tealstreet CLI - Trade crypto from your terminal

Downloads

558

Readme

Tealstreet CLI

Trade crypto from your terminal. Built on Bun, compiled to standalone cross-platform binaries (darwin-arm64/x64, linux-x64/arm64).

Looking for usage docs? Commands, account setup, sizing/price grammar, workflow operators, and recipes live at https://docs.tealstreet.io/cli/ (source in apps/documentation/cli/). This README is for working on the CLI itself — see that site for anything user-facing.

While the REPL is running it also acts as a loopback side-car for the web app on the same machine — see operations/listener.md for the listener wire protocol, auth, and kill switches.

Runtime

Bun, not Node.js (bun-types in tsconfig). Binaries are produced with bun build --compile. Exchange integration delegates to @tealstreet/safe-cex; shared command logic lives in @tealstreet/cli-core.

Develop locally

Prerequisite: Bun — the CLI's scripts invoke bun directly. Install workspace deps from the monorepo root first (this is a yarn workspace; @tealstreet/* deps resolve from there).

yarn install                 # from the monorepo root

cd apps/cli
yarn dev                     # run the REPL from source (= bun run src/index.ts)
yarn typecheck               # tsc --noEmit
yarn test                    # vitest
yarn logs                    # tail ~/.tealstreet/cli.log

Build a local binary

yarn build compiles standalone binaries for all four platforms (via bun build --compile) into dist/tealstreet-<platform>. To build and run the one for your machine:

yarn build
./dist/tealstreet-darwin-arm64        # or -darwin-x64 / -linux-x64 / -linux-arm64

npm package

The public @tealstreet/cli package is a thin installer/launcher. It does not ship CLI source; it downloads the matching binary from https://github.com/Tealstreet/cli/releases on install or first run.

Config and runtime state live under ~/.tealstreet/ — see operations/config-files.md.

Architecture

CLAUDE.md has the full source map, the listener subsystem, the remote-signing model, the logging taxonomy, and the script-types pipeline. High-level entry points:

  • src/index.ts — Commander.js entry
  • src/repl.ts — interactive REPL (readline)
  • src/listener/ — loopback 127.0.0.1:53219 WS + HTTP side-car for the web app
  • src/commands/ — command implementations (shared logic in @tealstreet/cli-core)
  • src/config.ts~/.tealstreet/config.json (accounts, listener kill-switches, footer layout)
  • src/logger.ts + src/log-classify.ts — console interception, severity taxonomy, operational-noise routing
  • src/scroll-region.ts + src/status-line.ts + src/footer.ts + src/footer-segments.ts — the pinned output surfaces (top alert bar + bottom status footer over one shared ANSI scroll region)
  • src/audit-log.ts — durable append-only write-op trail + command tracing (audit command)

Development

Watch Mode Pattern (Terminal Takeover)

Watch modes (wa, wp, wo, wm, watch chart, watch chase) need to "take over" the terminal to:

  1. Display live-updating content
  2. Capture single keystrokes to exit (Escape or Ctrl+X in REPL mode, also Ctrl+C when running via CLI args)
  3. Prevent the REPL prompt from showing

Exit Keys (centralized in utils/exit-keys.ts):

  • REPL mode: Escape or Ctrl+X (Ctrl+C stays with readline for line cancel)
  • CLI args mode: Ctrl+C, Escape, or Ctrl+X

The Pattern (see startWatchAccount in repl.ts):

import { isReplExitKey, getReplExitMessage } from './utils/exit-keys';

function startWatchMode(rl: readline.Interface): void {
  // 1. Set isMonitorMode flag - CRITICAL! This prevents REPL prompt from showing
  isMonitorMode = true;

  // 2. Pause readline to stop it from processing input
  rl.pause();

  // 3. Enter alternate screen buffer (optional - keeps scrollback clean)
  process.stdout.write(ENTER_ALT_SCREEN);

  // 4. Set up raw mode key handler for exit keys
  const onRawKey = (data: Buffer) => {
    const key = data[0];
    if (isReplExitKey(key)) {
      stopWatch();
    }
  };

  const stopWatch = () => {
    if (!isMonitorMode) return; // Prevent double-stop
    isMonitorMode = false;

    // Clean up: remove key handler, exit raw mode, exit alt screen
    process.stdin.removeListener('data', onRawKey);
    if (process.stdin.isTTY) process.stdin.setRawMode(false);
    process.stdout.write(EXIT_ALT_SCREEN);

    // CRITICAL: Recreate readline to restore terminal state
    recreateReadline();
  };

  // 5. Store stop function for cleanup (used by readline close handler)
  stopMonitorFn = stopWatch;

  // 6. Enter raw mode and start listening
  if (process.stdin.isTTY) process.stdin.setRawMode(true);
  process.stdin.on('data', onRawKey);

  // 7. Return immediately! The function does NOT block.
  // Watch mode runs via setInterval
}

Why isMonitorMode is CRITICAL:

  • The REPL's command handler always shows the prompt after a command completes
  • isMonitorMode = true suppresses this behavior (checked before calling rl.prompt())
  • Without this flag, the REPL prompt appears immediately after the watch command "returns"

Key Points:

  1. Watch functions return IMMEDIATELY - they don't await/block
  2. isMonitorMode = true prevents REPL prompt from showing
  3. Raw mode (setRawMode(true)) captures single keystrokes
  4. Must call recreateReadline() on cleanup (raw mode corrupts readline state)

Raw Mode and Readline Pattern

Watch modes use raw stdin mode (setRawMode(true)) to capture single keystrokes (Escape, Ctrl+X). This corrupts Node.js readline's internal state, causing issues like:

  • Double-printed characters
  • Arrow keys printing escape sequences ([A) instead of navigating history
  • Random input clearing

Solution: After exiting raw mode, recreate the readline interface entirely instead of just resuming it. The recreateReadline() helper in repl.ts handles this:

function recreateReadline(): void {
  if (!rlInstance) return;

  // Preserve history
  const history = (rlInstance as readline.Interface & { history?: string[] }).history || [];

  // Close old readline (with flag to prevent exit handler)
  isRecreatingReadline = true;
  rlInstance.close();
  isRecreatingReadline = false;

  // Create fresh readline
  rlInstance = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    prompt: getPrompt(),
    history: [...history],
    historySize: MAX_HISTORY_SIZE,
  });

  // Re-setup event handlers...
}

Important: All watch mode stop functions must call recreateReadline() to restore proper terminal state.

Console output, logging & status surfaces

src/logger.ts intercepts console.* and routes each line through, in order: operational-noise suppressionrate limitreadline-aware printing. The full taxonomy and the user-facing behaviour are documented in CLAUDE.md and the public Output reference — keep all three in sync (see the doc-sync table at the top of CLAUDE.md). The essentials:

  • Operational noise → file only. Lines matching OPERATIONAL_PATTERNS in src/log-classify.ts (keepalive pings, reconnect chatter, balance dumps) are kept out of the terminal — they still hit ~/.tealstreet/cli.log. Add new noisy prefixes there, not in logger.ts.
  • Everything else prints above the prompt via writeAbovePrompt (readline-aware), so async output never corrupts what the user is typing. console.warn / console.error (and any line log-classify.ts rates critical) are additionally mirrored on the top status bar (src/status-line.ts). ("critical" is a severity classification, not a console method.)
  • print() / originalConsoleLog() bypass all of the above — use them for primary command output, prompts, progress, and anything the user explicitly asked for.
  • Verbose transport diagnostics share cli.log. When the CLI runs with DEBUG=1 or DEBUG=true, tunneled HoW/tradetunnel REST requests emit sanitized [TradeTunnel] request/response summaries through the existing console.log interception. The [TradeTunnel] prefix is classified as operational, so those lines land in ~/.tealstreet/cli.log and stay off the terminal. This is off by default; it is not a separate network log file.
import { originalConsoleLog } from '../logger';
const print = originalConsoleLog; // never throttled / suppressed
print(chalk.green('✓ Operation complete'));

Pinned surfaces (one shared ANSI scroll region, src/scroll-region.ts): the transient top alert bar (status-line.ts, warn/error/critical, dims) and the always-on bottom footer (footer.ts + footer-segments.ts, user-customizable segments). Both no-op on non-TTY.

Command tracing: write-ops can be recorded to a durable append-only ~/.tealstreet/audit.log with per-invocation runId + fill attribution (src/audit-log.ts, audit command).

Building & Releasing

Prerequisites

  • Bun - curl -fsSL https://bun.sh/install | bash

Build (local only)

# Build binaries for all platforms (darwin-arm64, darwin-x64, linux-x64, linux-arm64)
bun run build

Binaries are output to dist/.

Release to GitHub

# Release with version bump
yarn release:patch     # 0.1.0 -> 0.1.1
yarn release:minor     # 0.1.0 -> 0.2.0
yarn release:major     # 0.1.0 -> 1.0.0

# Release current package.json version
yarn release

This will:

  1. Bump version in package.json (if specified)
  2. Commit the version bump
  3. Push a private monorepo tag named cli-vX.Y.Z
  4. Let GitHub Actions build binaries, publish public Tealstreet/cli release vX.Y.Z, and update Tealstreet/homebrew-tap

The workflow uses repository secret TEALSTREET_CLI_RELEASE_TOKEN to write to the public release repo and Homebrew tap.

License

MIT