ramani 0.1.0a1__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.

Potentially problematic release.


This version of ramani might be problematic. Click here for more details.

ramani-0.1.0a1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kevin Wasike Wakhisi
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.
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: ramani
3
+ Version: 0.1.0a1
4
+ Summary: Ramani (Swahili for “map”): keeps each file's path as a comment on its first line, updates it when files move, and prints your project as a tree.
5
+ Keywords: comments,paths,tree,project-structure,cli,swahili
6
+ Author: Kevin Wasike Wakhisi
7
+ Author-email: Kevin Wasike Wakhisi <kevin@treeolive.tech>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
+ Classifier: Topic :: Software Development
20
+ Classifier: Topic :: Utilities
21
+ Requires-Dist: pyperclip>=1.8
22
+ Maintainer: Kevin Wasike Wakhisi
23
+ Maintainer-email: Kevin Wasike Wakhisi <kevin@treeolive.tech>
24
+ Requires-Python: >=3.13
25
+ Project-URL: Repository, https://github.com/kvnwaks/ramani.git
26
+ Description-Content-Type: text/markdown
27
+
28
+ <!-- ramani: README.md -->
29
+ <h1 align="center">ramani</h1>
30
+
31
+ <p align="center">
32
+ <strong>Every file knows where it lives.</strong><br>
33
+ A line at the top of each file says where it sits in your project, and it follows the file when it moves.
34
+ </p>
35
+
36
+ <p align="center">
37
+ <a href="https://www.python.org/"><img alt="Python 3.13+" src="https://img.shields.io/badge/python-3.13%2B-3776AB?logo=python&logoColor=white"></a>
38
+ <a href="https://docs.astral.sh/uv/"><img alt="Built with uv" src="https://img.shields.io/badge/built%20with-uv-DE5FE9"></a>
39
+ <img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue">
40
+ <img alt="ramani means map in Swahili" src="https://img.shields.io/badge/ramani-Swahili%20for%20%22map%22-006600">
41
+ </p>
42
+
43
+ <p align="center">
44
+ <a href="#install">Install</a> ·
45
+ <a href="#usage">Usage</a> ·
46
+ <a href="#folder-tree">Folder tree</a> ·
47
+ <a href="#configuration">Configuration</a> ·
48
+ <a href="#supported-files">Supported files</a>
49
+ </p>
50
+
51
+ > **ramani** _(ra-MA-ni)_ is Swahili for **"map"**. That is the whole idea: ramani draws a map of your project _inside_ the project. Each file carries one comment with its own path, kept correct as files are renamed and moved, and the same tool can print the entire project as a tree.
52
+
53
+ ```python
54
+ # ramani: src/shop/billing/pay.py
55
+ def pay(): ...
56
+ ```
57
+
58
+ ## Why
59
+
60
+ Files travel without their address. They get pasted into chats, issues, code reviews and AI prompts, and the question "which file is this, again?" comes up every time. With ramani the path is part of the file, so it travels with it.
61
+
62
+ ## Features
63
+
64
+ - 🧭 **Move-aware.** Rename or move a file, run ramani again, and its comment follows. Nothing is duplicated.
65
+ - 🪶 **Careful placement.** The comment goes after shebangs, encoding lines, XML declarations and Markdown front matter, and never turns a docstring into a plain string.
66
+ - 🗂️ **Knows 60+ file types.** Python, JavaScript, Go, Rust, SQL, HTML, CSS, Markdown, Dockerfile and more, each with the right comment syntax. Add your own in one line.
67
+ - 🙈 **Respects your ignores.** Built-in lists for `__pycache__`, `node_modules` and friends, every `.gitignore` it finds (nested ones too), and flags for the rest.
68
+ - 🌳 **Prints a folder tree.** One flag draws your project as a tree, another copies it to the clipboard.
69
+ - 🔍 **CI-friendly.** `--check` exits with code 1 when any comment is missing or stale. `--dry-run` writes nothing.
70
+ - 🧹 **Reversible.** `--remove` strips every comment ramani added.
71
+
72
+ ## Install
73
+
74
+ ```bash
75
+ uv tool install ramani # or: pipx install ramani / pip install ramani
76
+ ```
77
+
78
+ Then, inside a project:
79
+
80
+ ```bash
81
+ ramani --dry-run # see what would change
82
+ ramani # do it
83
+ ```
84
+
85
+ ## Usage
86
+
87
+ Point it at a folder (default: the current one) or a single file. Paths in the comments are relative to that folder.
88
+
89
+ ```console
90
+ $ ramani
91
+ added docs/setup.md
92
+ added src/shop/cart.py
93
+ added src/shop/index.html
94
+ added src/shop/pay.py
95
+ added README.md
96
+ 5 added, 1 unsupported
97
+ no comment style for: .json x1
98
+ add one with -c EXT=START[,END] or [tool.ramani.comments] in pyproject.toml
99
+ ```
100
+
101
+ The comment uses each language's own syntax, and sits where it can't break anything:
102
+
103
+ ```python
104
+ # ramani: src/shop/cart.py
105
+ """Cart logic."""
106
+ import json
107
+ ```
108
+
109
+ ```html
110
+ <!-- ramani: src/shop/index.html -->
111
+ <h1>Hi</h1>
112
+ ```
113
+
114
+ ```text
115
+ ---
116
+ title: Setup
117
+ ---
118
+ <!-- ramani: docs/setup.md -->
119
+ # Setup
120
+ ```
121
+
122
+ ### When a file moves
123
+
124
+ Move `pay.py` into a new `billing/` folder and run ramani again. It recognises its own comment, sees the path is out of date, and rewrites it. Untouched files stay untouched.
125
+
126
+ ```console
127
+ $ mkdir src/shop/billing && mv src/shop/pay.py src/shop/billing/
128
+ $ ramani
129
+ updated src/shop/billing/pay.py
130
+ 4 unchanged, 1 unsupported, 1 updated
131
+ ```
132
+
133
+ ```python
134
+ # ramani: src/shop/billing/pay.py
135
+ def pay(): ...
136
+ ```
137
+
138
+ Add `ramani --check` to CI or a pre-commit hook to catch stale comments before they land. It changes nothing and exits with 1 if anything needs updating.
139
+
140
+ ## Folder tree
141
+
142
+ `--tree` prints your project as a tree and writes nothing. It uses the same ignore rules as marking, so you see exactly the files ramani works on. Folders come first.
143
+
144
+ ```console
145
+ $ ramani --tree
146
+ shop/
147
+ ├── docs/
148
+ │ └── setup.md
149
+ ├── src/
150
+ │ └── shop/
151
+ │ ├── billing/
152
+ │ │ └── pay.py
153
+ │ ├── cart.py
154
+ │ └── index.html
155
+ ├── README.md
156
+ └── data.json
157
+ ```
158
+
159
+ Add `--copy` to also put the tree on your clipboard, ready to paste into a chat, an issue or a doc.
160
+
161
+ ```bash
162
+ ramani --copy # print the tree and copy it
163
+ ramani ./src -t -d tests # tree of ./src, leaving out tests
164
+ ```
165
+
166
+ > On Linux, the clipboard needs `xclip`, `xsel` or `wl-clipboard` installed. If none is available the tree is still printed, with a note on stderr and exit code 1.
167
+
168
+ ## Options
169
+
170
+ | Option | What it does |
171
+ | ------------------------------- | ------------------------------------------------------------------- |
172
+ | `PATH` | Folder or file to process (default: current folder) |
173
+ | `-e, --ignore-ext EXT` | Also skip this extension, e.g. `-e .txt` (repeatable) |
174
+ | `-d, --ignore-dir NAME` | Also skip this folder name or glob, e.g. `-d "build*"` (repeatable) |
175
+ | `-c, --comment EXT=START[,END]` | Comment style for an extension or file name (repeatable) |
176
+ | `--no-gitignore` | Ignore `.gitignore` files |
177
+ | `-n, --dry-run` | Show what would change, write nothing |
178
+ | `--check` | Dry run that exits 1 if anything is missing or stale |
179
+ | `--remove` | Strip ramani comments instead of adding them |
180
+ | `-t, --tree` | Print the folder tree instead of marking files |
181
+ | `--copy` | Copy the tree to the clipboard (implies `--tree`) |
182
+ | `-V, --version` | Print the installed version and exit |
183
+ | `-v, --verbose` | Also list unchanged files |
184
+
185
+ ## Configuration
186
+
187
+ Teach ramani a file type on the command line:
188
+
189
+ ```bash
190
+ ramani -c .abc=// # line comment
191
+ ramani -c ".tpl=<!--,-->" # block comment: start,end
192
+ ramani -c Jenkinsfile=// # by exact file name
193
+ ```
194
+
195
+ or once and for all in your `pyproject.toml`:
196
+
197
+ ```toml
198
+ [tool.ramani.comments]
199
+ ".abc" = "//"
200
+ ".tpl" = ["<!--", "-->"]
201
+ ```
202
+
203
+ Flags beat `pyproject.toml`, which beats the built-in styles, so you can override those too.
204
+
205
+ ## Supported files
206
+
207
+ | Comment | Looks like | Files |
208
+ | ---------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
209
+ | `#` | `# ramani: a/b.py` | `.py` `.pyi` `.sh` `.rb` `.pl` `.r` `.jl` `.ex` `.yml` `.yaml` `.toml` `.cfg` `.tf` `.ps1` `.nix` `Dockerfile` `Makefile` `.gitignore` … |
210
+ | `//` | `// ramani: a/b.ts` | `.js` `.mjs` `.jsx` `.ts` `.tsx` `.java` `.kt` `.scala` `.c` `.h` `.cpp` `.cs` `.go` `.rs` `.swift` `.dart` `.scss` `.proto` … |
211
+ | `--` | `-- ramani: a/b.sql` | `.sql` `.lua` `.hs` `.elm` |
212
+ | `<!-- -->` | `<!-- ramani: a/b.html -->` | `.html` `.htm` `.xml` `.svg` `.vue` `.svelte` `.md` `.markdown` |
213
+ | `/* */` | `/* ramani: a/b.css */` | `.css` |
214
+ | `{# #}` | `{# ramani: a/b.j2 #}` | `.j2` `.jinja` `.jinja2` |
215
+ | `{/* */}` | `{/* ramani: a/b.mdx */}` | `.mdx` |
216
+ | `%` | `% ramani: a/b.tex` | `.tex` |
217
+
218
+ Formats with no comment syntax, such as `.json` and `.csv`, are left alone and listed at the end of each run so nothing is skipped silently. The full table lives in `src/ramani/config.py`.
219
+
220
+ ## How it works
221
+
222
+ 1. Skip anything that must stay first: a shebang, an encoding line, an XML declaration, a `# syntax=` line, or front matter in Markdown.
223
+ 2. Look at the next line. If it is a ramani comment with the **same** path, do nothing.
224
+ 3. If it is a ramani comment with a **different** path, the file has moved. Rewrite that one line.
225
+ 4. If it is not a ramani comment, insert one.
226
+
227
+ Line endings (LF or CRLF) and UTF-8 byte-order marks are preserved. Symlinks, files that are not UTF-8, and binary files (anything containing a NUL byte) are never touched.
228
+
229
+ ## Development
230
+
231
+ ```bash
232
+ uv sync
233
+ uv run poe test
234
+ ```
235
+
236
+ Ramani has a single runtime dependency, [`pyperclip`](https://pypi.org/project/pyperclip/), used only for `--copy`.
237
+
238
+ ## License
239
+
240
+ MIT © Kevin Wasike Wakhisi. Use it, change it, ship it; just keep the copyright notice.
@@ -0,0 +1,213 @@
1
+ <!-- ramani: README.md -->
2
+ <h1 align="center">ramani</h1>
3
+
4
+ <p align="center">
5
+ <strong>Every file knows where it lives.</strong><br>
6
+ A line at the top of each file says where it sits in your project, and it follows the file when it moves.
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.python.org/"><img alt="Python 3.13+" src="https://img.shields.io/badge/python-3.13%2B-3776AB?logo=python&logoColor=white"></a>
11
+ <a href="https://docs.astral.sh/uv/"><img alt="Built with uv" src="https://img.shields.io/badge/built%20with-uv-DE5FE9"></a>
12
+ <img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue">
13
+ <img alt="ramani means map in Swahili" src="https://img.shields.io/badge/ramani-Swahili%20for%20%22map%22-006600">
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="#install">Install</a> ·
18
+ <a href="#usage">Usage</a> ·
19
+ <a href="#folder-tree">Folder tree</a> ·
20
+ <a href="#configuration">Configuration</a> ·
21
+ <a href="#supported-files">Supported files</a>
22
+ </p>
23
+
24
+ > **ramani** _(ra-MA-ni)_ is Swahili for **"map"**. That is the whole idea: ramani draws a map of your project _inside_ the project. Each file carries one comment with its own path, kept correct as files are renamed and moved, and the same tool can print the entire project as a tree.
25
+
26
+ ```python
27
+ # ramani: src/shop/billing/pay.py
28
+ def pay(): ...
29
+ ```
30
+
31
+ ## Why
32
+
33
+ Files travel without their address. They get pasted into chats, issues, code reviews and AI prompts, and the question "which file is this, again?" comes up every time. With ramani the path is part of the file, so it travels with it.
34
+
35
+ ## Features
36
+
37
+ - 🧭 **Move-aware.** Rename or move a file, run ramani again, and its comment follows. Nothing is duplicated.
38
+ - 🪶 **Careful placement.** The comment goes after shebangs, encoding lines, XML declarations and Markdown front matter, and never turns a docstring into a plain string.
39
+ - 🗂️ **Knows 60+ file types.** Python, JavaScript, Go, Rust, SQL, HTML, CSS, Markdown, Dockerfile and more, each with the right comment syntax. Add your own in one line.
40
+ - 🙈 **Respects your ignores.** Built-in lists for `__pycache__`, `node_modules` and friends, every `.gitignore` it finds (nested ones too), and flags for the rest.
41
+ - 🌳 **Prints a folder tree.** One flag draws your project as a tree, another copies it to the clipboard.
42
+ - 🔍 **CI-friendly.** `--check` exits with code 1 when any comment is missing or stale. `--dry-run` writes nothing.
43
+ - 🧹 **Reversible.** `--remove` strips every comment ramani added.
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ uv tool install ramani # or: pipx install ramani / pip install ramani
49
+ ```
50
+
51
+ Then, inside a project:
52
+
53
+ ```bash
54
+ ramani --dry-run # see what would change
55
+ ramani # do it
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ Point it at a folder (default: the current one) or a single file. Paths in the comments are relative to that folder.
61
+
62
+ ```console
63
+ $ ramani
64
+ added docs/setup.md
65
+ added src/shop/cart.py
66
+ added src/shop/index.html
67
+ added src/shop/pay.py
68
+ added README.md
69
+ 5 added, 1 unsupported
70
+ no comment style for: .json x1
71
+ add one with -c EXT=START[,END] or [tool.ramani.comments] in pyproject.toml
72
+ ```
73
+
74
+ The comment uses each language's own syntax, and sits where it can't break anything:
75
+
76
+ ```python
77
+ # ramani: src/shop/cart.py
78
+ """Cart logic."""
79
+ import json
80
+ ```
81
+
82
+ ```html
83
+ <!-- ramani: src/shop/index.html -->
84
+ <h1>Hi</h1>
85
+ ```
86
+
87
+ ```text
88
+ ---
89
+ title: Setup
90
+ ---
91
+ <!-- ramani: docs/setup.md -->
92
+ # Setup
93
+ ```
94
+
95
+ ### When a file moves
96
+
97
+ Move `pay.py` into a new `billing/` folder and run ramani again. It recognises its own comment, sees the path is out of date, and rewrites it. Untouched files stay untouched.
98
+
99
+ ```console
100
+ $ mkdir src/shop/billing && mv src/shop/pay.py src/shop/billing/
101
+ $ ramani
102
+ updated src/shop/billing/pay.py
103
+ 4 unchanged, 1 unsupported, 1 updated
104
+ ```
105
+
106
+ ```python
107
+ # ramani: src/shop/billing/pay.py
108
+ def pay(): ...
109
+ ```
110
+
111
+ Add `ramani --check` to CI or a pre-commit hook to catch stale comments before they land. It changes nothing and exits with 1 if anything needs updating.
112
+
113
+ ## Folder tree
114
+
115
+ `--tree` prints your project as a tree and writes nothing. It uses the same ignore rules as marking, so you see exactly the files ramani works on. Folders come first.
116
+
117
+ ```console
118
+ $ ramani --tree
119
+ shop/
120
+ ├── docs/
121
+ │ └── setup.md
122
+ ├── src/
123
+ │ └── shop/
124
+ │ ├── billing/
125
+ │ │ └── pay.py
126
+ │ ├── cart.py
127
+ │ └── index.html
128
+ ├── README.md
129
+ └── data.json
130
+ ```
131
+
132
+ Add `--copy` to also put the tree on your clipboard, ready to paste into a chat, an issue or a doc.
133
+
134
+ ```bash
135
+ ramani --copy # print the tree and copy it
136
+ ramani ./src -t -d tests # tree of ./src, leaving out tests
137
+ ```
138
+
139
+ > On Linux, the clipboard needs `xclip`, `xsel` or `wl-clipboard` installed. If none is available the tree is still printed, with a note on stderr and exit code 1.
140
+
141
+ ## Options
142
+
143
+ | Option | What it does |
144
+ | ------------------------------- | ------------------------------------------------------------------- |
145
+ | `PATH` | Folder or file to process (default: current folder) |
146
+ | `-e, --ignore-ext EXT` | Also skip this extension, e.g. `-e .txt` (repeatable) |
147
+ | `-d, --ignore-dir NAME` | Also skip this folder name or glob, e.g. `-d "build*"` (repeatable) |
148
+ | `-c, --comment EXT=START[,END]` | Comment style for an extension or file name (repeatable) |
149
+ | `--no-gitignore` | Ignore `.gitignore` files |
150
+ | `-n, --dry-run` | Show what would change, write nothing |
151
+ | `--check` | Dry run that exits 1 if anything is missing or stale |
152
+ | `--remove` | Strip ramani comments instead of adding them |
153
+ | `-t, --tree` | Print the folder tree instead of marking files |
154
+ | `--copy` | Copy the tree to the clipboard (implies `--tree`) |
155
+ | `-V, --version` | Print the installed version and exit |
156
+ | `-v, --verbose` | Also list unchanged files |
157
+
158
+ ## Configuration
159
+
160
+ Teach ramani a file type on the command line:
161
+
162
+ ```bash
163
+ ramani -c .abc=// # line comment
164
+ ramani -c ".tpl=<!--,-->" # block comment: start,end
165
+ ramani -c Jenkinsfile=// # by exact file name
166
+ ```
167
+
168
+ or once and for all in your `pyproject.toml`:
169
+
170
+ ```toml
171
+ [tool.ramani.comments]
172
+ ".abc" = "//"
173
+ ".tpl" = ["<!--", "-->"]
174
+ ```
175
+
176
+ Flags beat `pyproject.toml`, which beats the built-in styles, so you can override those too.
177
+
178
+ ## Supported files
179
+
180
+ | Comment | Looks like | Files |
181
+ | ---------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
182
+ | `#` | `# ramani: a/b.py` | `.py` `.pyi` `.sh` `.rb` `.pl` `.r` `.jl` `.ex` `.yml` `.yaml` `.toml` `.cfg` `.tf` `.ps1` `.nix` `Dockerfile` `Makefile` `.gitignore` … |
183
+ | `//` | `// ramani: a/b.ts` | `.js` `.mjs` `.jsx` `.ts` `.tsx` `.java` `.kt` `.scala` `.c` `.h` `.cpp` `.cs` `.go` `.rs` `.swift` `.dart` `.scss` `.proto` … |
184
+ | `--` | `-- ramani: a/b.sql` | `.sql` `.lua` `.hs` `.elm` |
185
+ | `<!-- -->` | `<!-- ramani: a/b.html -->` | `.html` `.htm` `.xml` `.svg` `.vue` `.svelte` `.md` `.markdown` |
186
+ | `/* */` | `/* ramani: a/b.css */` | `.css` |
187
+ | `{# #}` | `{# ramani: a/b.j2 #}` | `.j2` `.jinja` `.jinja2` |
188
+ | `{/* */}` | `{/* ramani: a/b.mdx */}` | `.mdx` |
189
+ | `%` | `% ramani: a/b.tex` | `.tex` |
190
+
191
+ Formats with no comment syntax, such as `.json` and `.csv`, are left alone and listed at the end of each run so nothing is skipped silently. The full table lives in `src/ramani/config.py`.
192
+
193
+ ## How it works
194
+
195
+ 1. Skip anything that must stay first: a shebang, an encoding line, an XML declaration, a `# syntax=` line, or front matter in Markdown.
196
+ 2. Look at the next line. If it is a ramani comment with the **same** path, do nothing.
197
+ 3. If it is a ramani comment with a **different** path, the file has moved. Rewrite that one line.
198
+ 4. If it is not a ramani comment, insert one.
199
+
200
+ Line endings (LF or CRLF) and UTF-8 byte-order marks are preserved. Symlinks, files that are not UTF-8, and binary files (anything containing a NUL byte) are never touched.
201
+
202
+ ## Development
203
+
204
+ ```bash
205
+ uv sync
206
+ uv run poe test
207
+ ```
208
+
209
+ Ramani has a single runtime dependency, [`pyperclip`](https://pypi.org/project/pyperclip/), used only for `--copy`.
210
+
211
+ ## License
212
+
213
+ MIT © Kevin Wasike Wakhisi. Use it, change it, ship it; just keep the copyright notice.
@@ -0,0 +1,94 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.13.7,<0.14.0"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "ramani"
7
+ version = "0.1.0a1"
8
+ description = "Ramani (Swahili for “map”): keeps each file's path as a comment on its first line, updates it when files move, and prints your project as a tree."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.13"
13
+ keywords = [
14
+ "comments",
15
+ "paths",
16
+ "tree",
17
+ "project-structure",
18
+ "cli",
19
+ "swahili",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 3 - Alpha",
23
+ "Environment :: Console",
24
+ "Intended Audience :: Developers",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3 :: Only",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Python :: 3.14",
30
+ "Programming Language :: Python :: 3.15",
31
+ "Topic :: Software Development",
32
+ "Topic :: Utilities",
33
+ ]
34
+ dependencies = ["pyperclip>=1.8"]
35
+
36
+ [[project.authors]]
37
+ name = "Kevin Wasike Wakhisi"
38
+ email = "kevin@treeolive.tech"
39
+
40
+ [[project.maintainers]]
41
+ name = "Kevin Wasike Wakhisi"
42
+ email = "kevin@treeolive.tech"
43
+
44
+ [project.scripts]
45
+ ramani = "ramani:main"
46
+
47
+ [project.urls]
48
+ Repository = "https://github.com/kvnwaks/ramani.git"
49
+
50
+ [dependency-groups]
51
+ dev = [
52
+ "pytest>=9.2.0",
53
+ "poethepoet>=0.49.0",
54
+ ]
55
+
56
+ [tool.uv]
57
+ preview-features = [
58
+ "format-command",
59
+ "check-command",
60
+ ]
61
+
62
+ [[tool.uv.index]]
63
+ name = "testpypi"
64
+ url = "https://test.pypi.org/simple/"
65
+ publish-url = "https://test.pypi.org/legacy/"
66
+ explicit = true
67
+
68
+ [tool.pytest.ini_options]
69
+ pythonpath = ["src"]
70
+ testpaths = ["tests"]
71
+
72
+ [[tool.poe.tasks.format.sequence]]
73
+ cmd = "uv format"
74
+
75
+ [[tool.poe.tasks.lint.sequence]]
76
+ cmd = "uv lock --check"
77
+
78
+ [[tool.poe.tasks.lint.sequence]]
79
+ cmd = "uv format --check"
80
+
81
+ [[tool.poe.tasks.lint.sequence]]
82
+ cmd = "uv check"
83
+
84
+ [[tool.poe.tasks.test.sequence]]
85
+ cmd = "uv run pytest"
86
+
87
+ [[tool.poe.tasks.add.sequence]]
88
+ ref = "lint"
89
+
90
+ [[tool.poe.tasks.add.sequence]]
91
+ ref = "test"
92
+
93
+ [[tool.poe.tasks.add.sequence]]
94
+ cmd = "git add ."
@@ -0,0 +1,70 @@
1
+ # ramani: pyproject.toml
2
+ [build-system]
3
+ requires = ["uv_build>=0.13.7,<0.14.0"]
4
+ build-backend = "uv_build"
5
+
6
+ [project]
7
+ name = "ramani"
8
+ version = "0.1.0a1"
9
+ description = "Ramani (Swahili for “map”): keeps each file's path as a comment on its first line, updates it when files move, and prints your project as a tree."
10
+ readme = "README.md"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Kevin Wasike Wakhisi", email = "kevin@treeolive.tech" }]
14
+ maintainers = [
15
+ { name = "Kevin Wasike Wakhisi", email = "kevin@treeolive.tech" },
16
+ ]
17
+ requires-python = ">=3.13"
18
+ keywords = ["comments", "paths", "tree", "project-structure", "cli", "swahili"]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Environment :: Console",
22
+ "Intended Audience :: Developers",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3 :: Only",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Programming Language :: Python :: 3.15",
29
+ "Topic :: Software Development",
30
+ "Topic :: Utilities",
31
+ ]
32
+ dependencies = ["pyperclip>=1.8"]
33
+
34
+ [project.scripts]
35
+ ramani = "ramani:main"
36
+
37
+ [project.urls]
38
+ Repository = "https://github.com/kvnwaks/ramani.git"
39
+
40
+ [dependency-groups]
41
+ dev = ["pytest>=9.2.0", "poethepoet>=0.49.0"]
42
+
43
+ [tool.uv]
44
+ preview-features = ["format-command", "check-command"]
45
+
46
+ [tool.pytest.ini_options]
47
+ pythonpath = ["src"]
48
+ testpaths = ["tests"]
49
+
50
+ [tool.poe.tasks.format]
51
+ sequence = [{ cmd = "uv format" }]
52
+
53
+ [tool.poe.tasks.lint]
54
+ sequence = [
55
+ { cmd = "uv lock --check" },
56
+ { cmd = "uv format --check" },
57
+ { cmd = "uv check" },
58
+ ]
59
+
60
+ [tool.poe.tasks.test]
61
+ sequence = [{ cmd = "uv run pytest" }]
62
+
63
+ [tool.poe.tasks.add]
64
+ sequence = [{ ref = "lint" }, { ref = "test" }, { cmd = "git add ." }]
65
+
66
+ [[tool.uv.index]]
67
+ name = "testpypi"
68
+ url = "https://test.pypi.org/simple/"
69
+ publish-url = "https://test.pypi.org/legacy/"
70
+ explicit = true
@@ -0,0 +1,7 @@
1
+ # ramani: src/ramani/__init__.py
2
+ """ramani (Swahili for "map"): keep a path comment at the top of every source file."""
3
+
4
+ from .cli import main
5
+ from .core import mark_text, run, strip_text
6
+
7
+ __all__ = ["main", "mark_text", "run", "strip_text"]
@@ -0,0 +1,6 @@
1
+ # ramani: src/ramani/__main__.py
2
+ """Allow ``python -m ramani``."""
3
+
4
+ from .cli import main
5
+
6
+ raise SystemExit(main())