treemapper 1.6.1__tar.gz → 2.2.0__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 (172) hide show
  1. treemapper-2.2.0/.gitignore +53 -0
  2. treemapper-2.2.0/CHANGELOG.md +64 -0
  3. treemapper-2.2.0/PKG-INFO +120 -0
  4. treemapper-2.2.0/README.md +76 -0
  5. treemapper-2.2.0/pyproject.toml +107 -0
  6. treemapper-2.2.0/src/treemapper/__init__.py +24 -0
  7. treemapper-2.2.0/src/treemapper/__main__.py +6 -0
  8. treemapper-2.2.0/src/treemapper/cli.py +13 -0
  9. treemapper-2.2.0/src/treemapper/mcp_main.py +11 -0
  10. treemapper-2.2.0/src/treemapper/version.py +1 -0
  11. treemapper-2.2.0/tests/conftest.py +59 -0
  12. treemapper-2.2.0/tests/test_api.py +30 -0
  13. treemapper-2.2.0/tests/test_cli.py +82 -0
  14. treemapper-1.6.1/CHANGELOG.md +0 -59
  15. treemapper-1.6.1/PKG-INFO +0 -329
  16. treemapper-1.6.1/README.md +0 -253
  17. treemapper-1.6.1/diffctx/Cargo.lock +0 -1651
  18. treemapper-1.6.1/diffctx/Cargo.toml +0 -174
  19. treemapper-1.6.1/diffctx/src/analytics.rs +0 -791
  20. treemapper-1.6.1/diffctx/src/candidate_files.rs +0 -86
  21. treemapper-1.6.1/diffctx/src/config/analytics.rs +0 -17
  22. treemapper-1.6.1/diffctx/src/config/bm25.rs +0 -21
  23. treemapper-1.6.1/diffctx/src/config/budget.rs +0 -21
  24. treemapper-1.6.1/diffctx/src/config/category_weights.rs +0 -117
  25. treemapper-1.6.1/diffctx/src/config/edge_weights.rs +0 -246
  26. treemapper-1.6.1/diffctx/src/config/env_overrides.rs +0 -125
  27. treemapper-1.6.1/diffctx/src/config/extensions.rs +0 -134
  28. treemapper-1.6.1/diffctx/src/config/filtering.rs +0 -38
  29. treemapper-1.6.1/diffctx/src/config/fragmentation.rs +0 -17
  30. treemapper-1.6.1/diffctx/src/config/git.rs +0 -23
  31. treemapper-1.6.1/diffctx/src/config/graph_filtering.rs +0 -23
  32. treemapper-1.6.1/diffctx/src/config/importance.rs +0 -93
  33. treemapper-1.6.1/diffctx/src/config/limits.rs +0 -152
  34. treemapper-1.6.1/diffctx/src/config/mod.rs +0 -21
  35. treemapper-1.6.1/diffctx/src/config/mode.rs +0 -45
  36. treemapper-1.6.1/diffctx/src/config/needs.rs +0 -63
  37. treemapper-1.6.1/diffctx/src/config/parsers.rs +0 -27
  38. treemapper-1.6.1/diffctx/src/config/render.rs +0 -15
  39. treemapper-1.6.1/diffctx/src/config/scoring.rs +0 -21
  40. treemapper-1.6.1/diffctx/src/config/selection.rs +0 -81
  41. treemapper-1.6.1/diffctx/src/config/tokenization.rs +0 -19
  42. treemapper-1.6.1/diffctx/src/config/weights.rs +0 -364
  43. treemapper-1.6.1/diffctx/src/core.rs +0 -209
  44. treemapper-1.6.1/diffctx/src/discovery.rs +0 -320
  45. treemapper-1.6.1/diffctx/src/edges/base.rs +0 -294
  46. treemapper-1.6.1/diffctx/src/edges/config_edges/build_system.rs +0 -171
  47. treemapper-1.6.1/diffctx/src/edges/config_edges/cicd.rs +0 -323
  48. treemapper-1.6.1/diffctx/src/edges/config_edges/docker.rs +0 -266
  49. treemapper-1.6.1/diffctx/src/edges/config_edges/generic.rs +0 -290
  50. treemapper-1.6.1/diffctx/src/edges/config_edges/helm.rs +0 -342
  51. treemapper-1.6.1/diffctx/src/edges/config_edges/kubernetes.rs +0 -517
  52. treemapper-1.6.1/diffctx/src/edges/config_edges/mod.rs +0 -19
  53. treemapper-1.6.1/diffctx/src/edges/document/mod.rs +0 -153
  54. treemapper-1.6.1/diffctx/src/edges/history/cochange.rs +0 -132
  55. treemapper-1.6.1/diffctx/src/edges/history/mod.rs +0 -7
  56. treemapper-1.6.1/diffctx/src/edges/mod.rs +0 -137
  57. treemapper-1.6.1/diffctx/src/edges/semantic/ansible.rs +0 -206
  58. treemapper-1.6.1/diffctx/src/edges/semantic/bazel.rs +0 -268
  59. treemapper-1.6.1/diffctx/src/edges/semantic/c_family.rs +0 -387
  60. treemapper-1.6.1/diffctx/src/edges/semantic/cargo_edges.rs +0 -237
  61. treemapper-1.6.1/diffctx/src/edges/semantic/clojure.rs +0 -181
  62. treemapper-1.6.1/diffctx/src/edges/semantic/css.rs +0 -73
  63. treemapper-1.6.1/diffctx/src/edges/semantic/dart.rs +0 -278
  64. treemapper-1.6.1/diffctx/src/edges/semantic/dbt.rs +0 -146
  65. treemapper-1.6.1/diffctx/src/edges/semantic/dotnet.rs +0 -380
  66. treemapper-1.6.1/diffctx/src/edges/semantic/elixir.rs +0 -165
  67. treemapper-1.6.1/diffctx/src/edges/semantic/erlang.rs +0 -154
  68. treemapper-1.6.1/diffctx/src/edges/semantic/go.rs +0 -317
  69. treemapper-1.6.1/diffctx/src/edges/semantic/graphql.rs +0 -146
  70. treemapper-1.6.1/diffctx/src/edges/semantic/haskell.rs +0 -291
  71. treemapper-1.6.1/diffctx/src/edges/semantic/javascript.rs +0 -420
  72. treemapper-1.6.1/diffctx/src/edges/semantic/julia.rs +0 -156
  73. treemapper-1.6.1/diffctx/src/edges/semantic/jvm.rs +0 -420
  74. treemapper-1.6.1/diffctx/src/edges/semantic/latex.rs +0 -116
  75. treemapper-1.6.1/diffctx/src/edges/semantic/lua.rs +0 -140
  76. treemapper-1.6.1/diffctx/src/edges/semantic/mod.rs +0 -81
  77. treemapper-1.6.1/diffctx/src/edges/semantic/nim.rs +0 -196
  78. treemapper-1.6.1/diffctx/src/edges/semantic/nix.rs +0 -81
  79. treemapper-1.6.1/diffctx/src/edges/semantic/ocaml.rs +0 -141
  80. treemapper-1.6.1/diffctx/src/edges/semantic/openapi.rs +0 -151
  81. treemapper-1.6.1/diffctx/src/edges/semantic/perl.rs +0 -207
  82. treemapper-1.6.1/diffctx/src/edges/semantic/php.rs +0 -166
  83. treemapper-1.6.1/diffctx/src/edges/semantic/prisma.rs +0 -132
  84. treemapper-1.6.1/diffctx/src/edges/semantic/protobuf.rs +0 -126
  85. treemapper-1.6.1/diffctx/src/edges/semantic/python.rs +0 -357
  86. treemapper-1.6.1/diffctx/src/edges/semantic/r_lang.rs +0 -173
  87. treemapper-1.6.1/diffctx/src/edges/semantic/ruby.rs +0 -140
  88. treemapper-1.6.1/diffctx/src/edges/semantic/rust_lang.rs +0 -491
  89. treemapper-1.6.1/diffctx/src/edges/semantic/shell.rs +0 -125
  90. treemapper-1.6.1/diffctx/src/edges/semantic/sql.rs +0 -133
  91. treemapper-1.6.1/diffctx/src/edges/semantic/swift.rs +0 -150
  92. treemapper-1.6.1/diffctx/src/edges/semantic/tags.rs +0 -65
  93. treemapper-1.6.1/diffctx/src/edges/semantic/terraform.rs +0 -597
  94. treemapper-1.6.1/diffctx/src/edges/semantic/zig.rs +0 -165
  95. treemapper-1.6.1/diffctx/src/edges/similarity/lexical.rs +0 -264
  96. treemapper-1.6.1/diffctx/src/edges/similarity/mod.rs +0 -7
  97. treemapper-1.6.1/diffctx/src/edges/structural/containment.rs +0 -62
  98. treemapper-1.6.1/diffctx/src/edges/structural/mod.rs +0 -13
  99. treemapper-1.6.1/diffctx/src/edges/structural/sibling.rs +0 -89
  100. treemapper-1.6.1/diffctx/src/edges/structural/testing.rs +0 -266
  101. treemapper-1.6.1/diffctx/src/filtering.rs +0 -304
  102. treemapper-1.6.1/diffctx/src/fragmentation.rs +0 -350
  103. treemapper-1.6.1/diffctx/src/git.rs +0 -595
  104. treemapper-1.6.1/diffctx/src/graph.rs +0 -708
  105. treemapper-1.6.1/diffctx/src/graph_export.rs +0 -545
  106. treemapper-1.6.1/diffctx/src/interval.rs +0 -76
  107. treemapper-1.6.1/diffctx/src/languages.rs +0 -335
  108. treemapper-1.6.1/diffctx/src/lib.rs +0 -31
  109. treemapper-1.6.1/diffctx/src/main.rs +0 -87
  110. treemapper-1.6.1/diffctx/src/memory_pipeline.rs +0 -330
  111. treemapper-1.6.1/diffctx/src/mode.rs +0 -96
  112. treemapper-1.6.1/diffctx/src/parsers/config_parser.rs +0 -193
  113. treemapper-1.6.1/diffctx/src/parsers/generic.rs +0 -53
  114. treemapper-1.6.1/diffctx/src/parsers/markdown.rs +0 -105
  115. treemapper-1.6.1/diffctx/src/parsers/mod.rs +0 -142
  116. treemapper-1.6.1/diffctx/src/parsers/tree_sitter_strategy.rs +0 -1702
  117. treemapper-1.6.1/diffctx/src/pipeline.rs +0 -601
  118. treemapper-1.6.1/diffctx/src/postpass.rs +0 -265
  119. treemapper-1.6.1/diffctx/src/ppr.rs +0 -608
  120. treemapper-1.6.1/diffctx/src/project_graph.rs +0 -235
  121. treemapper-1.6.1/diffctx/src/pybridge.rs +0 -727
  122. treemapper-1.6.1/diffctx/src/render.rs +0 -237
  123. treemapper-1.6.1/diffctx/src/scoring.rs +0 -273
  124. treemapper-1.6.1/diffctx/src/select.rs +0 -683
  125. treemapper-1.6.1/diffctx/src/signatures.rs +0 -119
  126. treemapper-1.6.1/diffctx/src/stopwords.rs +0 -990
  127. treemapper-1.6.1/diffctx/src/test_harness.rs +0 -384
  128. treemapper-1.6.1/diffctx/src/tokenizer.rs +0 -34
  129. treemapper-1.6.1/diffctx/src/types.rs +0 -283
  130. treemapper-1.6.1/diffctx/src/utility/boltzmann.rs +0 -253
  131. treemapper-1.6.1/diffctx/src/utility/importance.rs +0 -142
  132. treemapper-1.6.1/diffctx/src/utility/mod.rs +0 -9
  133. treemapper-1.6.1/diffctx/src/utility/needs.rs +0 -700
  134. treemapper-1.6.1/diffctx/src/utility/scoring.rs +0 -641
  135. treemapper-1.6.1/diffctx/tests/common/mod.rs +0 -274
  136. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_api.py +0 -31
  137. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_constants.py +0 -11
  138. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_handlers.py +0 -27
  139. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_models.py +0 -25
  140. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_module.js +0 -23
  141. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_services.py +0 -37
  142. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_types.py +0 -31
  143. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_unrelated.yaml +0 -8
  144. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_utils.py +0 -31
  145. treemapper-1.6.1/diffctx/tests/fixtures/garbage/garbage_validators.py +0 -23
  146. treemapper-1.6.1/diffctx/tests/yaml_cases.rs +0 -279
  147. treemapper-1.6.1/pyproject.toml +0 -299
  148. treemapper-1.6.1/rust-toolchain.toml +0 -4
  149. treemapper-1.6.1/src/treemapper/__init__.py +0 -98
  150. treemapper-1.6.1/src/treemapper/__main__.py +0 -17
  151. treemapper-1.6.1/src/treemapper/cli.py +0 -468
  152. treemapper-1.6.1/src/treemapper/clipboard.py +0 -81
  153. treemapper-1.6.1/src/treemapper/diffctx/__init__.py +0 -7
  154. treemapper-1.6.1/src/treemapper/diffctx/graph_analytics.py +0 -59
  155. treemapper-1.6.1/src/treemapper/diffctx/graph_export.py +0 -46
  156. treemapper-1.6.1/src/treemapper/diffctx/pipeline.py +0 -108
  157. treemapper-1.6.1/src/treemapper/diffctx/project_graph.py +0 -27
  158. treemapper-1.6.1/src/treemapper/ignore.py +0 -345
  159. treemapper-1.6.1/src/treemapper/logger.py +0 -32
  160. treemapper-1.6.1/src/treemapper/mcp/README.md +0 -104
  161. treemapper-1.6.1/src/treemapper/mcp/__main__.py +0 -4
  162. treemapper-1.6.1/src/treemapper/mcp/formatting.py +0 -9
  163. treemapper-1.6.1/src/treemapper/mcp/security.py +0 -30
  164. treemapper-1.6.1/src/treemapper/mcp/server.py +0 -237
  165. treemapper-1.6.1/src/treemapper/py.typed +0 -0
  166. treemapper-1.6.1/src/treemapper/tokens.py +0 -49
  167. treemapper-1.6.1/src/treemapper/tree.py +0 -279
  168. treemapper-1.6.1/src/treemapper/treemapper.py +0 -292
  169. treemapper-1.6.1/src/treemapper/version.py +0 -1
  170. treemapper-1.6.1/src/treemapper/writer.py +0 -400
  171. {treemapper-1.6.1 → treemapper-2.2.0}/LICENSE +0 -0
  172. {treemapper-1.6.1/src/treemapper/mcp → treemapper-2.2.0/tests}/__init__.py +0 -0
@@ -0,0 +1,53 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # Default output files
30
+ tree.yaml
31
+ tree.json
32
+ tree.md
33
+ tree.txt
34
+
35
+ # Virtual environments
36
+ .venv/
37
+ venv/
38
+ ENV/
39
+
40
+ # Tooling caches
41
+ .pytest_cache/
42
+ .mypy_cache/
43
+ .ruff_cache/
44
+ .hypothesis/
45
+
46
+ # IDE / OS
47
+ .idea/
48
+ .vscode/
49
+ .DS_Store
50
+
51
+ # Local-only planning
52
+ TODO.md
53
+ test-repos
@@ -0,0 +1,64 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2.2.0] - 2026-06-20
11
+
12
+ ### Changed
13
+
14
+ - Bumped the dependency floor to `diffctx>=1.10.0,<2.0`. This pulls in the
15
+ diffctx 1.10 engine: the calibrated default `--tau` of 0.12 (tighter
16
+ diff-context selection by default), the 256 KB MCP file cap, and the
17
+ document/import edge correctness fixes. No treemapper API changes.
18
+
19
+ ## [2.1.0] - 2026-06-14
20
+
21
+ ### Changed
22
+
23
+ - Bumped the dependency floor to `diffctx>=1.9.1,<2.0`. This pulls in the diffctx
24
+ 1.9 diff-context improvements for `treemapper . --diff`: an orientation header
25
+ (`commit_message` + `changed_files`) at the top of every format, a `role:
26
+ changed` marker on fragments overlapping the diff with changed code emitted
27
+ first, context ordered by descending per-file relevance, and merging of
28
+ line-contiguous same-role fragments. The `>=1.9.1` floor also remains a hard
29
+ requirement for the branded `run(prog=…, version=…)` entry — the pre-1.8
30
+ fallback path was removed, so there is no unbranded code path.
31
+ - `treemapper` drives the engine through the public
32
+ `diffctx.run(prog="treemapper", version=…)` entry, so `--help`, `--version`,
33
+ and error prefixes are branded as `treemapper`. The `treemapper-mcp` install
34
+ hint is likewise branded via the engine's `prog`/`extra` parameters.
35
+
36
+ ### Added
37
+
38
+ - GitHub Actions release workflow (`cd.yml`) that builds the pure wheel + sdist
39
+ and publishes to PyPI via OIDC trusted publishing.
40
+
41
+ ## [2.0.0]
42
+
43
+ ### Changed
44
+
45
+ - **TreeMapper is now a thin wrapper over the [`diffctx`](https://pypi.org/project/diffctx/)
46
+ engine.** All directory traversal, serialization, and git-diff context
47
+ selection are delegated to `diffctx` (pinned `>=1.7,<2.0`). TreeMapper itself
48
+ ships only the `treemapper` command, the `treemapper-mcp` server entry point,
49
+ and a Python API that re-exports `map_directory`, `build_diff_context`, and
50
+ the `to_yaml`/`to_json`/`to_text`/`to_markdown` serializers. No engine logic
51
+ is duplicated.
52
+ - Pure-Python wheel (built with hatchling). The native engine arrives through
53
+ the `diffctx` dependency.
54
+
55
+ ### Note
56
+
57
+ Releases `1.0.0` through `1.6.1` shipped TreeMapper as a self-contained package;
58
+ that lineage was renamed to `diffctx` at `diffctx` `1.7.0`. TreeMapper `2.0.0`
59
+ re-establishes the `treemapper` name as the product layer on top of that engine.
60
+
61
+ [Unreleased]: https://github.com/nikolay-e/treemapper/compare/v2.2.0...HEAD
62
+ [2.2.0]: https://github.com/nikolay-e/treemapper/compare/v2.1.0...v2.2.0
63
+ [2.1.0]: https://github.com/nikolay-e/treemapper/compare/v2.0.0...v2.1.0
64
+ [2.0.0]: https://github.com/nikolay-e/treemapper/releases/tag/v2.0.0
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: treemapper
3
+ Version: 2.2.0
4
+ Summary: Map a codebase to YAML/JSON/Markdown/text and select smart git-diff context for LLMs
5
+ Project-URL: Changelog, https://github.com/nikolay-e/treemapper/releases
6
+ Project-URL: Homepage, https://github.com/nikolay-e/treemapper
7
+ Project-URL: Issues, https://github.com/nikolay-e/treemapper/issues
8
+ Project-URL: Repository, https://github.com/nikolay-e/treemapper
9
+ Author-email: Nikolay Eremeev <nikolay.eremeev@outlook.com>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: ai,claude,code-context,codebase,context-selection,diff-context,directory-tree,git-diff,json,llm,mcp,tree,yaml
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Software Development
24
+ Classifier: Topic :: Software Development :: Version Control :: Git
25
+ Classifier: Topic :: Utilities
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Requires-Dist: diffctx<2.0,>=1.10.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy<3.0,>=2.1.0; extra == 'dev'
31
+ Requires-Dist: pre-commit<5.0,>=3.0; extra == 'dev'
32
+ Requires-Dist: pytest-timeout<3.0,>=2.4.0; extra == 'dev'
33
+ Requires-Dist: pytest<10.0,>=7.0; extra == 'dev'
34
+ Requires-Dist: pyyaml<8.0,>=6.0.2; extra == 'dev'
35
+ Requires-Dist: ruff<1.0,>=0.4; extra == 'dev'
36
+ Requires-Dist: types-pyyaml<7.0,>=6.0.12.20260518; extra == 'dev'
37
+ Provides-Extra: full
38
+ Requires-Dist: diffctx[full]<2.0,>=1.10.0; extra == 'full'
39
+ Provides-Extra: mcp
40
+ Requires-Dist: diffctx[mcp]<2.0,>=1.10.0; extra == 'mcp'
41
+ Provides-Extra: tree-sitter
42
+ Requires-Dist: diffctx[tree-sitter]<2.0,>=1.10.0; extra == 'tree-sitter'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # TreeMapper
46
+
47
+ [![PyPI](https://img.shields.io/pypi/v/treemapper)](https://pypi.org/project/treemapper/)
48
+ [![License](https://img.shields.io/pypi/l/treemapper)](https://github.com/nikolay-e/treemapper/blob/main/LICENSE)
49
+
50
+ **Map a codebase into LLM-ready context.** TreeMapper serializes an entire
51
+ directory tree — structure plus file contents — to YAML, JSON, Markdown, or
52
+ text, and selects the minimal smart git-diff context needed to understand a
53
+ change. Paste the output into Claude, ChatGPT, or any LLM.
54
+
55
+ TreeMapper is a thin command-line product built on the
56
+ [`diffctx`](https://pypi.org/project/diffctx/) engine. All traversal,
57
+ serialization, and diff-context selection live in `diffctx`; TreeMapper
58
+ re-exposes them under the `treemapper` name so there is a single source of
59
+ truth and no duplicated logic.
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ pipx install treemapper # recommended: isolated, no venv needed
65
+ pip install treemapper # or with pip
66
+ pip install 'treemapper[tree-sitter]' # + AST parsing for smarter diff context
67
+ pip install 'treemapper[mcp]' # + MCP server for AI assistants
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ ```bash
73
+ treemapper . # map current directory to YAML (stdout)
74
+ treemapper /path/to/project # map a specific directory
75
+ treemapper . -f json # output as JSON
76
+ treemapper . -f md --save # save as tree.md
77
+ treemapper . --no-content # structure only, no file contents
78
+ treemapper . -c # copy output to clipboard
79
+ treemapper . --diff HEAD~1 # smart context for the last commit
80
+ treemapper . --diff main..HEAD # smart context for a branch range
81
+ treemapper graph . # project dependency graph (mermaid)
82
+ ```
83
+
84
+ ### Two modes
85
+
86
+ - **Tree mapping** (`treemapper .`) — walks the directory tree, respects
87
+ hierarchical ignore patterns (`.gitignore`, `.diffctx/ignore`), reads file
88
+ contents with binary/encoding detection, and serializes the result.
89
+ - **Diff context** (`treemapper . --diff`) — analyzes a git diff and selects
90
+ the minimal set of code fragments needed to understand the change, instead
91
+ of dumping whole files.
92
+
93
+ Run `treemapper --help` for the full flag reference.
94
+
95
+ ## Python API
96
+
97
+ ```python
98
+ import treemapper
99
+
100
+ tree = treemapper.map_directory(".", no_content=False)
101
+ print(treemapper.to_yaml(tree))
102
+
103
+ context = treemapper.build_diff_context(root_dir=".", diff_range="HEAD~1")
104
+
105
+ # treemapper.run drives the full branded CLI from Python (same surface as the command)
106
+ treemapper.run(["graph", "."], prog="treemapper", version=treemapper.__version__)
107
+ ```
108
+
109
+ Every run reports an **exact `tiktoken` token count** (not a `chars / 4`
110
+ estimate), so you know the real context cost before you paste.
111
+
112
+ ## Relationship to diffctx
113
+
114
+ TreeMapper is the user-facing distribution; `diffctx` is the reusable engine.
115
+ Pin compatibility is `diffctx>=1.10.0,<2.0`. If you are embedding the engine in
116
+ your own tool, depend on `diffctx` directly.
117
+
118
+ ## License
119
+
120
+ Apache 2.0
@@ -0,0 +1,76 @@
1
+ # TreeMapper
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/treemapper)](https://pypi.org/project/treemapper/)
4
+ [![License](https://img.shields.io/pypi/l/treemapper)](https://github.com/nikolay-e/treemapper/blob/main/LICENSE)
5
+
6
+ **Map a codebase into LLM-ready context.** TreeMapper serializes an entire
7
+ directory tree — structure plus file contents — to YAML, JSON, Markdown, or
8
+ text, and selects the minimal smart git-diff context needed to understand a
9
+ change. Paste the output into Claude, ChatGPT, or any LLM.
10
+
11
+ TreeMapper is a thin command-line product built on the
12
+ [`diffctx`](https://pypi.org/project/diffctx/) engine. All traversal,
13
+ serialization, and diff-context selection live in `diffctx`; TreeMapper
14
+ re-exposes them under the `treemapper` name so there is a single source of
15
+ truth and no duplicated logic.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pipx install treemapper # recommended: isolated, no venv needed
21
+ pip install treemapper # or with pip
22
+ pip install 'treemapper[tree-sitter]' # + AST parsing for smarter diff context
23
+ pip install 'treemapper[mcp]' # + MCP server for AI assistants
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```bash
29
+ treemapper . # map current directory to YAML (stdout)
30
+ treemapper /path/to/project # map a specific directory
31
+ treemapper . -f json # output as JSON
32
+ treemapper . -f md --save # save as tree.md
33
+ treemapper . --no-content # structure only, no file contents
34
+ treemapper . -c # copy output to clipboard
35
+ treemapper . --diff HEAD~1 # smart context for the last commit
36
+ treemapper . --diff main..HEAD # smart context for a branch range
37
+ treemapper graph . # project dependency graph (mermaid)
38
+ ```
39
+
40
+ ### Two modes
41
+
42
+ - **Tree mapping** (`treemapper .`) — walks the directory tree, respects
43
+ hierarchical ignore patterns (`.gitignore`, `.diffctx/ignore`), reads file
44
+ contents with binary/encoding detection, and serializes the result.
45
+ - **Diff context** (`treemapper . --diff`) — analyzes a git diff and selects
46
+ the minimal set of code fragments needed to understand the change, instead
47
+ of dumping whole files.
48
+
49
+ Run `treemapper --help` for the full flag reference.
50
+
51
+ ## Python API
52
+
53
+ ```python
54
+ import treemapper
55
+
56
+ tree = treemapper.map_directory(".", no_content=False)
57
+ print(treemapper.to_yaml(tree))
58
+
59
+ context = treemapper.build_diff_context(root_dir=".", diff_range="HEAD~1")
60
+
61
+ # treemapper.run drives the full branded CLI from Python (same surface as the command)
62
+ treemapper.run(["graph", "."], prog="treemapper", version=treemapper.__version__)
63
+ ```
64
+
65
+ Every run reports an **exact `tiktoken` token count** (not a `chars / 4`
66
+ estimate), so you know the real context cost before you paste.
67
+
68
+ ## Relationship to diffctx
69
+
70
+ TreeMapper is the user-facing distribution; `diffctx` is the reusable engine.
71
+ Pin compatibility is `diffctx>=1.10.0,<2.0`. If you are embedding the engine in
72
+ your own tool, depend on `diffctx` directly.
73
+
74
+ ## License
75
+
76
+ Apache 2.0
@@ -0,0 +1,107 @@
1
+ [build-system]
2
+ build-backend = "hatchling.build"
3
+ requires = [ "hatchling>=1.25,<2.0" ]
4
+
5
+ [project]
6
+ name = "treemapper"
7
+ dynamic = [ "version" ]
8
+ description = "Map a codebase to YAML/JSON/Markdown/text and select smart git-diff context for LLMs"
9
+ readme = "README.md"
10
+ keywords = [
11
+ "ai",
12
+ "claude",
13
+ "code-context",
14
+ "codebase",
15
+ "context-selection",
16
+ "diff-context",
17
+ "directory-tree",
18
+ "git-diff",
19
+ "json",
20
+ "llm",
21
+ "mcp",
22
+ "tree",
23
+ "yaml",
24
+ ]
25
+ license = "Apache-2.0"
26
+ authors = [
27
+ { name = "Nikolay Eremeev", email = "nikolay.eremeev@outlook.com" },
28
+ ]
29
+ requires-python = ">=3.10"
30
+ classifiers = [
31
+ "Development Status :: 5 - Production/Stable",
32
+ "Environment :: Console",
33
+ "Intended Audience :: Developers",
34
+ "Operating System :: OS Independent",
35
+ "Programming Language :: Python :: 3 :: Only",
36
+ "Programming Language :: Python :: 3.10",
37
+ "Programming Language :: Python :: 3.11",
38
+ "Programming Language :: Python :: 3.12",
39
+ "Programming Language :: Python :: 3.13",
40
+ "Programming Language :: Python :: 3.14",
41
+ "Topic :: Software Development",
42
+ "Topic :: Software Development :: Version Control :: Git",
43
+ "Topic :: Utilities",
44
+ "Typing :: Typed",
45
+ ]
46
+ dependencies = [
47
+ "diffctx>=1.10.0,<2.0",
48
+ ]
49
+ optional-dependencies.dev = [
50
+ "mypy>=2.1.0,<3.0",
51
+ "pre-commit>=3.0,<5.0",
52
+ "pytest>=7.0,<10.0",
53
+ "pytest-timeout>=2.4.0,<3.0",
54
+ "pyyaml>=6.0.2,<8.0",
55
+ "ruff>=0.4,<1.0",
56
+ "types-pyyaml>=6.0.12.20260518,<7.0",
57
+ ]
58
+ optional-dependencies.full = [
59
+ "diffctx[full]>=1.10.0,<2.0",
60
+ ]
61
+ optional-dependencies.mcp = [
62
+ "diffctx[mcp]>=1.10.0,<2.0",
63
+ ]
64
+ optional-dependencies.tree-sitter = [
65
+ "diffctx[tree-sitter]>=1.10.0,<2.0",
66
+ ]
67
+ urls.Changelog = "https://github.com/nikolay-e/treemapper/releases"
68
+ urls.Homepage = "https://github.com/nikolay-e/treemapper"
69
+ urls.Issues = "https://github.com/nikolay-e/treemapper/issues"
70
+ urls.Repository = "https://github.com/nikolay-e/treemapper"
71
+ scripts.treemapper = "treemapper.cli:main"
72
+ scripts.treemapper-mcp = "treemapper.mcp_main:main"
73
+
74
+ [tool.hatch.version]
75
+ path = "src/treemapper/version.py"
76
+
77
+ [tool.hatch.build.targets.wheel]
78
+ packages = [ "src/treemapper" ]
79
+
80
+ [tool.hatch.build.targets.sdist]
81
+ include = [
82
+ "src/treemapper",
83
+ "tests",
84
+ "README.md",
85
+ "CHANGELOG.md",
86
+ "LICENSE",
87
+ ]
88
+
89
+ [tool.ruff]
90
+ target-version = "py310"
91
+ line-length = 130
92
+ lint.select = [ "C901", "E", "F", "I", "N", "RUF", "UP", "W" ]
93
+ lint.ignore = [ "E501" ]
94
+
95
+ [tool.pytest.ini_options]
96
+ testpaths = [ "tests" ]
97
+ pythonpath = [ "src" ]
98
+ timeout = 30
99
+
100
+ [tool.mypy]
101
+ python_version = "3.10"
102
+ strict = true
103
+ files = [ "src" ]
104
+
105
+ [[tool.mypy.overrides]]
106
+ module = [ "diffctx.*" ]
107
+ ignore_missing_imports = true
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from diffctx import (
4
+ build_diff_context,
5
+ map_directory,
6
+ run,
7
+ to_json,
8
+ to_markdown,
9
+ to_text,
10
+ to_yaml,
11
+ )
12
+
13
+ from .version import __version__
14
+
15
+ __all__ = [
16
+ "__version__",
17
+ "build_diff_context",
18
+ "map_directory",
19
+ "run",
20
+ "to_json",
21
+ "to_markdown",
22
+ "to_text",
23
+ "to_yaml",
24
+ ]
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ import diffctx
4
+
5
+ from .version import __version__
6
+
7
+
8
+ def main(argv: list[str] | None = None) -> None:
9
+ diffctx.run(argv, prog="treemapper", version=__version__)
10
+
11
+
12
+ if __name__ == "__main__":
13
+ main()
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+ from diffctx.mcp.__main__ import main as _engine_mcp_main
4
+
5
+
6
+ def main() -> None:
7
+ _engine_mcp_main(prog="treemapper-mcp", extra="treemapper[mcp]")
8
+
9
+
10
+ if __name__ == "__main__":
11
+ main()
@@ -0,0 +1 @@
1
+ __version__ = "2.2.0"
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import io
5
+ import subprocess
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ from treemapper.cli import main
12
+
13
+
14
+ @dataclass
15
+ class CliResult:
16
+ stdout: str
17
+ stderr: str
18
+ exit_code: int
19
+
20
+
21
+ def run_cli(argv: list[str]) -> CliResult:
22
+ out, err = io.StringIO(), io.StringIO()
23
+ exit_code = 0
24
+ with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
25
+ try:
26
+ main(argv)
27
+ except SystemExit as exc:
28
+ code = exc.code
29
+ exit_code = code if isinstance(code, int) else (0 if code is None else 1)
30
+ return CliResult(stdout=out.getvalue(), stderr=err.getvalue(), exit_code=exit_code)
31
+
32
+
33
+ @pytest.fixture
34
+ def sample_project(tmp_path: Path) -> Path:
35
+ (tmp_path / "alpha.py").write_text("def alpha():\n return 1\n", encoding="utf-8")
36
+ (tmp_path / "readme.txt").write_text("hello tree\n", encoding="utf-8")
37
+ nested = tmp_path / "pkg"
38
+ nested.mkdir()
39
+ (nested / "beta.py").write_text("def beta():\n return 2\n", encoding="utf-8")
40
+ return tmp_path
41
+
42
+
43
+ def _git(repo: Path, *args: str) -> None:
44
+ subprocess.run(["git", *args], cwd=repo, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
45
+
46
+
47
+ @pytest.fixture
48
+ def git_repo(tmp_path: Path) -> Path:
49
+ _git(tmp_path, "init")
50
+ _git(tmp_path, "config", "user.email", "test@example.com")
51
+ _git(tmp_path, "config", "user.name", "Test")
52
+ target = tmp_path / "module.py"
53
+ target.write_text("def compute(x):\n return x + 1\n", encoding="utf-8")
54
+ _git(tmp_path, "add", "-A")
55
+ _git(tmp_path, "commit", "-m", "initial")
56
+ target.write_text("def compute(x):\n return x + 2\n\n\ndef extra(y):\n return y * 2\n", encoding="utf-8")
57
+ _git(tmp_path, "add", "-A")
58
+ _git(tmp_path, "commit", "-m", "change compute and add extra")
59
+ return tmp_path
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import diffctx
6
+
7
+ import treemapper
8
+
9
+
10
+ def test_public_api_is_exported() -> None:
11
+ for name in ("map_directory", "build_diff_context", "run", "to_yaml", "to_json", "to_text", "to_markdown"):
12
+ assert hasattr(treemapper, name), name
13
+
14
+
15
+ def test_run_is_the_engine_entry() -> None:
16
+ assert treemapper.run is diffctx.run
17
+
18
+
19
+ def test_map_directory_round_trips_to_yaml(sample_project: Path) -> None:
20
+ tree = treemapper.map_directory(str(sample_project))
21
+ assert tree["type"] == "directory"
22
+ rendered = treemapper.to_yaml(tree)
23
+ assert "alpha.py" in rendered
24
+
25
+
26
+ def test_build_diff_context_on_real_repo(git_repo: Path) -> None:
27
+ context = treemapper.build_diff_context(root_dir=git_repo, diff_range="HEAD~1")
28
+ assert isinstance(context, dict)
29
+ rendered = treemapper.to_yaml(context)
30
+ assert "module.py" in rendered
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import yaml
9
+
10
+ from treemapper.version import __version__
11
+
12
+ from .conftest import CliResult, run_cli
13
+
14
+
15
+ def test_version_is_treemapper_branded() -> None:
16
+ result = run_cli(["--version"])
17
+ assert result.exit_code == 0
18
+ assert result.stdout.strip() == f"treemapper {__version__}"
19
+
20
+
21
+ def test_help_renders_and_is_treemapper_branded() -> None:
22
+ result = run_cli(["--help"])
23
+ assert result.exit_code == 0
24
+ assert "--diff" in result.stdout
25
+ assert "usage: treemapper" in result.stdout.lower()
26
+ assert "usage: diffctx" not in result.stdout.lower()
27
+
28
+
29
+ def test_yaml_tree_includes_files_and_content(sample_project: Path) -> None:
30
+ result = run_cli([str(sample_project)])
31
+ assert result.exit_code == 0
32
+ tree = yaml.safe_load(result.stdout)
33
+ assert tree["type"] == "directory"
34
+ names = {child["name"] for child in tree["children"]}
35
+ assert "alpha.py" in names
36
+ assert "pkg" in names
37
+ assert "def alpha()" in result.stdout
38
+
39
+
40
+ def test_json_format(sample_project: Path) -> None:
41
+ result = run_cli([str(sample_project), "-f", "json"])
42
+ assert result.exit_code == 0
43
+ tree = json.loads(result.stdout)
44
+ assert tree["type"] == "directory"
45
+
46
+
47
+ def test_no_content_omits_file_bodies(sample_project: Path) -> None:
48
+ result = run_cli([str(sample_project), "--no-content"])
49
+ assert result.exit_code == 0
50
+ assert "def alpha()" not in result.stdout
51
+ assert "alpha.py" in result.stdout
52
+
53
+
54
+ def test_save_writes_file(sample_project: Path, monkeypatch) -> None:
55
+ monkeypatch.chdir(sample_project)
56
+ result = run_cli([str(sample_project), "-f", "md", "--save"])
57
+ assert result.exit_code == 0
58
+ assert (sample_project / "tree.md").is_file()
59
+
60
+
61
+ def test_diff_mode_selects_changed_context(git_repo: Path, monkeypatch) -> None:
62
+ monkeypatch.chdir(git_repo)
63
+ result = run_cli([str(git_repo), "--diff", "HEAD~1"])
64
+ assert result.exit_code == 0
65
+ assert "module.py" in result.stdout
66
+ assert "extra" in result.stdout
67
+
68
+
69
+ def test_console_script_entry_point(sample_project: Path) -> None:
70
+ proc = subprocess.run(
71
+ [sys.executable, "-m", "treemapper", str(sample_project), "--no-content"],
72
+ capture_output=True,
73
+ text=True,
74
+ check=False,
75
+ )
76
+ assert proc.returncode == 0
77
+ assert "alpha.py" in proc.stdout
78
+
79
+
80
+ def test_result_dataclass_shape() -> None:
81
+ result = run_cli(["--version"])
82
+ assert isinstance(result, CliResult)