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

ai-share-usage-cli

v0.1.13

Published

Shared Codex account usage in the terminal: collect, upload, watch and dashboard

Downloads

1,671

Readme

ai-share-usage-cli

Shared Codex (ChatGPT) account usage in the terminal. Same product as the AI Share Usage VS Code extension, same team server, same numbers — for people who work in a terminal.

npm i -g ai-share-usage-cli
ais join <invite>

ais needs Node 20 or newer. It ships as one bundled file, so the install has nothing to build.

No editor? Use the browser dashboard

If Codex is the desktop app for you — no VS Code, no herdr, no terminal habit — three commands are the whole setup:

npm i -g github:DongHyunnn/ai-share-usage-herdr   # the `ais` CLI
ais join <invite>
ais open          # starts the daemon if it is not running, opens the dashboard

ais open prints the URL and opens it (open / wslview / xdg-open); ais web-url only prints it. The daemon binds 127.0.0.1 on settings.webPort (0 = an OS-assigned port) and every request must carry the random token from daemon.json, so nothing on the network can reach it.

Threshold alerts arrive as native OS notifications — macOS Notification Center via osascript, notify-send on Linux, a toast through PowerShell on Windows. ais daemon --no-notify or ais config set notifications false turns them off, --no-web leaves the dashboard unserved.

Collection needs nothing from you. By default the collector reads OMO sessions and their discovered Senpi child sessions, Codex rollout logs from ~/.codex/sessions (or $CODEX_HOME/sessions), and Gajae Code sessions from ~/.gjc/agent/sessions.

Commands

| Command | What it does | | --- | --- | | ais join <invite\|link> | Applies the invite (server, key and group), signs in with GitHub, joins | | ais login | GitHub sign-in through a loopback callback; the URL is printed for headless shells | | ais logout | Forgets the stored session | | ais status | One line: ~48% / 61% ⚡1.3×, plus daemon health | | ais status --json | The full snapshot and a dashboard summary, for scripts | | ais report | One quota window as a summary to paste into a chat (Markdown) | | ais report --window last --format json | The previous window, as the report object | | ais dashboard | Full-screen dashboard: r refresh, 1-4 range, ? help, q quit | | ais daemon | Collects, uploads, polls the account quota, refits weights, raises alerts | | ais daemon --once | One cycle and exit — for cron, a shell hook or a CI step | | ais open | Opens the local web dashboard, starting the daemon when it is not running | | ais web-url | Prints the dashboard URL (token included) and nothing else | | ais autostart install\|uninstall | Writes (or removes) the launchd agent / systemd --user unit | | ais guide [--admin] | The setup guide as text (--lang ko\|en) | | ais join --prompt | Asks for the invite on the terminal (what the herdr popup pane runs) | | ais herdr status-line | Prints the token the herdr sidebar shows as $ais | | ais invite | Prints the invite token and the one-click link | | ais create-group <name> | Creates a team (admin; needs the server settings) | | ais config get [key] | Prints settings | | ais config set <key> <value> | Changes one setting | | ais --version | Prints the version |

The weekly report

ais report turns one quota window into the paragraph somebody would otherwise write by hand: the range, where the account opened and closed, every member with their tokens, quota, API-equivalent cost and share of their own fair share, the models that did the work, what the window is missing, the calibration the percentages rest on, and where the current pace lands.

It carries the marks the dashboard uses, and they mean the same thing here: is a floor, is partly estimated, and is withheld — nothing behind that figure could be priced, so no percent is claimed. --format json prints the same object with those qualifications as fields (coverage.isLowerBound, coverage.unknown, cost.hasEstimate) rather than as marks.

The same summary is a Copy report button on the dashboard's admin tab, in the editor and in the browser page alike, and it is there for every member: it is a summary of your own group.

Where state lives

$AIS_HOME, by default ~/.config/ai-share-usage/. Every file is written 0600.

| File | Contents | | --- | --- | | settings.json | supabaseUrl, supabaseAnonKey, groupInviteCode, displayName, pollIntervalSeconds, language, sources, extraHomes, discoverContainers, containerNamePatterns, targetSharePercent, notifications, webPort | | session.json | The Supabase session and its PKCE verifier | | cursors.json | Per-file resume cursors for the collector | | alerts.json | Which alert levels already fired in this quota window | | daemon.json | Heartbeat: pid, startedAt, lastCycleAt, lastStatus, and web (port, token, url) |

language is auto (follows LANG/LC_ALL), ko or en. sources picks which session logs to collect: omo (including discovered Senpi children), codex, and gjc. All three are enabled by default.

Collecting from a container

When omo or Codex run inside a container, their sessions are written into the container's home. Bind-mount that home and name it in extraHomes:

docker run -v $HOME/dev-box:/root -it my-image
ais config set extraHomes '~/dev-box'
# or, to choose the label: ais config set extraHomes '~/dev-box = box'

settings.json takes the same list as strings or objects, and the daemon's browser dashboard edits it in the Extra home directories card:

{ "extraHomes": ["~/dev-box", { "path": "/srv/ci", "label": "ci" }] }

Each entry is an absolute path (~ and $VAR are expanded) and is read like your own home — <home>/.omo/agent/sessions, <home>/.codex/sessions, <home>/.gjc/agent/sessions for the enabled sources, Senpi child sessions included. Usage found there is filed under the machine <hostname>:<label>, the label defaulting to the directory's name, so a container and its host stay separate rows in the per-machine breakdown. A home that is missing or unreadable is not watched and says so once in the log; it is picked up on a later cycle. Adding or removing an entry takes effect on the next cycle — no daemon restart.

Your Codex sign-in stays the one in your own home: an extra home's .codex/auth.json is only compared with it, and a different account there is logged as a warning while collection continues. What may be uploaded is decided by the account-provenance rules, not by which directory a log sat in.

Finding those homes automatically

If the containers already run on this host, the daemon can ask Docker where their homes are instead of you writing the paths down:

ais config set discoverContainers true
ais config set containerNamePatterns 'dev-*, ci'   # empty = every running container

Every running container that matches is inspected, and each bind or volume mount whose destination is a home (/root, /home/<user>) or one of the agent directories (.omo, .codex, .gjc) becomes an extra home on its host-side path, filed under the machine <hostname>:<container name>. A container that stops loses its watchers on the next cycle, one that starts gains them; no restart either way. An extraHomes entry you wrote yourself always wins for the same path, label included, and your own home is never collected twice.

Volume mounts resolve to /var/lib/docker/volumes/<name>/_data, which usually only root can read. That is detected, not hit: the home is skipped and the log says which container and which path, so you can bind-mount the home instead or run the daemon as root. No Docker socket, or a DOCKER_HOST that is not a local unix socket, means the feature stays inactive and says so once.

The trust boundary. Being able to talk to /var/run/docker.sock is root-equivalent on most hosts — whoever reaches it can start a privileged container. That is why this is opt-in and off by default. What the collector itself does with the socket is two read-only calls, GET /containers/json and GET /containers/{id}/json; it never execs, never attaches, never creates, and of the answer it reads only the container name, whether it is running, and the mount table. Environment variables, labels and secrets are not read.

What is collected

Model names and token counts, session ids, message timestamps and the machine hostname — never prompts, responses, file names or file contents. The Codex access token never leaves the machine.

Running it as a service

ais daemon runs until SIGINT/SIGTERM and can be supervised by systemd, tmux or a herdr session. ais daemon --once fits a cron entry or a shell hook. ais status exits 0 even before you have joined, so a prompt can call it unguarded.

ais autostart install writes the file your platform wants and prints the one command left to run:

| OS | File | Then run | | --- | --- | --- | | macOS | ~/Library/LaunchAgents/com.github.donghyunnn.ais.plist | launchctl load -w <file> | | Linux | ~/.config/systemd/user/ais.service | systemctl --user daemon-reload && systemctl --user enable --now ais | | Windows | none — one Scheduled Task | schtasks /create /tn "AI Share Usage" /sc onlogon /tr "node C:\path\to\ais.mjs daemon" |

ais autostart uninstall removes the file and prints the matching disable command. Both files are also in autostart/ to copy by hand.

MIT licensed.