Skip to content

astkit is a token-efficient, reproducible structural search/patch toolkit for TypeScript/JavaScript that can be run manually, in CI, or by an agent.

License

Notifications You must be signed in to change notification settings

ClaudiuCeia/astkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

astkit

astkit is a token-efficient, reproducible structural search/patch toolkit for TypeScript/JavaScript that can be run manually, in CI, or by an agent. It operates on AST structure, TypeScript type services, and reference graphs.

What astkit provides

  • Definition and reference navigation via the TypeScript language service
  • Structural search and rewrite using AST-shaped patterns
  • Reference-based symbol ranking as an impact heuristic

Non-Goals

astkit does not:

  • infer program intent or meaning
  • perform whole-program flow analysis
  • prove correctness or enforce architecture
  • replace the TypeScript compiler or type checker
  • make decisions automatically
  • guarantee behavioral equivalence after rewrites

Install

npm install --save-dev @claudiu-ceia/astkit typescript

astkit uses the project's typescript installation for type services.

You can also install individual tools:

npm install --save-dev @claudiu-ceia/sgrep
npm install --save-dev @claudiu-ceia/spatch
npm install --save-dev @claudiu-ceia/nav typescript

Run

npx @claudiu-ceia/astkit <command> [args]

Or via the bin entry:

astkit <command> [args]

Install Skill (Codex)

From an installed npm package:

npx skills@latest add ./node_modules/@claudiu-ceia/astkit/skills/astkit-tooling -a codex -y

From this repository:

npm run skill:install

CLI Reference

General help:

astkit --help
astkit <command> --help

Full command surface:

astkit nav declarations <file>
astkit nav definition <location>
astkit nav references <location>
astkit search [--json] [--no-color] [--no-isomorphisms] [--cwd <path>] <pattern-input> [scope]
astkit patch [--interactive] [--json] [--no-color] [--dry-run] [--cwd <path>] <patch-input> [scope]
astkit code-rank [--json] [--limit <n>] [--cwd <path>] [scope]

nav

astkit nav declarations <file>
astkit nav definition <location>
astkit nav references <location>

<location> format:

  • path/to/file.ts:120:17

Line and character are 1-indexed.

Mock execution:

$ astkit nav declarations src/__tests__/fixtures/simple.ts
{
  "file": "src/__tests__/fixtures/simple.ts",
  "declarations": [
    {
      "name": "User",
      "kind": "interface",
      "signature": "User",
      "line": 1
    },
    {
      "name": "UserService",
      "kind": "class",
      "signature": "UserService",
      "line": 7
    }
  ]
}

$ astkit nav definition src/__tests__/fixtures/importer.ts:1:15
{
  "symbol": "User",
  "definitions": [
    {
      "file": "src/__tests__/fixtures/simple.ts",
      "line": 1,
      "character": 18,
      "kind": "interface",
      "containerName": "\".../simple\""
    }
  ]
}

$ astkit nav references src/__tests__/fixtures/simple.ts:1:18
{
  "symbol": "interface User",
  "definition": {
    "file": "src/__tests__/fixtures/simple.ts",
    "line": 1,
    "character": 18
  },
  "references": [
    {
      "file": "src/__tests__/fixtures/simple.ts",
      "line": 1,
      "character": 18,
      "isDefinition": true,
      "isWriteAccess": true
    },
    {
      "file": "src/__tests__/fixtures/importer.ts",
      "line": 1,
      "character": 15,
      "isDefinition": false,
      "isWriteAccess": true
    }
  ]
}

search (sgrep)

astkit search <pattern-input> [scope] [--cwd <path>] [--no-color] [--no-isomorphisms] [--json]
  • Default output is compact, file-grouped text
  • In interactive terminals, captures are colorized
  • --no-color disables coloring
  • Isomorphism expansion is enabled by default (commutative binary operators, object-literal key order, redundant parentheses)
  • --no-isomorphisms disables isomorphism expansion
  • --json prints structured result

Examples:

# inline pattern
astkit search 'const :[name] = :[value];' src

# pattern loaded from file
astkit search rules/find-const.sgrep src --cwd /repo

# machine output
astkit search --json 'const :[name] = :[value];' src

Mock execution:

$ astkit search 'const :[name] = :[value];' src
//src/example.ts
12: const foo = 42;
27: const bar = makeValue( ...

$ astkit search --json 'const :[name] = :[value];' src
{
  "scope": "/repo/src",
  "pattern": "const :[name] = :[value];",
  "filesScanned": 24,
  "filesMatched": 2,
  "totalMatches": 3,
  "files": [
    {
      "file": "src/example.ts",
      "matchCount": 2,
      "matches": [
        {
          "line": 12,
          "character": 1,
          "matched": "const foo = 42;",
          "captures": {
            "name": "foo",
            "value": "42"
          }
        }
      ]
    }
  ]
}

patch (spatch)

astkit patch <patch-input> [scope] [--cwd <path>] [--dry-run] [--json] [--no-color] [--interactive]
  • patch-input can be inline patch text or a file path
  • Patch format uses +/-/context lines in one document
  • Default output is compact diff-style text
  • --json prints structured output
  • --no-color disables color in compact output
  • --interactive lets you accept/reject each match

Example:

astkit patch $'-const :[name] = :[value];\n+let :[name] = :[value];' src

Notes:

  • In bash/zsh, $'...' enables \n escapes for multi-line patch documents. Alternatively, pass a patch file path as <patch-input>.

Mock execution:

$ astkit patch --dry-run $'-const :[name] = :[value];\n+let :[name] = :[value];' src
diff --git a/src/example.ts b/src/example.ts
--- a/src/example.ts
+++ b/src/example.ts
@@ -12,1 +12,1 @@
-const foo = 42;
+let foo = 42;
1 file changed, 1 replacement, (dry-run)

$ astkit patch --interactive $'-const :[name] = :[value];\n+let :[name] = :[value];' src
------------------------------------------------------------------------
Change 1/2: src/example.ts:12
@@ -12,1 +12,1 @@
-const foo = 42;
+let foo = 42;
Choice [y/n/a/q] (default: n): y

code-rank

astkit code-rank [scope] [--cwd <path>] [--limit <n>] [--json]
  • Ranks exported symbols by TypeScript reference strength
  • Uses the TypeScript language service (findReferences)
  • Default output is compact, one symbol per line
  • --json prints structured output

Example:

astkit code-rank src --limit 20

Mock execution:

$ astkit code-rank src --limit 3
1. score=14 refs=3 ext=3 files=2 function hot src/a.ts:1:8
2. score=9 refs=2 ext=2 files=1 function warm src/a.ts:5:8
3. score=6 refs=1 ext=1 files=1 interface User src/model.ts:1:18

$ astkit code-rank src --limit 1 --json
{
  "scope": "/repo/src",
  "symbolsRanked": 1,
  "symbols": [
    {
      "symbol": "hot",
      "kind": "function",
      "file": "src/a.ts",
      "line": 1,
      "character": 8,
      "score": 14,
      "referenceCount": 3
    }
  ]
}

Structural Pattern Syntax

Both search and patch use the same hole/metavariable syntax:

  • :[name]
  • :[_] anonymous hole (ignored in captures)
  • :[name~regex] regex-constrained hole
  • ... variadic wildcard (matches balanced text and can be reused in replacement)

Repeated named holes enforce equality:

:[x] + :[x]

This matches foo + foo but not foo + bar.

Hole captures are structurally balanced (brackets/strings/comments), which helps avoid malformed partial matches.

Output Examples

Default compact search output:

//src/example.ts
12: const foo = 42;
34: const bar = compute( ...

JSON search output (--json) includes:

  • files scanned/matched
  • total matches
  • byte spans
  • line/character
  • captures

patch --json includes structured match and replacement stats per file.

Programmatic API

Root exports:

  • patchProject from src/spatch
  • searchProject from src/sgrep
  • rankCode from src/code-rank
import { patchProject, rankCode, searchProject } from "@claudiu-ceia/astkit";

See detailed internals:

  • src/spatch/README.md
  • src/sgrep/README.md

Development

Run local CLI:

bun run astkit -- <command> [args]

Build distributable output:

npm run build

Run tests:

bun test

Run typecheck:

npm run typecheck

Preview npm package contents:

npm run pack:check

Install this repo's skill locally for Codex:

npm run skill:install

Code Organization

  • src/nav/*: TypeScript language-service navigation commands
  • src/sgrep/*: search pipeline (parse -> search -> output)
  • src/spatch/*: patch pipeline (parse -> rewrite -> output)
  • src/pattern/*: shared structural parser/matcher/renderer
  • src/common/*: shared helpers (for example inline-or-file text resolution)

About

astkit is a token-efficient, reproducible structural search/patch toolkit for TypeScript/JavaScript that can be run manually, in CI, or by an agent.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •