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

audacity-cli

v0.1.0

Published

Audacity Claude-Code-style coding-agent CLI (talks only to Audacity infra)

Readme

audacity

A local, Claude-Code-style CLI coding agent whose "brain" is your own Audacity infrastructure — never an external Claude/OpenAI endpoint. It talks only to the Audacity web host's OpenAI-compatible chat endpoints, authenticated with a personal audacity_api_… key.

audacity                      # interactive REPL
audacity "fix the failing test"   # run one prompt to completion, then exit

How it works

  • Phase 1 — /rag false (default): a full coding agent. Each turn streams from POST {AUDACITY_API_URL}/v1/chat/completions, and the model can call local tools (read_file, list_files, grep, edit_file, write_file, run_bash). The conversation is held in memory and resent on every call (the endpoint is stateless).
  • Phase 2 — /rag true (coming soon): routes to POST {AUDACITY_API_URL}/v1/agent/chat/completions, the Mastra RAG agent (server-side memory + company/fund/doc tools). Same key, same wire format. The /rag true slash command already toggles session state; sending in RAG mode currently prints a "Phase 2" notice.

All transport/auth lives in src/model.ts (the only integration seam). The public web host handles the litellm-proxy JWT and Cloud Run IAM downstream — the CLI only ever sends your audacity_api_… key. No gcloud, no service token.

Setup

bun install
bun run build          # → dist/index.js (executable, with shebang)

Run it:

bun run dev            # dev (bun --watch src/index.ts)
node dist/index.js     # after build

Install globally (recommended)

cd apps/audacity
npm install -g .       # builds dist/ via the prepare hook, then links `audacity` onto your PATH
audacity               # now works from any directory

npm install -g . runs the prepare script (tsup), so the self-contained dist/index.js is built at install time — no separate build step needed. (bun link or npm link also work for local development.)

On first run, audacity prompts for your production key and a model, then saves them to ~/.audacity/config.json — so it's remembered across every session, shell, and terminal on the machine. You only enter the key once.

To unregister the local global install later:

npm uninstall -g audacity-cli   # removes the `audacity` command from your PATH

Publishing to npm

The package is self-contained — no workspace:* deps, only commander at runtime — so it publishes straight from apps/audacity with no monorepo build orchestration.

You don't need to build first. The prepare lifecycle script (tsup && chmod +x) runs automatically on npm publish, so the shipped dist/index.js is always freshly built from the current src/.

One-time setup:

npm login                       # authenticate to the npm registry

Publish:

cd apps/audacity
npm publish --dry-run           # inspect the tarball WITHOUT publishing — do this first
npm publish                     # ships audacity-cli@<version> to the public registry

The dry run prints exactly what ships. Expect only three files — dist/index.js, package.json, README.md (controlled by the files: ["dist"] whitelist; README.md is always included automatically). No src/, no tests.

After publishing, anyone can install it:

npm install -g audacity-cli
audacity

Name note: the package name is audacity-cli (the bare audacity name is taken on npm). If you ever want to namespace it under the org instead, rename to a scoped name like @audacity-investments/cli in package.json and publish with npm publish --access public (scoped packages default to private otherwise).

Updating the published package

You can never republish the same version number, and unpublishing is restricted (only within 72h). The fix for any bad release is always to roll forward — publish a higher version. Never delete; just bump.

cd apps/audacity
npm version patch               # 0.1.0 → 0.1.1  (bug fixes)
# npm version minor             # 0.1.1 → 0.2.0  (new features, backwards-compatible)
# npm version major             # 0.2.0 → 1.0.0  (breaking changes)
npm publish

npm version bumps package.json and creates a git commit + tag. Then npm publish rebuilds via prepare and ships the new version. Users upgrade with:

npm install -g audacity-cli@latest

While the version stays under 1.0.0, semver convention treats every release as potentially breaking — fine for early development. Cut 1.0.0 once the wire format and CLI surface are stable.

Configuration

audacity is self-contained: the only source of configuration is ~/.audacity/config.json. It depends on no environment variables and nothing else on the machine — a key entered once is remembered globally on that device, across every shell, directory, and session.

On first interactive run, audacity prompts for your production key (pasted, not echoed) and a model, defaults the base URL to production (https://portal.audacityinvestments.com), and auto-saves to ~/.audacity/config.json (chmod 600) — no "save?" prompt. Requests go to the public prod host, which routes them through the production litellm-proxy downstream. Run /key anytime to change the saved key. One-shot mode (audacity "…") never prompts — it reads the saved config and errors clearly if no key is saved.

Optional field: compactModel — the model /compact uses to summarize. Summarizing is an easy task, so it defaults to a cheap, fast model (gemini-2.5-flash) independent of your chat model; set compactModel to override it.

{
  "apiUrl": "https://portal.audacityinvestments.com",
  "apiKey": "audacity_api_…",
  "model": "claude-opus-4-8",
  "compactModel": "gemini-2.5-flash"
}

REPL commands

| Command | Action | |---------|--------| | /model [id] | Pick a model (no arg → numbered picker; sourced from apps/litellm/litellm_config.yaml) | | /rag true\|false | Toggle RAG mode for the session (Phase 2 for true) | | /auto | Toggle auto-approve for mutating tools | | /key | Re-enter and save your API key | | /cwd | Show the working directory | | /compact | Summarize older turns into one message, keep the last 2 verbatim (shrinks context) | | /clear | Reset the conversation | | /exit | Quit |

Permissions

read_file, list_files, grep run without prompting. edit_file, write_file, run_bash ask for y/N approval first (showing exactly what will run) — bypass with the --yes/-y flag or the /auto toggle. In one-shot mode, mutating tools require -y.

Testing prompt caching

The harness is a realistic way to exercise OpenAI prompt caching: it resends the whole conversation on every turn (the endpoint is stateless), so a large, stable prefix repeats call after call — exactly what the provider cache rewards. Cheaper cached input tokens are captured server-side as litellm_usage_log.cached_input_tokens (see apps/litellm-proxy/README.md for the full metering/verification story).

Prerequisites

  1. Point at an environment where the capture is deployed. Prompt-cache metering lives on the UAT proxy first. Set ~/.audacity/config.json:
    {
      "apiUrl": "https://web-uat-qpe5npob6a-uk.a.run.app",
      "apiKey": "audacity_api_…your UAT key…",
      "model": "gpt-5.5"
    }
  2. Use an OpenAI model (gpt-5.5, gpt-5.4, …). OpenAI caches automatically; other providers need explicit cache markers that aren't wired yet.

⚠️ Cache population is asynchronous

The cache isn't guaranteed warm on the very next turn — an early turn can still report cached_tokens = 0, and hits land reliably only after the prefix has been seen a few times. Run several turns in one session and don't /clear.

Good sessions to trigger hits

Load a large file early (so the prefix crosses OpenAI's ~1024-token floor), then ask follow-ups that reuse that context:

read apps/litellm-proxy/src/routes/api/chat/completions/index.ts
walk me through the streaming success path
where exactly is user cost computed vs fmv cost?
now explain the non-streaming path and how it differs

or a multi-file exploration:

read src/agent.ts, src/model.ts, and src/tools.ts
explain how a tool call flows from the model back into the loop
which tools require approval and where is that enforced?

Bad cache tests (expect no cache): short one-liners with no file context, /clear between questions, or jumping topics each turn.

Observe the hits

The harness streams and doesn't print usage, so watch the proxy logs (the stream variant fires for harness traffic):

gcloud logging read 'resource.type="cloud_run_revision" AND resource.labels.service_name="litellm-proxy-uat" AND textPayload:"[DEV:prompt-cache]"' \
  --project=audacity-uat --limit=10 --freshness=10m --format='value(textPayload)'

Expect cached_input_tokens to climb turn over turn, e.g. [DEV:prompt-cache] stream model=gpt-5.5 prompt_tokens=4450 cached_input_tokens=4224 CACHE HIT.

Test

bun test               # tool-layer unit tests (no API key needed)
bun run typecheck