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

pi-tree-sitter

v0.2.8

Published

Pre-write syntax validation for pi using tree-sitter WASM grammars

Readme

pi-tree-sitter

Pre-write syntax validation and structural code tools for pi using tree-sitter WASM grammars.

Write-time validation: hooks into write and edit tools to parse content before it hits disk. If tree-sitter finds syntax errors, the extension blocks the tool with actionable feedback — line, column, source snippet, and for MISSING nodes, what token was expected. The LLM sees the error in the same turn and self-corrects.

Semantic code tools: registers list_symbols, find_definition, find_callers, find_callees, and get_symbol_body tools so the agent can query code structure — functions, classes, methods, interfaces — without grepping or reading whole files.

Inspired by dirge's syntax_validator.rs and semantic adapters.

Installation

pi install npm:pi-tree-sitter

Git version

pi install git:github.com/markokocic/pi-tree-sitter

Or clone and use locally:

git clone https://github.com/markokocic/pi-tree-sitter.git
cd pi-tree-sitter
npm install
pi install .

Run ad-hoc without installing:

pi -e ./path/to/pi-tree-sitter

Tools

| Tool | Parameters | Description | |------|-----------|-------------| | list_symbols | path?, kind? | List symbols (functions, classes, methods, etc.) in a file or across the project. Parses code with tree-sitter for accurate results. Use this instead of grep when looking for code structure. | | find_definition | name | Find where a SYMBOL (function, class, type, etc.) is DEFINED across the project. Uses tree-sitter for precise structural matching. NOT for finding files by name — use find_files for that. NOT for content search — use grep. | | find_callers | name, path? | Find all call sites of a function or method across the project, with file path and line number. Excludes the definition site. | | find_callees | path, name | Find all functions/methods called by a given symbol, with line number per call site. | | get_symbol_body | path, name | Get the full source code of a named symbol (function, class, method, etc.) from a file. Uses tree-sitter to precisely extract by byte range. |

All tools parse code with tree-sitter on demand — no caching, always fresh.

TUI Rendering

All symbol tools include custom renderCall and renderResult for a polished terminal experience:

  • Tool title shows the tool name and its parameters inline: find_definition — myFunction list_symbols src/file.ts [kind: function]
  • Collapsed (default — press Ctrl+O to expand): compact summary: ✓ 42 symbols across 5 files ✓ 3 definitions for 'myFunction'
  • Expanded (Ctrl+O): full detail output
  • get_symbol_body renders expanded source with syntax highlighting via highlightCode(), auto-detecting the language from the file extension

Write-time validation

The extension hooks write and edit tools. Before content hits disk, it's parsed with the matching tree-sitter grammar. If ERROR or MISSING nodes are found (capped at 10), the tool is blocked with:

Syntax check failed for src/main.rs: 2 error(s) detected by tree-sitter.
Fix and re-submit. (This is a pre-write guard — the file was NOT modified.)
  missing `}` at 42:1: fn main() {
  syntax error at 15:8: let x =

For edit tools, the extension runs the edit tool's own execution in memory (file operations redirected) and validates the result — so the guard always checks exactly what the tool would write. If an oldText matched only a prefix of a line — leaving trailing characters behind after the replacement, a common cause of rejected edits — the block message names that edit and line instead of only showing the resulting syntax error. Edits the edit tool itself would reject with a precise error (text not found, non-unique, overlapping) are left for the tool to report. For languages without WASM grammars, a comment/string-aware delimiter-balance scanner provides fallback validation.

Languages

WASM grammars + symbol tools (21 configs)

| Language | Extensions | Symbols | |----------|-----------|---------| | TypeScript / JavaScript | .ts, .tsx, .mts, .cts, .js, .jsx, .mjs, .cjs | functions, classes, interfaces, types, methods, variables | | Python | .py, .pyi | functions, classes, methods, decorated definitions | | Rust | .rs | functions, structs, enums, traits, impl methods | | Go | .go | functions, methods, structs, interfaces | | Java | .java | classes, interfaces, enums | | C# | .cs | classes, structs, interfaces, enums, methods, namespaces | | Kotlin | .kt, .kts | functions, classes, interfaces, objects, properties | | Ruby | .rb | methods, classes, modules | | PHP | .php | functions, classes, interfaces, traits, methods | | Dart | .dart | functions, classes, mixins, enums, methods, variables | | C | .c, .h | functions, structs, unions, enums | | C++ | .cpp, .cc, .cxx, .hpp, .hh, .hxx | functions, classes, structs, namespaces | | Bash | .sh, .bash | functions | | Clojure / EDN / Babashka / ClojureDart | .clj, .cljs, .cljc, .cljd, .edn, .bb | functions, vars, protocols, records | | Elixir | .ex, .exs | functions, modules, protocols | | Scala | .scala | functions, classes, traits, objects | | Swift | .swift | functions, classes, structs, protocols, enums | | Lua | .lua | functions | | Zig | .zig | functions, variables, containers | | Scheme | .scm, .ss | validation only | | Racket | .rkt | validation only |

WASM validation only (no symbol tools)

| Language | Extensions | |----------|-----------| | Haskell | .hs, .lhs | | CSS | .css | | HTML | .htm, .html | | JSON | .json | | TOML | .toml | | YAML | .yaml, .yml | | Vue | .vue |

Delimiter balance only (no WASM grammar available)

| Language | Extensions | |----------|-----------| | Common Lisp | .lisp, .lsp, .cl | | Emacs Lisp | .el | | Fennel | .fnl | | Janet | .janet, .jdn |

Grammar caching

WASM grammars are fetched from jsDelivr CDN and cached to ~/.cache/pi-tree-sitter/. Each grammar has three files:

  • <wasm> — the WASM binary
  • <wasm>.etag — server ETag for conditional requests
  • <wasm>.date — last-checked timestamp

On every load, the .date file is checked. Only if 30+ days old does the extension revalidate against the CDN using If-None-Match with the stored ETag:

  • 304 Not Modified → touches .date (zero bytes transferred, timer reset)
  • 200 OK → downloads updated grammar, saves new WASM + ETag + date
  • Network error → keeps cache, touches .date (retries in 30 days)

On first download, the bytes are verified with Language.load() before persisting. If cached bytes are ever corrupted, they are deleted and re-downloaded on the next access.

How it works

  1. Write-time validation hooks tool_call events for write and edit
  2. Semantic tools are registered via pi.registerTool() with TypeBox parameter schemas
  3. Each tool parses the relevant file(s) with tree-sitter on demand (no in-memory cache)
  4. Per-language extractors map grammar-specific node types to a unified Symbol kind
  5. Callee queries use tree-sitter S-expression queries for each language

Project structure

pi-tree-sitter/
  index.ts           # Extension entry: write/edit hooks + 5 tool registrations
  src/
    grammar.ts       # LANGUAGE_MAP, WASM loading from CDN, disk cache with ETag
    delimiter.ts     # Comment/string-aware delimiter balance scanner (fallback)
    edit-guard.ts    # In-memory edit simulation via the tool's own execute + prefix-match diagnosis
    languages.ts     # 21 per-language configs: extractors + callee queries
    files.ts         # Recursive project file discovery

License

EPL-2.0 — Copyright 2026 Marko Kocic