cxtree 0.1.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.
- cxtree-0.1.0/.gitignore +210 -0
- cxtree-0.1.0/.python-version +1 -0
- cxtree-0.1.0/LICENSE +21 -0
- cxtree-0.1.0/PKG-INFO +448 -0
- cxtree-0.1.0/README.md +437 -0
- cxtree-0.1.0/cxtree/__init__.py +1 -0
- cxtree-0.1.0/cxtree/cli.py +123 -0
- cxtree-0.1.0/cxtree/commands/__init__.py +1 -0
- cxtree-0.1.0/cxtree/commands/create_.py +84 -0
- cxtree-0.1.0/cxtree/commands/flatten_.py +188 -0
- cxtree-0.1.0/cxtree/commands/init_.py +295 -0
- cxtree-0.1.0/cxtree/commands/leaf_.py +317 -0
- cxtree-0.1.0/cxtree/commands/rm_.py +54 -0
- cxtree-0.1.0/cxtree/commands/tree_.py +57 -0
- cxtree-0.1.0/cxtree/models.py +159 -0
- cxtree-0.1.0/cxtree/renderer.py +180 -0
- cxtree-0.1.0/cxtree/source.py +647 -0
- cxtree-0.1.0/cxtree/walker.py +428 -0
- cxtree-0.1.0/cxtree/yaml_io.py +283 -0
- cxtree-0.1.0/pyproject.toml +30 -0
- cxtree-0.1.0/tests/conftest.py +61 -0
- cxtree-0.1.0/tests/test_commands.py +458 -0
- cxtree-0.1.0/tests/test_models.py +172 -0
- cxtree-0.1.0/tests/test_source.py +330 -0
- cxtree-0.1.0/tests/test_yaml_io.py +202 -0
- cxtree-0.1.0/uv.lock +190 -0
cxtree-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
abstract.yaml
|
|
2
|
+
abstract-tree.yaml
|
|
3
|
+
context.md
|
|
4
|
+
# Byte-compiled / optimized / DLL files
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[codz]
|
|
7
|
+
*$py.class
|
|
8
|
+
|
|
9
|
+
# C extensions
|
|
10
|
+
*.so
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
MANIFEST
|
|
31
|
+
|
|
32
|
+
# PyInstaller
|
|
33
|
+
# Usually these files are written by a python script from a template
|
|
34
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
35
|
+
*.manifest
|
|
36
|
+
*.spec
|
|
37
|
+
|
|
38
|
+
# Installer logs
|
|
39
|
+
pip-log.txt
|
|
40
|
+
pip-delete-this-directory.txt
|
|
41
|
+
|
|
42
|
+
# Unit test / coverage reports
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
.coverage
|
|
47
|
+
.coverage.*
|
|
48
|
+
.cache
|
|
49
|
+
nosetests.xml
|
|
50
|
+
coverage.xml
|
|
51
|
+
*.cover
|
|
52
|
+
*.py.cover
|
|
53
|
+
.hypothesis/
|
|
54
|
+
.pytest_cache/
|
|
55
|
+
cover/
|
|
56
|
+
|
|
57
|
+
# Translations
|
|
58
|
+
*.mo
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
# Django stuff:
|
|
62
|
+
*.log
|
|
63
|
+
local_settings.py
|
|
64
|
+
db.sqlite3
|
|
65
|
+
db.sqlite3-journal
|
|
66
|
+
|
|
67
|
+
# Flask stuff:
|
|
68
|
+
instance/
|
|
69
|
+
.webassets-cache
|
|
70
|
+
|
|
71
|
+
# Scrapy stuff:
|
|
72
|
+
.scrapy
|
|
73
|
+
|
|
74
|
+
# Sphinx documentation
|
|
75
|
+
docs/_build/
|
|
76
|
+
|
|
77
|
+
# PyBuilder
|
|
78
|
+
.pybuilder/
|
|
79
|
+
target/
|
|
80
|
+
|
|
81
|
+
# Jupyter Notebook
|
|
82
|
+
.ipynb_checkpoints
|
|
83
|
+
|
|
84
|
+
# IPython
|
|
85
|
+
profile_default/
|
|
86
|
+
ipython_config.py
|
|
87
|
+
|
|
88
|
+
# pyenv
|
|
89
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
90
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
91
|
+
# .python-version
|
|
92
|
+
|
|
93
|
+
# pipenv
|
|
94
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
95
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
96
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
97
|
+
# install all needed dependencies.
|
|
98
|
+
#Pipfile.lock
|
|
99
|
+
|
|
100
|
+
# UV
|
|
101
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
102
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
103
|
+
# commonly ignored for libraries.
|
|
104
|
+
#uv.lock
|
|
105
|
+
|
|
106
|
+
# poetry
|
|
107
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
108
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
109
|
+
# commonly ignored for libraries.
|
|
110
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
111
|
+
#poetry.lock
|
|
112
|
+
#poetry.toml
|
|
113
|
+
|
|
114
|
+
# pdm
|
|
115
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
116
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
117
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
118
|
+
#pdm.lock
|
|
119
|
+
#pdm.toml
|
|
120
|
+
.pdm-python
|
|
121
|
+
.pdm-build/
|
|
122
|
+
|
|
123
|
+
# pixi
|
|
124
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
125
|
+
#pixi.lock
|
|
126
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
127
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
128
|
+
.pixi
|
|
129
|
+
|
|
130
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
131
|
+
__pypackages__/
|
|
132
|
+
|
|
133
|
+
# Celery stuff
|
|
134
|
+
celerybeat-schedule
|
|
135
|
+
celerybeat.pid
|
|
136
|
+
|
|
137
|
+
# SageMath parsed files
|
|
138
|
+
*.sage.py
|
|
139
|
+
|
|
140
|
+
# Environments
|
|
141
|
+
.env
|
|
142
|
+
.envrc
|
|
143
|
+
.venv
|
|
144
|
+
env/
|
|
145
|
+
venv/
|
|
146
|
+
ENV/
|
|
147
|
+
env.bak/
|
|
148
|
+
venv.bak/
|
|
149
|
+
|
|
150
|
+
# Spyder project settings
|
|
151
|
+
.spyderproject
|
|
152
|
+
.spyproject
|
|
153
|
+
|
|
154
|
+
# Rope project settings
|
|
155
|
+
.ropeproject
|
|
156
|
+
|
|
157
|
+
# mkdocs documentation
|
|
158
|
+
/site
|
|
159
|
+
|
|
160
|
+
# mypy
|
|
161
|
+
.mypy_cache/
|
|
162
|
+
.dmypy.json
|
|
163
|
+
dmypy.json
|
|
164
|
+
|
|
165
|
+
# Pyre type checker
|
|
166
|
+
.pyre/
|
|
167
|
+
|
|
168
|
+
# pytype static type analyzer
|
|
169
|
+
.pytype/
|
|
170
|
+
|
|
171
|
+
# Cython debug symbols
|
|
172
|
+
cython_debug/
|
|
173
|
+
|
|
174
|
+
# PyCharm
|
|
175
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
176
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
177
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
178
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
179
|
+
#.idea/
|
|
180
|
+
|
|
181
|
+
# Abstra
|
|
182
|
+
# Abstra is an AI-powered process automation framework.
|
|
183
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
184
|
+
# Learn more at https://abstra.io/docs
|
|
185
|
+
.abstra/
|
|
186
|
+
|
|
187
|
+
# Visual Studio Code
|
|
188
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
189
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
190
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
191
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
192
|
+
# .vscode/
|
|
193
|
+
|
|
194
|
+
# Ruff stuff:
|
|
195
|
+
.ruff_cache/
|
|
196
|
+
|
|
197
|
+
# PyPI configuration file
|
|
198
|
+
.pypirc
|
|
199
|
+
|
|
200
|
+
# Cursor
|
|
201
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
202
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
203
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
204
|
+
.cursorignore
|
|
205
|
+
.cursorindexingignore
|
|
206
|
+
|
|
207
|
+
# Marimo
|
|
208
|
+
marimo/_static/
|
|
209
|
+
marimo/_lsp/
|
|
210
|
+
__marimo__/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
cxtree-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aiumi Net
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cxtree-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cxtree
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate focused, token-efficient LLM context files from your project.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: click>=8.1
|
|
8
|
+
Requires-Dist: pyyaml>=6.0
|
|
9
|
+
Requires-Dist: rich>=13.0
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# cxtree
|
|
13
|
+
|
|
14
|
+
[](https://pypi.org/project/cxtree/)
|
|
15
|
+
[](https://github.com/aiumi-net/cxtree)
|
|
16
|
+
|
|
17
|
+
> Generate focused, token-efficient LLM context files from your project.
|
|
18
|
+
|
|
19
|
+
`cxtree` walks a project directory and produces a structured Markdown file
|
|
20
|
+
containing the directory tree and relevant source files as code blocks — ready
|
|
21
|
+
to paste into any LLM chat as context.
|
|
22
|
+
|
|
23
|
+
The key idea: instead of dumping everything into the context window, you control
|
|
24
|
+
exactly what the LLM sees — per directory, per file, per class, per function —
|
|
25
|
+
using a YAML configuration file.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install cxtree
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or with [uv](https://github.com/astral-sh/uv):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv add cxtree
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# 1. Generate abstract-tree.yaml in your project root
|
|
47
|
+
cxtree init
|
|
48
|
+
|
|
49
|
+
# 2. Edit abstract-tree.yaml to configure what the LLM sees (optional)
|
|
50
|
+
|
|
51
|
+
# 3. Generate context.md
|
|
52
|
+
cxtree create
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then paste `context.md` into any LLM chat.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Commands
|
|
60
|
+
|
|
61
|
+
All commands accept `-r / --root` to point at a project directory other than `.`.
|
|
62
|
+
|
|
63
|
+
### `init`
|
|
64
|
+
|
|
65
|
+
Traverses the project, discovers files, and writes `abstract-tree.yaml` to the
|
|
66
|
+
project root. If a file already exists it is preserved — only new entries are
|
|
67
|
+
added.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cxtree init
|
|
71
|
+
cxtree init -r path/to/project
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**`--folder` flag** — stores both `abstract-tree.yaml` and `context.md` inside a
|
|
75
|
+
`.abstract-tree/` subdirectory (which gets a `.gitignore` that excludes its
|
|
76
|
+
contents from git). Useful for keeping the project root clean.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
cxtree init --folder
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Switching between folder and normal mode re-runs automatically and cleans up the
|
|
83
|
+
previous location.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### `create`
|
|
88
|
+
|
|
89
|
+
Reads `abstract-tree.yaml` and generates `context.md`.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cxtree create
|
|
93
|
+
cxtree create -o docs/llm-context.md # custom output path
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### `leafs`
|
|
99
|
+
|
|
100
|
+
Splits the flat root `abstract-tree.yaml` into per-directory `abstract.yaml`
|
|
101
|
+
child files. Useful for large projects where many directories need fine-grained
|
|
102
|
+
control.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
cxtree leafs
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Each directory with file-level entries gets its own `abstract.yaml`. The root
|
|
109
|
+
file is reduced to directory stubs. Re-running `leafs` on an already-split
|
|
110
|
+
project merges changes back first, then re-splits.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### `flatten`
|
|
115
|
+
|
|
116
|
+
The reverse of `leafs`. Reads all child `abstract.yaml` files and merges their
|
|
117
|
+
entries back into the root file, then deletes them.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
cxtree flatten # flatten everything
|
|
121
|
+
cxtree flatten domain # flatten only the domain/ subtree
|
|
122
|
+
cxtree flatten domain.users
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### `tree`
|
|
128
|
+
|
|
129
|
+
Prints a coloured directory tree of the project respecting the same exclusion
|
|
130
|
+
rules as `init`.
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cxtree tree
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Folders are shown in yellow, `.py` files in blue, everything else in white.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### `rm`
|
|
141
|
+
|
|
142
|
+
Removes all generated files: `context.md`, `abstract-tree.yaml`, and all child
|
|
143
|
+
`abstract.yaml` files.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
cxtree rm
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## abstract-tree.yaml
|
|
152
|
+
|
|
153
|
+
`abstract-tree.yaml` is the root configuration file. It has two sections:
|
|
154
|
+
|
|
155
|
+
1. A `cxtree:` header block with project-wide settings.
|
|
156
|
+
2. Directory and file entries that control what the LLM sees.
|
|
157
|
+
|
|
158
|
+
### Header block
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
cxtree:
|
|
162
|
+
x_root: docs # default tag for the whole project
|
|
163
|
+
is_flat: true # true = only root file used; false = leaf mode
|
|
164
|
+
ext_found: [py, toml] # written by init — informational only
|
|
165
|
+
config:
|
|
166
|
+
x_rm_empty_lines: false # strip all blank lines from output
|
|
167
|
+
x_rm_empty_lines_docs: true # strip blank lines from doc-only sections
|
|
168
|
+
include:
|
|
169
|
+
x_extensions: [py] # file extensions included in context
|
|
170
|
+
exclude:
|
|
171
|
+
x_startswith: [".", "__"] # skip files/dirs starting with these prefixes
|
|
172
|
+
x_folders: [".venv", "node_modules", "__pycache__"]
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Directory entries
|
|
176
|
+
|
|
177
|
+
Directories use dot-notation keys with `is_dir: true`. `init` generates these
|
|
178
|
+
automatically.
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
domain:
|
|
182
|
+
is_dir: true
|
|
183
|
+
|
|
184
|
+
domain.users:
|
|
185
|
+
is_dir: true
|
|
186
|
+
models.py: docs
|
|
187
|
+
auth.py: include
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### File entries
|
|
191
|
+
|
|
192
|
+
Files are nested under their directory key (or at root level for files in the
|
|
193
|
+
project root). The value controls what the LLM sees.
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
domain.users:
|
|
197
|
+
is_dir: true
|
|
198
|
+
models.py: docs # show docstrings only
|
|
199
|
+
auth.py: include # show full source
|
|
200
|
+
legacy.py: exclude # hide completely
|
|
201
|
+
base.py: "Shared base classes — no details needed." # replace with text
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Tags
|
|
207
|
+
|
|
208
|
+
Tags control how a file (or symbol) is rendered.
|
|
209
|
+
|
|
210
|
+
| Tag | What the LLM sees |
|
|
211
|
+
|---|---|
|
|
212
|
+
| `docs` | Docstrings only — code bodies are replaced with `# ...` |
|
|
213
|
+
| `code` | Code bodies only — docstrings are stripped |
|
|
214
|
+
| `include` | Full source: code + docstrings |
|
|
215
|
+
| `exclude` | Hidden — not included in context at all |
|
|
216
|
+
|
|
217
|
+
Tags are inherited top-down. The `x_root` value in the header is the starting
|
|
218
|
+
point; any entry without an explicit tag inherits from its parent.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Symbol-level configuration
|
|
223
|
+
|
|
224
|
+
For Python files you can configure individual classes and functions.
|
|
225
|
+
|
|
226
|
+
```yaml
|
|
227
|
+
domain.users:
|
|
228
|
+
is_dir: true
|
|
229
|
+
auth.py:
|
|
230
|
+
x_abstract:
|
|
231
|
+
- "Authentication service — login, logout, token validation."
|
|
232
|
+
class:
|
|
233
|
+
AuthService:
|
|
234
|
+
x_abstract:
|
|
235
|
+
- "Handles login, logout and token validation."
|
|
236
|
+
def:
|
|
237
|
+
login: docs # show docstring only
|
|
238
|
+
logout: docs
|
|
239
|
+
validate_token: include # show full source
|
|
240
|
+
_sign: exclude # hide private helper
|
|
241
|
+
def:
|
|
242
|
+
create_token: docs
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`__init__`, `__post_init__`, `__new__` and other lifecycle dunders are always
|
|
246
|
+
skipped — they are never emitted even with `include`.
|
|
247
|
+
|
|
248
|
+
`x_abstract` on a file or class sets a description shown above its content.
|
|
249
|
+
Use a list for multi-line descriptions:
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
auth.py:
|
|
253
|
+
x_abstract:
|
|
254
|
+
- "Authentication service."
|
|
255
|
+
- "Tokens are HMAC-signed. No external JWT library required."
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Text replacements
|
|
261
|
+
|
|
262
|
+
Assign any string to a directory or file entry to replace it entirely with that
|
|
263
|
+
text. No further content is shown.
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
domain.legacy:
|
|
267
|
+
is_dir: true
|
|
268
|
+
old_service.py: "Deprecated. Superseded by domain.users.services."
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Multiline replacement using a YAML list:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
domain.users:
|
|
275
|
+
is_dir: true
|
|
276
|
+
models.py:
|
|
277
|
+
- "User entity with id, username, email, is_active, roles."
|
|
278
|
+
- "Session entity binding a user_id to a token and expiry."
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### `x_hard_abstract` (directory-level)
|
|
282
|
+
|
|
283
|
+
Setting `x_hard_abstract` on a directory entry replaces the entire directory
|
|
284
|
+
with a single summary line — no files inside are walked.
|
|
285
|
+
|
|
286
|
+
```yaml
|
|
287
|
+
workers:
|
|
288
|
+
is_dir: true
|
|
289
|
+
x_hard_abstract: "Background workers for cleanup and reporting."
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Set it to `"off"` to disable the override without removing the key:
|
|
293
|
+
|
|
294
|
+
```yaml
|
|
295
|
+
workers:
|
|
296
|
+
is_dir: true
|
|
297
|
+
x_hard_abstract: "off"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## abstract-leaf.yaml
|
|
303
|
+
|
|
304
|
+
Place an `abstract-leaf.yaml` file inside any directory to provide the
|
|
305
|
+
highest-priority flat overrides for that directory. Entries here override
|
|
306
|
+
everything else — tags, symbol config, even the `include_extensions` filter.
|
|
307
|
+
|
|
308
|
+
```yaml
|
|
309
|
+
# domain/abstract-leaf.yaml
|
|
310
|
+
notifications: "Email and SMS dispatchers — not relevant for this task."
|
|
311
|
+
models.py: "User entity and Notification entity."
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Keys = filenames or subdirectory names** within that directory only.
|
|
315
|
+
Values must be plain strings.
|
|
316
|
+
|
|
317
|
+
To deactivate an entry without deleting it, prefix the key with `.` or `__`
|
|
318
|
+
(the default `exclude_startswith` prefixes):
|
|
319
|
+
|
|
320
|
+
```yaml
|
|
321
|
+
# disabled — notifications/ is walked normally
|
|
322
|
+
.notifications: "Email and SMS dispatchers — not relevant for this task."
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`abstract-leaf.yaml` is never included in the context output itself.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Inline source tags
|
|
330
|
+
|
|
331
|
+
Fine-tune what gets shown inside a function or method body using inline comments.
|
|
332
|
+
|
|
333
|
+
### `# ++` — show N lines from this point
|
|
334
|
+
|
|
335
|
+
The number of `+` characters determines how many lines are shown starting from
|
|
336
|
+
and including the tagged line. `# ++` = 2 lines, `# +++` = 3 lines, etc.
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
def build_app(config: AppConfig) -> dict:
|
|
340
|
+
user_svc = UserService(config.db_url) # ++
|
|
341
|
+
notif_svc = NotificationService(...)
|
|
342
|
+
# ← both lines above are shown; rest of body is compressed to # ...
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### `# ---` — hide N lines
|
|
346
|
+
|
|
347
|
+
The number of `-` characters determines how many lines are hidden. The tagged
|
|
348
|
+
line and the N−1 lines that follow are replaced by a single `# ---` placeholder.
|
|
349
|
+
`# ---` = 3 lines hidden, `# ----` = 4 lines, etc.
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
def process(self, request: dict) -> dict:
|
|
353
|
+
token = header[len(prefix):] # ---
|
|
354
|
+
request["_token"] = token # ← this line is hidden (part of the 3)
|
|
355
|
+
return request
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Both tags preserve the indentation of the tagged line in the placeholder.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Leaf mode (per-directory child files)
|
|
363
|
+
|
|
364
|
+
Run `leafs` to split the flat root file into one `abstract.yaml` per directory.
|
|
365
|
+
This is useful when many directories need independent, detailed configuration.
|
|
366
|
+
|
|
367
|
+
```
|
|
368
|
+
project/
|
|
369
|
+
├── abstract-tree.yaml # root — directory stubs only
|
|
370
|
+
├── domain/
|
|
371
|
+
│ └── abstract.yaml # file entries for domain/
|
|
372
|
+
└── api/
|
|
373
|
+
└── abstract.yaml # file entries for api/
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Child `abstract.yaml` files use the same tag and symbol syntax. They are
|
|
377
|
+
identified by `abstract-depth:` (set automatically by `leafs`) which must match
|
|
378
|
+
the directory's actual depth from the project root.
|
|
379
|
+
|
|
380
|
+
### `x_is_flat` and `x_hard_abstract` in child abstracts
|
|
381
|
+
|
|
382
|
+
A subdirectory entry inside a child abstract can carry two control keys:
|
|
383
|
+
|
|
384
|
+
```yaml
|
|
385
|
+
# domain/abstract.yaml
|
|
386
|
+
abstract-depth: 1
|
|
387
|
+
parent-dirs: [domain]
|
|
388
|
+
|
|
389
|
+
users:
|
|
390
|
+
is_dir: true
|
|
391
|
+
x_is_flat: false # false = keep its own child abstract
|
|
392
|
+
x_hard_abstract: "off" # placeholder — replace "off" with text to activate
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- `x_is_flat: true` — merge this subdirectory back into the parent on the next
|
|
396
|
+
`leafs` run instead of keeping its own child abstract.
|
|
397
|
+
- `x_hard_abstract: "<text>"` — replace the entire subdirectory with a summary
|
|
398
|
+
in the context output. `"off"` = feature inactive.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Folder mode
|
|
403
|
+
|
|
404
|
+
Use `--folder` to keep generated files out of the project root:
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
cxtree init --folder
|
|
408
|
+
cxtree create # reads and writes inside .abstract-tree/
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
The `.abstract-tree/` directory contains:
|
|
412
|
+
|
|
413
|
+
```
|
|
414
|
+
.abstract-tree/
|
|
415
|
+
├── .gitignore # excludes everything inside from git
|
|
416
|
+
├── abstract-tree.yaml
|
|
417
|
+
└── context.md
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Switch back to normal mode by running `init` without `--folder`:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
cxtree init # deletes .abstract-tree/, writes to project root
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Example workflow
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
# Initial setup
|
|
432
|
+
cxtree init
|
|
433
|
+
|
|
434
|
+
# Review abstract-tree.yaml, tune tags and descriptions, then generate
|
|
435
|
+
cxtree create
|
|
436
|
+
|
|
437
|
+
# For large projects: split into per-directory files
|
|
438
|
+
cxtree leafs
|
|
439
|
+
|
|
440
|
+
# Edit individual abstract.yaml files in each directory, then regenerate
|
|
441
|
+
cxtree create
|
|
442
|
+
|
|
443
|
+
# Merge a subtree back (e.g. after simplifying domain/)
|
|
444
|
+
cxtree flatten domain
|
|
445
|
+
|
|
446
|
+
# Clean up everything
|
|
447
|
+
cxtree rm
|
|
448
|
+
```
|