toji 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. toji-0.1.2/.github/workflows/release.yml +56 -0
  2. toji-0.1.2/.gitignore +14 -0
  3. toji-0.1.2/CHANGELOG.md +43 -0
  4. toji-0.1.2/PKG-INFO +100 -0
  5. toji-0.1.2/README.md +88 -0
  6. toji-0.1.2/SKILL.md +98 -0
  7. toji-0.1.2/pyproject.toml +54 -0
  8. toji-0.1.2/src/toji/__init__.py +3 -0
  9. toji-0.1.2/src/toji/cli.py +433 -0
  10. toji-0.1.2/src/toji/extract.py +440 -0
  11. toji-0.1.2/src/toji/graph.py +330 -0
  12. toji-0.1.2/src/toji/indexer.py +110 -0
  13. toji-0.1.2/src/toji/languages.py +42 -0
  14. toji-0.1.2/src/toji/models.py +48 -0
  15. toji-0.1.2/src/toji/queries/__init__.py +1 -0
  16. toji-0.1.2/src/toji/queries/js.scm +45 -0
  17. toji-0.1.2/src/toji/queries/python.scm +33 -0
  18. toji-0.1.2/src/toji/queries/tsjs.scm +72 -0
  19. toji-0.1.2/src/toji/store.py +162 -0
  20. toji-0.1.2/src/toji/walker.py +86 -0
  21. toji-0.1.2/tests/fixtures/demo/.env.local +1 -0
  22. toji-0.1.2/tests/fixtures/demo/.gitignore +1 -0
  23. toji-0.1.2/tests/fixtures/demo/env/lib/site.py +2 -0
  24. toji-0.1.2/tests/fixtures/demo/node_modules/dep/index.ts +1 -0
  25. toji-0.1.2/tests/fixtures/demo/pyapp/__init__.py +1 -0
  26. toji-0.1.2/tests/fixtures/demo/pyapp/cli.py +5 -0
  27. toji-0.1.2/tests/fixtures/demo/pyapp/main.py +14 -0
  28. toji-0.1.2/tests/fixtures/demo/pyapp/util.py +6 -0
  29. toji-0.1.2/tests/fixtures/demo/pyapp/worker.py +6 -0
  30. toji-0.1.2/tests/fixtures/demo/skipped.md +1 -0
  31. toji-0.1.2/tests/fixtures/demo/tsapp/index.ts +13 -0
  32. toji-0.1.2/tests/fixtures/demo/tsapp/util.ts +7 -0
  33. toji-0.1.2/tests/fixtures/demo/venv/lib/site.py +2 -0
  34. toji-0.1.2/tests/test_toji.py +314 -0
  35. toji-0.1.2/uv.lock +1112 -0
@@ -0,0 +1,56 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: write # semantic-release: version commit + tag + GitHub release
9
+ id-token: write # PyPI trusted publishing (OIDC)
10
+
11
+ concurrency:
12
+ group: release-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ release:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with:
21
+ fetch-depth: 0 # full history: PSR needs tags to compute the next version
22
+ token: ${{ secrets.GH_RELEASE_TOKEN || github.token }}
23
+
24
+ - uses: astral-sh/setup-uv@v5
25
+ with:
26
+ python-version: "3.13"
27
+
28
+ - name: Install
29
+ run: uv sync --dev
30
+
31
+ - name: Test
32
+ run: uv run pytest -q
33
+ - name: Semantic release
34
+ env:
35
+ GH_TOKEN: ${{ secrets.GH_RELEASE_TOKEN || github.token }}
36
+ PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
37
+ run: |
38
+ uv run semantic-release version
39
+ if git describe --tags --exact-match HEAD 2>/dev/null; then
40
+ uv build
41
+ if [ -n "$PYPI_TOKEN" ]; then
42
+ uv publish --token "$PYPI_TOKEN"
43
+ else
44
+ echo "PYPI_TOKEN not set - skipping PyPI publish"
45
+ fi
46
+ else
47
+ echo "No version change - skipping build/publish"
48
+ fi
49
+
50
+ - name: Upload dist artifacts
51
+ if: always()
52
+ uses: actions/upload-artifact@v4
53
+ with:
54
+ name: dist
55
+ path: dist/
56
+ retention-days: 14
toji-0.1.2/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ # python
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+
9
+ # tooling
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+
13
+ # toji's own index
14
+ .toji/
@@ -0,0 +1,43 @@
1
+ # CHANGELOG
2
+
3
+
4
+
5
+ ## v0.1.2 (2026-08-22)
6
+
7
+ ### Fix
8
+
9
+ * fix(release): pass pypi token to uv publish ([`894aac2`](https://github.com/mr-jones123/toji/commit/894aac2ea83946b5f22ccf62e0ab4b3660aa0e59))
10
+
11
+
12
+ ## v0.1.1 (2026-08-22)
13
+
14
+ ### Fix
15
+
16
+ * fix(release): enable pypi publishing ([`943119b`](https://github.com/mr-jones123/toji/commit/943119bf4705226ef8d9f846611a0807b779ab5b))
17
+
18
+ ### Unknown
19
+
20
+ * Update README.md ([`bf76e79`](https://github.com/mr-jones123/toji/commit/bf76e7942080e1b92a881acc64e282af017e5704))
21
+
22
+
23
+ ## v0.1.0 (2026-08-22)
24
+
25
+ ### Chore
26
+
27
+ * chore: restore version field clobbered during packaging edits ([`0ef59ab`](https://github.com/mr-jones123/toji/commit/0ef59abbe09433e6fe843ca199b202de8f6d3864))
28
+
29
+ ### Ci
30
+
31
+ * ci: fix invalid semantic-release flag, skip publish without token ([`bb71603`](https://github.com/mr-jones123/toji/commit/bb71603119aef854772bc29a4303b5c55e30fca7))
32
+
33
+ ### Documentation
34
+
35
+ * docs: add README with badges and usage; package readme for PyPI ([`1be5cd0`](https://github.com/mr-jones123/toji/commit/1be5cd03f0ec12433a7bef1fad686bf83e3ac8a5))
36
+
37
+ ### Feature
38
+
39
+ * feat: codebase graph memory with evidence CLI (v0.1.0) ([`8d84931`](https://github.com/mr-jones123/toji/commit/8d849311a70d396ab7e8cbc68bb3cea7bcfe84ba))
40
+
41
+ ### Fix
42
+
43
+ * fix(release): use angular commit parser name for python-semantic-release ([`0af8d30`](https://github.com/mr-jones123/toji/commit/0af8d30c645d7933890d11c74bcecd2a8fedf24e))
toji-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.5
2
+ Name: toji
3
+ Version: 0.1.2
4
+ Requires-Python: >=3.11
5
+ Requires-Dist: pathspec>=0.12
6
+ Requires-Dist: rich>=15.0.0
7
+ Requires-Dist: tree-sitter-javascript>=0.23
8
+ Requires-Dist: tree-sitter-python>=0.23
9
+ Requires-Dist: tree-sitter-typescript>=0.23
10
+ Requires-Dist: tree-sitter<0.26,>=0.23
11
+ Description-Content-Type: text/markdown
12
+
13
+ # toji
14
+
15
+ > Codebase graph memory: index structure once, answer with evidence forever.
16
+
17
+ [![PyPI](https://img.shields.io/pypi/v/toji)](https://pypi.org/project/toji/)
18
+ [![Python](https://img.shields.io/pypi/pyversions/toji)](https://pypi.org/project/toji/)
19
+ [![Release](https://github.com/mr-jones123/toji/actions/workflows/release.yml/badge.svg)](https://github.com/mr-jones123/toji/actions/workflows/release.yml)
20
+ [![License](https://img.shields.io/badge/license-unreleased-lightgrey)]()
21
+
22
+ toji parses your codebase (Python, TypeScript, TSX, JavaScript) into a queryable
23
+ graph — symbols, signatures, docstrings, call/import/inherit edges — stored in
24
+ SQLite. No source is stored; `read` always fetches live lines from disk. Awesome no?
25
+
26
+ Built for AI reviewers and anyone tired of skimming ten files to answer
27
+ "who calls this?": every answer carries exact `path:line` evidence, ambiguous
28
+ names are surfaced instead of guessed, and unresolved calls are reported as
29
+ unknown rather than invented.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install toji # or: uv tool install toji
35
+ ```
36
+
37
+ Or install as an agent skill (instructions for AI coding agents):
38
+
39
+ ```bash
40
+ npx skills add mr-jones123/toji
41
+ ```
42
+
43
+ ## Quickstart
44
+
45
+ ```bash
46
+ toji index . # index current directory -> .toji/graph.db
47
+ toji map src/ # skeleton of a module: symbols, signatures, docstrings
48
+ toji find "classify" # regex search over symbol names
49
+ toji callers classify_change # who calls it, with file:line evidence
50
+ toji blast classify_change # BFS blast radius: what a change affects, hop-ranked
51
+ toji read classify_change # the symbol's actual source lines
52
+ ```
53
+
54
+ Reindexing is incremental and content-hashed: only changed files re-parse.
55
+ A full 12k-file monorepo indexes in ~40s; unchanged reindex scans are sub-second.
56
+
57
+ ## Commands
58
+
59
+ | Command | Evidence returned |
60
+ |---|---|
61
+ | `index [PATH] [--force]` | build/rebuild the graph (incremental by content hash) |
62
+ | `map [FILE\|SYM]` | file skeleton or symbol detail |
63
+ | `find <regex>` | matching symbols |
64
+ | `calls <sym>` | forward call edges + unresolved callees |
65
+ | `callers <sym>` | reverse call edges (1 hop) |
66
+ | `blast <sym> [--depth N] [--forward]` | affected symbols across calls/contains/inherits |
67
+ | `deps <file>` | import edges both directions, resolved to files |
68
+ | `read <sym>` | the symbol's live source lines from disk |
69
+ | `stats` | index size, resolution quality metrics |
70
+
71
+ Every command accepts `--json` for stable machine-readable output.
72
+
73
+ ## How resolution works
74
+
75
+ Call edges store the callee *as written* (`obj.method`, `helper`). At query
76
+ time they resolve through file-local scopes, the importing file's own imports,
77
+ then global unique suffix/bare-name matches:
78
+
79
+ - **Confident** matches resolve with the exact call-site line attached.
80
+ - **Ambiguous** names list every candidate instead of guessing.
81
+ - **Unresolved** calls (stdlib, dynamic dispatch) are counted and shown —
82
+ never fabricated. `toji stats` reports the ratio so you know what the graph
83
+ is confident about.
84
+
85
+ `blast` and `callers` merge same-named definitions (e.g. a method implemented
86
+ by several cloud adapters) and traverse from all of them, reporting the count;
87
+ `read`, `calls`, and `map` require a single symbol and will ask you to
88
+ disambiguate instead.
89
+
90
+ ## Releasing
91
+
92
+ Conventional Commits drive versions automatically on push to `main`
93
+ (`fix:` → patch, `feat:` → minor, `BREAKING CHANGE:` → major). The release
94
+ workflow tests, bumps the version, generates the changelog, tags, builds, and
95
+ publishes to PyPI. Configure either PyPI trusted publishing or a `PYPI_TOKEN`
96
+ secret to enable publishing.
97
+
98
+ ## License
99
+
100
+ TBD.
toji-0.1.2/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # toji
2
+
3
+ > Codebase graph memory: index structure once, answer with evidence forever.
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/toji)](https://pypi.org/project/toji/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/toji)](https://pypi.org/project/toji/)
7
+ [![Release](https://github.com/mr-jones123/toji/actions/workflows/release.yml/badge.svg)](https://github.com/mr-jones123/toji/actions/workflows/release.yml)
8
+ [![License](https://img.shields.io/badge/license-unreleased-lightgrey)]()
9
+
10
+ toji parses your codebase (Python, TypeScript, TSX, JavaScript) into a queryable
11
+ graph — symbols, signatures, docstrings, call/import/inherit edges — stored in
12
+ SQLite. No source is stored; `read` always fetches live lines from disk. Awesome no?
13
+
14
+ Built for AI reviewers and anyone tired of skimming ten files to answer
15
+ "who calls this?": every answer carries exact `path:line` evidence, ambiguous
16
+ names are surfaced instead of guessed, and unresolved calls are reported as
17
+ unknown rather than invented.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install toji # or: uv tool install toji
23
+ ```
24
+
25
+ Or install as an agent skill (instructions for AI coding agents):
26
+
27
+ ```bash
28
+ npx skills add mr-jones123/toji
29
+ ```
30
+
31
+ ## Quickstart
32
+
33
+ ```bash
34
+ toji index . # index current directory -> .toji/graph.db
35
+ toji map src/ # skeleton of a module: symbols, signatures, docstrings
36
+ toji find "classify" # regex search over symbol names
37
+ toji callers classify_change # who calls it, with file:line evidence
38
+ toji blast classify_change # BFS blast radius: what a change affects, hop-ranked
39
+ toji read classify_change # the symbol's actual source lines
40
+ ```
41
+
42
+ Reindexing is incremental and content-hashed: only changed files re-parse.
43
+ A full 12k-file monorepo indexes in ~40s; unchanged reindex scans are sub-second.
44
+
45
+ ## Commands
46
+
47
+ | Command | Evidence returned |
48
+ |---|---|
49
+ | `index [PATH] [--force]` | build/rebuild the graph (incremental by content hash) |
50
+ | `map [FILE\|SYM]` | file skeleton or symbol detail |
51
+ | `find <regex>` | matching symbols |
52
+ | `calls <sym>` | forward call edges + unresolved callees |
53
+ | `callers <sym>` | reverse call edges (1 hop) |
54
+ | `blast <sym> [--depth N] [--forward]` | affected symbols across calls/contains/inherits |
55
+ | `deps <file>` | import edges both directions, resolved to files |
56
+ | `read <sym>` | the symbol's live source lines from disk |
57
+ | `stats` | index size, resolution quality metrics |
58
+
59
+ Every command accepts `--json` for stable machine-readable output.
60
+
61
+ ## How resolution works
62
+
63
+ Call edges store the callee *as written* (`obj.method`, `helper`). At query
64
+ time they resolve through file-local scopes, the importing file's own imports,
65
+ then global unique suffix/bare-name matches:
66
+
67
+ - **Confident** matches resolve with the exact call-site line attached.
68
+ - **Ambiguous** names list every candidate instead of guessing.
69
+ - **Unresolved** calls (stdlib, dynamic dispatch) are counted and shown —
70
+ never fabricated. `toji stats` reports the ratio so you know what the graph
71
+ is confident about.
72
+
73
+ `blast` and `callers` merge same-named definitions (e.g. a method implemented
74
+ by several cloud adapters) and traverse from all of them, reporting the count;
75
+ `read`, `calls`, and `map` require a single symbol and will ask you to
76
+ disambiguate instead.
77
+
78
+ ## Releasing
79
+
80
+ Conventional Commits drive versions automatically on push to `main`
81
+ (`fix:` → patch, `feat:` → minor, `BREAKING CHANGE:` → major). The release
82
+ workflow tests, bumps the version, generates the changelog, tags, builds, and
83
+ publishes to PyPI. Configure either PyPI trusted publishing or a `PYPI_TOKEN`
84
+ secret to enable publishing.
85
+
86
+ ## License
87
+
88
+ TBD.
toji-0.1.2/SKILL.md ADDED
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: toji
3
+ description: 'Use when you need to understand a codebase, answer questions about callers, callees, imports, estimate blast radius of a change, or review code with evidence instead of guessing. toji indexes code structure (symbols, signatures, docstrings, call/import/inherit edges) into a queryable graph; no source is stored. Triggers: "who calls X", "what breaks if I change X", "map this module", "review this PR with evidence", "how do A and B connect".'
4
+ ---
5
+
6
+ # toji — codebase graph memory
7
+
8
+ Index a codebase once, then answer structural questions with exact `file:line`
9
+ evidence — no file-by-file skimming.
10
+
11
+ ## When to use
12
+
13
+ Use toji instead of reading files directly when the question is structural:
14
+ where a symbol is defined, who calls it, what it calls, what imports what, or
15
+ what a change breaks. After toji narrows you to the relevant lines, use
16
+ `toji read` (or the file) for the actual source.
17
+
18
+ ## CLI availability
19
+
20
+ The `toji` command must be installed on the machine:
21
+
22
+ ```bash
23
+ pip install toji # published package
24
+ uv tool install toji # or as a standalone tool
25
+ ```
26
+
27
+ If the command is missing, run one of the above (or build from source with
28
+ `uv tool install .`).
29
+
30
+ ## Workflow
31
+
32
+ 1. **Index first.** If `<root>/.toji/graph.db` does not exist (or code changed
33
+ since), run:
34
+
35
+ ```bash
36
+ toji index [PATH] # default: current directory
37
+ ```
38
+
39
+ Reindexing is incremental and content-hashed: only changed files re-parse.
40
+ The index lives at `<PATH>/.toji/graph.db`; pass `--db <path>` to point
41
+ any query at a specific index.
42
+
43
+ 2. **Find the symbol** (regex over symbol names/qualnames):
44
+
45
+ ```bash
46
+ toji find <regex> # -> path:line kind qualname rows
47
+ ```
48
+
49
+ 3. **Answer structural questions:**
50
+
51
+ | Command | Evidence returned |
52
+ |---|---|
53
+ | `toji map [FILE\|SYM]` | file skeleton (signatures + docstrings) or symbol detail |
54
+ | `toji callers <sym>` | who calls it (1 hop, reverse) |
55
+ | `toji calls <sym>` | what it calls + unresolved callees |
56
+ | `toji blast <sym> [--depth N] [--forward]` | BFS blast radius: affected symbols, hop-ranked, each with the exact call-site line |
57
+ | `toji deps <file>` | import edges both directions, resolved to files |
58
+ | `toji read <sym>` | the symbol's actual source lines from disk (def line highlighted) |
59
+ | `toji stats` | index size + unresolved-call count |
60
+
61
+ 4. **Read only what matters.** `toji read <sym> [--context N]` prints the exact
62
+ line range; that is the source of truth for behavior claims.
63
+
64
+ ## Evidence contract
65
+
66
+ - **Cite what you verified.** Every `calls`/`callers`/`blast`/`deps` result
67
+ carries `path:line` — when you make a claim from it, keep that reference.
68
+ When you need the body, `read` it before asserting behavior.
69
+ - **Unresolved means unknown.** toji stores callees as written text and
70
+ resolves them heuristically (exact name -> unique suffix -> unique bare
71
+ name). Calls it cannot resolve are listed explicitly as `unresolved` —
72
+ never treat them as facts, and never invent what they might be.
73
+ - **Ambiguity handling.** `read`, `calls`, and `map` require a single symbol:
74
+ an ambiguous name errors and lists every candidate with `path:line` —
75
+ disambiguate with the full qualname or a `find` result. `blast` and
76
+ `callers` instead merge all same-named definitions (e.g. a method
77
+ implemented by several adapters) and traverse from every one, reporting
78
+ the count in the header (`across N definitions`). Same-name merging is
79
+ exhaustive, never a guess.
80
+ - **`--json` for machine use.** Every command supports `--json` and emits
81
+ stable structured output (`{path, line, kind, qualname, ...}`) suitable for
82
+ parsing; omit it for human-readable rich tables.
83
+ - **Blast radius direction.** `blast` is reverse by default (callers,
84
+ containers, subclasses — what a change affects). `--forward` adds callees.
85
+ `--depth` caps hops; large graphs truncate at `--max-nodes` (default 200)
86
+ with an explicit notice.
87
+ - **No source is stored.** Signatures and docstrings yes; bodies no. `read`
88
+ always fetches live source — if the file changed since indexing, reindex
89
+ (`toji index`) to refresh line numbers.
90
+
91
+ ## Model limitations (state them, don't hide them)
92
+
93
+ - Call resolution is name-based, not type-aware. Dynamic dispatch, factories,
94
+ and same-named symbols in different modules are handled conservatively:
95
+ unresolved or ambiguous, never guessed.
96
+ - TS/JS docstrings are not captured (Python only).
97
+ - `import * as X` (TS namespace imports) and star re-exports resolve as
98
+ module edges, not per-symbol edges.
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "toji"
3
+ readme = "README.md"
4
+ version = "0.1.2"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "tree-sitter>=0.23,<0.26",
8
+ "tree-sitter-python>=0.23",
9
+ "tree-sitter-javascript>=0.23",
10
+ "tree-sitter-typescript>=0.23",
11
+ "pathspec>=0.12",
12
+ "rich>=15.0.0",
13
+ ]
14
+
15
+ [project.scripts]
16
+ toji = "toji.cli:main"
17
+
18
+ [build-system]
19
+ requires = ["hatchling"]
20
+ build-backend = "hatchling.build"
21
+
22
+ [tool.hatch.build.targets.wheel]
23
+ packages = ["src/toji"]
24
+
25
+ [tool.hatch.build.targets.wheel.force-include]
26
+ "src/toji/queries/python.scm" = "toji/queries/python.scm"
27
+ "src/toji/queries/tsjs.scm" = "toji/queries/tsjs.scm"
28
+ "src/toji/queries/js.scm" = "toji/queries/js.scm"
29
+
30
+ [tool.pytest.ini_options]
31
+ testpaths = ["tests"]
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ "pytest>=9.1.1",
36
+ "python-semantic-release>=9.3.1",
37
+ "twine>=7.0.0",
38
+ ]
39
+
40
+ [tool.semantic_release]
41
+ version_toml = ["pyproject.toml:project.version"]
42
+ tag_format = "v{version}"
43
+ commit_parser = "angular"
44
+ changelog_file = "CHANGELOG.md"
45
+ build_command = "uv build"
46
+ allow_zero_version = true
47
+
48
+ [tool.semantic_release.branches.main]
49
+ match = "main"
50
+
51
+ [tool.semantic_release.publish]
52
+ dist_glob_patterns = ["dist/*"]
53
+ upload_to_vcs_release = true
54
+
@@ -0,0 +1,3 @@
1
+ """toji — codebase graph memory for AI reviewers."""
2
+
3
+ __version__ = "0.1.0"