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

ios-simmer

v0.2.0

Published

Fast terminal loop for building, installing, launching, and streaming logs from iOS apps — no Xcode window required.

Readme

simmer

A fast terminal loop for building, installing, launching, and streaming logs from iOS apps — no Xcode window required.

pick target → build → install → launch → stream logs → [r/l/c/f/d/s/v/q]

Install

Published as ios-simmer on the public npm registry (the package is named ios-simmer; the command it installs is simmer):

npm install -g ios-simmer

simmer is now on your PATH. Re-run the same command to upgrade to the latest published version. No auth needed — it's a public package.

Global installs straight from the git repo (npm install -g git+ssh://...) don't work reliably — npm's git-dependency install path can leave a global install symlinked into its own cache tmp dir, which gets cleaned up right after, breaking the binary. Hence a real npm publish instead.

Local development

cd ios-simmer
npm install
npm run dev -- <args>   # runs straight from src/ via tsx, no build needed

Or npm link after npm run build to get a simmer binary backed by your working tree.

Releasing a new version

  1. Bump version in package.json (semver).
  2. npm run build and commit the updated dist/ alongside your source changes — CI fails if dist/ drifts from src/.
  3. Tag and push: git tag vX.Y.Z && git push origin vX.Y.Z. This triggers .github/workflows/publish.yml, which builds and npm publishes to the public registry using the repo's NPM_TOKEN secret (an npm automation token — create one at npmjs.com → Access Tokens and add it as a repo secret named NPM_TOKEN).

Use

From an iOS project root (a directory containing a .xcworkspace or .xcodeproj):

simmer

First run in a project prompts for:

  • Scheme — auto-picked if there's only one, otherwise a numbered list.
  • Bundle identifier — no reliable way to read this from xcodebuild -list, so it's asked once and cached.
  • Target — booted/bootable simulators and paired devices in one numbered list, most recently booted first.

All three are saved to .simmerrc in the project root so subsequent runs don't re-prompt. Override any of them per-invocation:

simmer --scheme mobile-staging --bundle-id com.halftone.mobile.dev --target <udid>

Flags always win over .simmerrc.

Keys while logs are streaming

| Key | Action | |---|---| | r | Rebuild, reinstall, relaunch | | l | Relaunch the already-installed binary — no rebuild, for resetting app state fast | | c | Wipe DerivedData and force a full rebuild | | f | Toggle log filter: app-only ↔ everything (simulator only — see caveats) | | d | Prompt for a URL and deep-link into the running app | | s | Screenshot the active simulator (simulator only — see caveats) | | v | Start/stop serve-sim on the active simulator for agent-driven e2e control | | q / Ctrl-C | Terminate the app, kill the log stream, exit cleanly |

Builds stay quiet: a braille spinner + elapsed timer replace the usual xcodebuild flood. On failure, only extracted compilation errors are printed, then the keypress loop resumes — it never installs/launches stale output, and it never kills the whole session.

Where things go

  • DerivedData~/.cache/simmer/derived-data/<project-slug>-<hash>, keyed by the project's absolute path. This is deliberately outside the project tree: it stays stable across runs, and because two git worktree checkouts of the same repo have distinct absolute paths, each worktree gets an isolated build directory automatically — no cross-worktree stomping, no .gitignore changes needed for this one.
  • Logs<project>/logs/<YYYY-MM-DD-HHmm>.log, one file per run, always written in full regardless of which filter mode is echoed to the terminal. simmer appends logs/ (and a couple of its own housekeeping files) to the project's .gitignore the first time it runs there, if a .gitignore exists — additive only, never touches existing lines.
  • Screenshots<project>/screenshots/<timestamp>.png.
  • Config<project>/.simmerrc (JSON: scheme, bundle id, workspace/ project file, last-used target).

Platform caveats (read before relying on these)

A few "device equivalent" commands in the original spec don't have a public 1:1 match in devicectl, and I didn't want to fabricate flags that only look right. Rather than silently degrading, these throw a clear error on device targets:

  • Screenshots (s) — simulator-only. There is no devicectl subcommand that dumps a screenshot PNG for a physical device; screen mirroring is only exposed through Xcode's Devices window / QuickTime screen recording.
  • "Everything" log mode (f → all) — simulator-only. It shells out to simctl spawn <udid> log stream; there's no devicectl equivalent for a physical device's unified log.
  • Deep links (d) on device — uses devicectl device process launch --payload-url, which is real and documented, but unlike simctl openurl I haven't verified it against a real device + app. Simulator deep linking (simctl openurl) is solid.

None of this affects the simulator path, which is what the core loop was built and tested against end-to-end (build → install → launch → live log stream → clean SIGTERM shutdown, verified against photo-journal-ios).

serve-sim integration

v shells out to npx serve-sim <simulator-name> against whichever simulator is currently active, and --kill <name> on v again or on quit. Two things worth knowing:

  • serve-sim is simulator-only (it captures the sim's framebuffer via simctl io) — v errors out on a device target.
  • Its CLI matches a simulator by display name (e.g. "iPhone 17"), not UDID, since that's the interface it exposes. This is a best-effort match: if you ever have two booted simulators with the same name, it's ambiguous.

Install serve-sim's Agent Skill separately per its own docs (bunx add-skill EvanBacon/serve-sim or the Claude Code plugin) — simmer only sequences the handoff, it doesn't reimplement the streaming/skill.

Not implemented from the original scope

  • Arrow-key interactive picker (numbered stdin selection only).
  • Full-screen ink app (lightweight ANSI spinner + status line instead).

Layout

simmer/
├── package.json
├── src/
│   ├── cli.ts             # commander wiring, orchestration, state machine
│   ├── config.ts          # .simmerrc, DerivedData/logs path resolution
│   ├── discover.ts        # find .xcworkspace/.xcodeproj, list schemes
│   ├── picker.ts          # simulator + device listing, numbered picker
│   ├── build.ts           # quiet xcodebuild wrapper + error extraction
│   ├── launch.ts          # install/launch/openurl/screenshot (sim+device)
│   ├── logs.ts            # console stream + optional system log, tee to file
│   ├── keypress-loop.ts   # raw-mode single-keypress dispatch
│   ├── status.ts          # status line rendering
│   ├── tui.ts             # ANSI styles, loading indicator
│   ├── serve-sim.ts       # serve-sim handoff
│   ├── prompt.ts          # readline helpers used outside raw-mode
│   └── types.ts
└── bin/simmer