codemap-cli 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.
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: codemap-cli
3
+ Version: 0.1.0
4
+ Summary: A deterministic filesystem mapper optimized for AI context
5
+ Author: Purva Sanjay Patel
6
+ Requires-Python: >=3.9
7
+ Requires-Dist: typer
Binary file
@@ -0,0 +1,14 @@
1
+ [project]
2
+ name = "codemap-cli"
3
+ version = "0.1.0"
4
+ description = "A deterministic filesystem mapper optimized for AI context"
5
+ authors = [{ name = "Purva Sanjay Patel" }]
6
+ dependencies = ["typer"]
7
+ requires-python = ">=3.9"
8
+
9
+ [project.scripts]
10
+ codemap = "codemap.cli:app"
11
+
12
+ [build-system]
13
+ requires = ["setuptools", "wheel"]
14
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,74 @@
1
+ import typer
2
+ from pathlib import Path
3
+ from .root import find_project_root, detect_plugin
4
+ from .scanner import build_tree
5
+ from .formatter import format_tree
6
+ from .writer import build_markdown, write_file
7
+
8
+ app = typer.Typer(invoke_without_command=True)
9
+
10
+
11
+ @app.callback()
12
+ def main():
13
+ start_path = Path.cwd()
14
+
15
+ root = find_project_root(start_path)
16
+
17
+ if not root:
18
+ typer.secho(
19
+ "Error: No project root detected.",
20
+ fg=typer.colors.RED,
21
+ )
22
+ raise typer.Exit(code=1)
23
+
24
+ if root != start_path:
25
+ typer.secho(
26
+ f"Detected project root at: {root}",
27
+ fg=typer.colors.CYAN,
28
+ )
29
+
30
+ plugin = detect_plugin(root)
31
+
32
+ output_file = root / "codemap.md"
33
+
34
+ # Build tree
35
+ tree = build_tree(root, plugin)
36
+ tree_text = format_tree(tree)
37
+
38
+ # Build full markdown content
39
+ new_content = build_markdown(
40
+ tree_text,
41
+ root,
42
+ plugin.name if plugin else "unknown",
43
+ )
44
+
45
+ if output_file.exists():
46
+ old_content = output_file.read_text(encoding="utf-8")
47
+
48
+ # Extract old tree block
49
+ if "```" in old_content:
50
+ old_tree = old_content.split("```")[1].strip()
51
+ else:
52
+ old_tree = ""
53
+
54
+ if old_tree == tree_text.strip():
55
+ typer.secho(
56
+ "No structural changes detected. codemap.md is up to date.",
57
+ fg=typer.colors.BLUE,
58
+ )
59
+ raise typer.Exit()
60
+
61
+ # Structure changed → rewrite file with new timestamp
62
+ write_file(output_file, new_content)
63
+
64
+ typer.secho(
65
+ "codemap.md updated successfully.",
66
+ fg=typer.colors.YELLOW,
67
+ )
68
+ else:
69
+ write_file(output_file, new_content)
70
+
71
+ typer.secho(
72
+ "codemap.md generated successfully.",
73
+ fg=typer.colors.GREEN,
74
+ )
@@ -0,0 +1,11 @@
1
+ GLOBAL_IGNORE = [
2
+ ".git",
3
+ ".idea",
4
+ ".vscode",
5
+ ]
6
+
7
+ GLOBAL_HIDDEN_FILES = [
8
+ ".env",
9
+ ".env.local",
10
+ ".env.production",
11
+ ]
@@ -0,0 +1,18 @@
1
+ def format_tree(tree):
2
+ lines = [tree["name"]]
3
+
4
+ def _format(node, prefix=""):
5
+ children = node.get("children", [])
6
+ total = len(children)
7
+
8
+ for index, child in enumerate(children):
9
+ connector = "└── " if index == total - 1 else "├── "
10
+ line = prefix + connector + child["name"]
11
+ lines.append(line)
12
+
13
+ if child["type"] == "dir" and not child.get("collapsed"):
14
+ extension = " " if index == total - 1 else "│ "
15
+ _format(child, prefix + extension)
16
+
17
+ _format(tree)
18
+ return "\n".join(lines)
File without changes
@@ -0,0 +1,23 @@
1
+ class BasePlugin:
2
+ name = "base"
3
+
4
+ # Files that indicate the current framework
5
+ detection_files = []
6
+
7
+ # Files to ignore when scanning the code
8
+ ignore = set()
9
+
10
+ # Show folder but do not traverse inside
11
+ collapse = set()
12
+
13
+ # Files that should never be shown
14
+ hidden_files = set()
15
+
16
+ def matches(self, root_path):
17
+ from pathlib import Path
18
+
19
+ for file in self.detection_files:
20
+ if (Path(root_path) / file).exists():
21
+ return True
22
+ return False
23
+
@@ -0,0 +1,22 @@
1
+ from .base import BasePlugin
2
+
3
+
4
+ class JavaScriptPlugin(BasePlugin):
5
+ name = "javascript"
6
+
7
+ detection_files = ["package.json"]
8
+
9
+ ignore = {
10
+ ".next",
11
+ "dist",
12
+ "build",
13
+ }
14
+
15
+ collapse = {
16
+ "node_modules",
17
+ }
18
+
19
+ hidden_files = {
20
+ ".env",
21
+ ".env.local",
22
+ }
@@ -0,0 +1,23 @@
1
+ from .base import BasePlugin
2
+
3
+ class PythonPlugin(BasePlugin):
4
+ name = "python"
5
+
6
+ detection_files = ["pyproject.toml","requirements.txt","setup.py"]
7
+
8
+ ignore = {
9
+ "__pycache__",
10
+ ".venv",
11
+ "venv",
12
+ "env",
13
+ ".env",
14
+ ".mypy_cache",
15
+ ".pytest_cache",
16
+ }
17
+
18
+ collapse = set()
19
+
20
+ hidden_files = {
21
+ ".env",
22
+ ".env.local",
23
+ }
@@ -0,0 +1,29 @@
1
+ from pathlib import Path
2
+ from .plugins.python import PythonPlugin
3
+ from .plugins.javascript import JavaScriptPlugin
4
+
5
+ PLUGINS = [
6
+ PythonPlugin(),
7
+ JavaScriptPlugin(),
8
+ ]
9
+
10
+ def find_project_root(start_path: Path) -> Path | None:
11
+ current = start_path.resolve()
12
+
13
+ while current != current.parent:
14
+ for plugin in PLUGINS:
15
+ for marker in plugin.detection_files:
16
+ if (current / marker).exists():
17
+ return current
18
+ if (current / ".git").exists():
19
+ return current
20
+ current = current.parent
21
+
22
+ return None
23
+
24
+
25
+ def detect_plugin(root_path: Path):
26
+ for plugin in PLUGINS:
27
+ if plugin.matches(root_path):
28
+ return plugin
29
+ return None
@@ -0,0 +1,49 @@
1
+ from pathlib import Path
2
+ from .constants import GLOBAL_IGNORE, GLOBAL_HIDDEN_FILES
3
+
4
+
5
+ def build_tree(path: Path, plugin):
6
+ name = path.name
7
+
8
+ if path.is_file():
9
+ return {
10
+ "type": "file",
11
+ "name": name,
12
+ }
13
+
14
+ children = []
15
+
16
+ for item in sorted(path.iterdir(), key=lambda x: x.name.lower()):
17
+ if item.name in GLOBAL_IGNORE:
18
+ continue
19
+
20
+ if plugin and item.name in plugin.ignore:
21
+ continue
22
+
23
+ if item.name in GLOBAL_HIDDEN_FILES:
24
+ continue
25
+
26
+ if plugin and item.name in plugin.hidden_files:
27
+ continue
28
+
29
+ if item.name.endswith(".egg-info"):
30
+ continue
31
+
32
+ if item.is_dir() and plugin and item.name in plugin.collapse:
33
+ children.append({
34
+ "type": "dir",
35
+ "name": item.name,
36
+ "collapsed": True,
37
+ })
38
+ continue
39
+
40
+ children.append(build_tree(item, plugin))
41
+
42
+ if item.name == "codemap.md":
43
+ continue
44
+
45
+ return {
46
+ "type": "dir",
47
+ "name": name,
48
+ "children": children,
49
+ }
@@ -0,0 +1,20 @@
1
+ from datetime import datetime
2
+
3
+
4
+ def build_markdown(tree_text: str, root_path, plugin_name: str) -> str:
5
+ header = (
6
+ "# CodeMap\n\n"
7
+ f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
8
+ f"Root: {root_path}\n"
9
+ f"Framework: {plugin_name}\n\n"
10
+ "```\n"
11
+ )
12
+
13
+ footer = "\n```\n"
14
+
15
+ return header + tree_text + footer
16
+
17
+
18
+ def write_file(output_path, content: str):
19
+ with open(output_path, "w", encoding="utf-8") as f:
20
+ f.write(content)
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: codemap-cli
3
+ Version: 0.1.0
4
+ Summary: A deterministic filesystem mapper optimized for AI context
5
+ Author: Purva Sanjay Patel
6
+ Requires-Python: >=3.9
7
+ Requires-Dist: typer
@@ -0,0 +1,19 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/codemap/__init__.py
4
+ src/codemap/cli.py
5
+ src/codemap/constants.py
6
+ src/codemap/formatter.py
7
+ src/codemap/root.py
8
+ src/codemap/scanner.py
9
+ src/codemap/writer.py
10
+ src/codemap/plugins/__init__.py
11
+ src/codemap/plugins/base.py
12
+ src/codemap/plugins/javascript.py
13
+ src/codemap/plugins/python.py
14
+ src/codemap_cli.egg-info/PKG-INFO
15
+ src/codemap_cli.egg-info/SOURCES.txt
16
+ src/codemap_cli.egg-info/dependency_links.txt
17
+ src/codemap_cli.egg-info/entry_points.txt
18
+ src/codemap_cli.egg-info/requires.txt
19
+ src/codemap_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ codemap = codemap.cli:app