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

@afk-watch/cli

v0.4.0

Published

Installer for afk.watch integrations - wires Claude Code hooks and optional hosted pickup.

Readme

@afk-watch/cli

Installer for the afk.watch agent integrations. It wires the Claude Code lifecycle hooks (scripts/afk-hook.mjs, issue #36), installs the /afk-watch skill, and can generate the opt-in hosted pickup workflow, so runs show up in the app without hand-editing settings.json. Every path has a symmetric uninstall. The idempotent settings.json merge at its core (src/settings.ts) is runtime-agnostic and will back future runtimes too (issue #35).

Use

npx @afk-watch/cli@latest init --key key_live_xxx --test
  • Stores the key in ~/.config/afk.watch/config.json.
  • Installs the hook handler to ~/.config/afk.watch/afk-hook.mjs and merges the four afk hooks into your Claude Code settings.json - idempotently (re-running never duplicates), preserving your existing hooks and settings.
  • Installs the afk-watch skill to ~/.claude/skills/afk-watch/, which is what gives you /afk-watch [issue]. --project puts it in ./.claude/skills/ instead, matching where the settings went. A re-run replaces it, so a CLI upgrade refreshes the skill rather than leaving a stale copy.
  • Checks issue resolution in the current repo, by importing the handler it just installed, and prints what a session here would report against - or why it wouldn't be reported at all (you're on main, no GitHub remote, …). --test proves the key and push delivery; this proves the path a real session takes. See ADR 0008.
  • --test fires a confirmation run so your phone lights up right away.

Once installed, hand the agent an issue directly:

/afk-watch #33     # claim issue 33, work it, report the run
/afk-watch         # find open `ready-for-agent` issues and claim the oldest

The skill claims an issue by swapping ready-for-agent for in-progress before starting work, so a second pass can't pick up the same one. That is an advisory lock, not a real one - two runs started in the same moment can still race.

afk uninstall                     # remove the hooks, handler, skill, and key
afk uninstall --keep-key          # ...but keep the stored key
afk uninstall --pickup            # ...and remove the generated hosted workflow

Optional automatic local pickup

init installs the skill but cannot create a Claude Desktop scheduled task. Open the repository you want watched in Claude Desktop and say exactly:

Create a scheduled task named afk.watch pickup that runs /afk-watch every 5 minutes in this folder using auto permission mode.

Use auto permission mode: it is the safest unattended mode that can edit files, run commands, commit, and open PRs, while still blocking actions it judges risky. Do not use bypassPermissions. Pickup works only while Claude Desktop is open and the machine is awake; closing the lid stops it. /loop is session-scoped and is not the unattended mechanism.

Optional automatic hosted pickup

If pickup must continue while your machine is off, opt in per repository:

npx @afk-watch/cli@latest init --pickup

Run it from inside the repository. This writes .github/workflows/afk-pickup.yml at the repository root - the only place GitHub reads workflows from - without touching sibling workflows, and errors out rather than writing anything when there is no repository.

The generated file carries its own afk-template-version and an afk-template-sha256 of the rest of its body, which is how the CLI tells its own output from yours. An untouched copy - of any version - is a no-op to re-install, is upgraded in place when a newer template ships, and is removed by afk uninstall --pickup. Edit it and the digest stops matching: from then on neither command writes or deletes that file. init tells you a newer template exists (and flags a security-relevant one) so you can merge it yourself; uninstall reminds you the file keeps firing on ready-for-agent until you delete it. Run from outside a repository, uninstall skips the workflow half with an explanation and still removes the hooks, handler, skill, and stored key.

Hosted pickup runs on ubuntu-latest and needs two repository Actions secrets: AFK_KEY and ANTHROPIC_API_KEY. A Claude Pro/Max subscription does not authenticate hosted CI. Anthropic usage is billed per token in addition to GitHub Actions minutes. Commit and merge the workflow to the repository's default branch; GitHub does not deliver issues events to a workflow that exists only on a feature branch. It also needs Settings > Actions > General > "Allow GitHub Actions to create and approve pull requests", because the runner is deleted when the job ends: the workflow has the agent commit to afk-pickup/issue-<n>-<run id>-<attempt> (a fresh branch per run, so it never collides with what an earlier pickup pushed), push, and open a pull request, and verifies that before reporting done. Work left uncommitted, unpushed, or without an open pull request carrying those exact commits fails the run instead of being reported as finished - though a run that pushed its work and then left a stray file behind still names the pull request holding the commits, rather than claiming everything was lost.

That pull request runs no CI. GitHub does not fire pull_request or push workflow runs for anything created with the built-in GITHUB_TOKEN, and this path keeps to two secrets - no PAT, no GitHub App - so there is nothing else to open it with. It arrives with no checks on it. The agent has to run the project's own validation inside the job and report which commands it ran, but that is its word, not a check run: trigger the repository's checks yourself and confirm they pass before merging. Every report repeats this on the line that names the pull request.

Because each run has its own branch, a second pickup of an issue whose pull request is still open would produce two pull requests for the same work. So it refuses: the run starts nothing, spends no tokens, reports the open pull request's URL, and swaps ready-for-agent for in-progress. Nothing is ever closed, deleted, or force-pushed on your behalf - you decide whether that pull request merges or closes, and re-applying ready-for-agent afterwards picks the issue up again.

Hosted pickup is opt-in because of that billing and secret setup; plain init keeps the local/manual paths only. It requires CLI 0.4.0 or newer.

Issue text is agent instructions. The agent is handed the issue text and runs unattended with a token that can write contents, issues, and pull requests. Event fields never reach a shell command, but nothing stops issue prose from steering an agent asked to follow it. So the workflow picks up an issue only when GitHub reports its author's author_association as OWNER, MEMBER, or COLLABORATOR.

Only the title and body from that gated event reach the agent, and it is told not to fetch or obey issue comments, other issues, or reviews. Comments are not trusted pickup input - anyone can comment on an admitted issue whatever their association, so a thread-reading agent would take instructions from exactly the people the gate excludes. Put what you want done in the issue body before you tap.

That is the relationship GitHub declares in the event payload, not a check that the author has write access here: MEMBER means a member of the owning organization, which in an org whose base permission is Read (the default) includes people with no write access to this repository, and COLLABORATOR covers read-only invitees. It narrows pickup to people already inside your org or repo; it does not verify they could push the change themselves.

Everything else is excluded - CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR, and NONE, and NONE is also what GitHub reports for issues filed by a GitHub App or bot, so automated backlog items are never picked up either. In every excluded case the label stays on and you work it by hand (locally with /afk-watch, or by re-filing it in your own words). Residual risk stands for everyone the gate admits: they can steer the agent through issue text.

If setup fails before the afk.watch run is created (a missing secret, an unreachable API), the ready-for-agent label is left in place, so a tap from the phone is never silently swallowed.

Options

| | | |---|---| | --key <key> | your API key (or set AFK_KEY). Prompted on a terminal if omitted. | | --global | write to ~/.claude/settings.json (default; applies everywhere). | | --project | write to ./.claude/settings.json (this repo only). | | --test | fire a post-install confirmation run. | | --pickup | install or upgrade the opt-in hosted Actions workflow in this repository; with uninstall, remove it. Either way, a file you edited is left alone. | | --api <url> | API base (default https://api.afk.watch/v1). | | --agent <name> | agent label shown on runs (default claude-code). | | -y, --yes | don't prompt; use flags/env and defaults. |

The curl form (served from the API origin) just runs this CLI:

curl -fsSL https://afk.watch/install.sh | AFK_KEY=key_live_xxx sh

Develop

npm run build      # tsc → dist/, bundle the hook, skill, hosted workflow, and shebang
npm test           # vitest (pure merge, config, init/uninstall, arg parsing,
                   #   the hook handler end to end - src/hook.test.ts, and
                   #   what the tarball ships - src/packaging.test.ts, which
                   #   packs the package, so it is the slow one)
npm run typecheck

Editing templates/afk-pickup.yml invalidates the # afk-template-sha256: line in its own header, which is what marks a generated file as ours. npm test fails with the replacement line printed in full - paste it over the old one. Bump # afk-template-version: in the same edit whenever the change ships to users, so an installed copy can say which version it came from.

Unlike the rest of the workspace (consumed as TS source by bundler-aware tools), this package is executed by the end user's Node, so it builds to plain ESM with NodeNext resolution and explicit .js import extensions. See docs/adr/0004-cli-installer-distribution.md.