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

opencode-ast-tools

v0.1.0-alpha.1

Published

Safe structural search and AST refactoring tools for OpenCode

Readme

OpenCode AST Tools

Safe structural search and AST refactoring for OpenCode, powered by the official ast-grep CLI.

This project is in public alpha. Pin an exact version and review previews before applying them.

The plugin deliberately separates preview from writing:

  • ast_grep_search searches syntax trees and never writes files.
  • ast_grep_replace calculates an immutable preview and stores a short-lived in-memory plan. It never writes files.
  • ast_grep_apply applies exactly one previously generated plan after checking edit permission, path containment, ownership, expiry, engine version, and file hashes.

Install

Pin the plugin version in opencode.json:

{
  "plugin": ["[email protected]"]
}

Optional limits can be provided with the plugin entry:

{
  "plugin": [
    [
      "[email protected]",
      {
        "limits": {
          "maxSearchResults": 50,
          "maxChangedFiles": 50,
          "maxReplacements": 500,
          "planTtlSeconds": 900
        },
        "respectGitignore": true,
        "allowIgnoredFiles": false
      }
    ]
  ]
}

Tool catalog permission and filesystem permission are separate. ast_grep_search and ast_grep_replace request read access to their input scopes. ast_grep_apply requests edit access to the exact files in its plan, so an agent configured with edit: deny cannot apply a preview.

Search

{
  "pattern": "console.log($ARG)",
  "language": "typescript",
  "paths": ["src"],
  "include": ["**/*.ts"],
  "contextLines": 1,
  "maxResults": 50
}

$NAME captures one named AST node, $_ is anonymous, $$$NAME captures zero or more nodes, and $$$ is an unnamed multi-node wildcard. Ranges shown to the model use one-based lines and columns; byte offsets remain zero-based and end-exclusive.

Preview And Apply

Create a preview:

{
  "operations": [
    {
      "pattern": "console.log($ARG)",
      "replacement": "logger.info($ARG)"
    }
  ],
  "language": "typescript",
  "paths": ["src"],
  "include": ["**/*.ts"]
}

If the rewrite changes bytes, the result contains a planId, hashes, and bounded unified diffs. Apply only that identifier:

{
  "planId": "0123456789abcdef0123456789abcdef"
}

Apply does not accept paths, patterns, replacements, caller-provided edits, force, or output text. Plans are bound to the OpenCode session and real worktree, expire after 15 minutes by default, live only in memory, and are consumed after a successful apply.

Supported Languages

bash, c, cpp, csharp, css, elixir, go, haskell, html, java, javascript, json, kotlin, lua, nix, php, python, ruby, rust, scala, solidity, swift, typescript, tsx, and yaml.

Safety Model

  • Only relative paths contained by the real worktree are accepted. Absolute paths, .. traversal, symlink escapes, junction escapes, and non-regular result files are rejected.
  • The installed @ast-grep/cli executable is resolved directly and checked for version 0.44.1. The plugin does not search PATH, invoke a shell, load project grammars, or download executables at runtime.
  • Files must be UTF-8 and no larger than 5 MiB. Rewrites operate on byte ranges, preserving BOM, line endings, and all bytes outside each range.
  • Discovery is deterministic and limited to 10,000 language-eligible files. Search reports a truncated scope; replace fails without creating a partial plan.
  • Identical edits are deduplicated and overlapping edits fail before staging.
  • Apply rechecks every source hash before staging and immediately before commit. A stale plan writes no files.
  • Outputs are bounded, terminal control characters are removed from model-facing text, and invalid engine JSON is an error rather than an empty result.

Each file is replaced with a same-directory rename when the filesystem supports atomic rename. A multi-file apply is not a crash-recoverable transaction: a failure during the rename sequence can produce a partial commit. The plugin keeps original bytes through commit, attempts best-effort rollback, and reports COMMIT_PARTIAL if at least one file was replaced or COMMIT_FAILED if none were.

These checks detect known path, content, and mode changes immediately before each rename. Portable Node.js does not provide directory-relative renameat operations, so the final pathname check and rename cannot be one atomic operation. The apply guarantees assume no hostile process with permission to rename entries in target directories during that final interval.

Alpha Limitations

  • Plans are held in memory and do not survive an OpenCode restart.
  • Multi-file apply is not crash-recoverable; inspect COMMIT_PARTIAL failures before retrying.
  • Discovery stops at 10,000 eligible files, individual files are limited to 5 MiB, and only the listed built-in languages are supported.
  • npm-based hosts require Node.js ^22.22.2, ^24.15.0, or >=26 because of the production dependency graph.
  • The final pathname validation and rename have the portable Node.js race described in the safety model.

Errors include a stable category prefix such as [STALE_PLAN], [LIMIT_EXCEEDED], or [COMMIT_PARTIAL]. When reporting a bug, open a GitHub issue with the package and OpenCode versions, operating system, error category, and minimal reproduction. Remove source code, paths, credentials, and other sensitive data before posting logs.

Development

npm install
npm run check
npm test
npm run build

Set AST_GREP_INTEGRATION=1 when running npm test to execute search and rewrite fixtures for every advertised language. CI runs those fixtures on Windows x64, Linux x64 GNU, macOS arm64, and macOS x64. The native ast-grep executable must be allowed by the host's application-control policy for these end-to-end tests.

License

The plugin is MIT licensed. Direct dependency notices are in THIRD_PARTY_NOTICES.md.

Development milestones and remaining MVP evidence are tracked in ROADMAP.md.