context-gen-cli 1.2.5__tar.gz → 1.3.5__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 (24) hide show
  1. context_gen_cli-1.3.5/PKG-INFO +192 -0
  2. context_gen_cli-1.3.5/README.md +164 -0
  3. context_gen_cli-1.3.5/context_gen/cli.py +242 -0
  4. context_gen_cli-1.3.5/context_gen/distill.py +107 -0
  5. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/scanner.py +18 -0
  6. context_gen_cli-1.3.5/context_gen_cli.egg-info/PKG-INFO +192 -0
  7. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen_cli.egg-info/SOURCES.txt +1 -0
  8. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen_cli.egg-info/requires.txt +2 -1
  9. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/pyproject.toml +3 -2
  10. context_gen_cli-1.2.5/PKG-INFO +0 -115
  11. context_gen_cli-1.2.5/README.md +0 -88
  12. context_gen_cli-1.2.5/context_gen/cli.py +0 -507
  13. context_gen_cli-1.2.5/context_gen_cli.egg-info/PKG-INFO +0 -115
  14. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/__init__.py +0 -0
  15. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/extractor.py +0 -0
  16. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/generator.py +0 -0
  17. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/graph.py +0 -0
  18. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/mcp/__init__.py +0 -0
  19. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen/mcp/advanced_tools.py +0 -0
  20. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen_cli.egg-info/dependency_links.txt +0 -0
  21. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen_cli.egg-info/entry_points.txt +0 -0
  22. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/context_gen_cli.egg-info/top_level.txt +0 -0
  23. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/setup.cfg +0 -0
  24. {context_gen_cli-1.2.5 → context_gen_cli-1.3.5}/tests/test_advanced_tools.py +0 -0
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: context-gen-cli
3
+ Version: 1.3.5
4
+ Summary: A modern CLI tool that scans any project, builds an AST-based dependency graph, and generates structured LLM context (agent.md / agent.json).
5
+ Author: yakkshit
6
+ License-Expression: MIT
7
+ Keywords: llm,context,agent,cli,code-analysis,ast,graph,mcp
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Code Generators
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: typer>=0.12.0
21
+ Requires-Dist: rich>=13.7.0
22
+ Requires-Dist: shellingham>=1.5.4
23
+ Requires-Dist: pathspec>=0.12.1
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
26
+ Requires-Dist: build>=1.1.0; extra == "dev"
27
+ Requires-Dist: twine>=5.0.0; extra == "dev"
28
+
29
+ # ⚡ context-gen-cli (`ctx`) — Python Edition
30
+
31
+ <p align="center">
32
+ <a href="https://pypi.org/project/context-gen-cli/"><img src="https://img.shields.io/pypi/v/context-gen-cli.svg?color=3775a9" alt="PyPI version" /></a>
33
+ <a href="https://pypi.org/project/context-gen-cli/"><img src="https://img.shields.io/pypi/pyversions/context-gen-cli.svg" alt="Python Versions" /></a>
34
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Protocol%20Ready-6366f1.svg" alt="MCP Ready" /></a>
35
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License" /></a>
36
+ <a href="https://resume.cedzlabs.com/labs"><img src="https://img.shields.io/badge/Cedzlabs-Labs%20%E2%86%97-cyan.svg" alt="Cedzlabs Labs" /></a>
37
+ </p>
38
+
39
+ > **Stop dumping 50,000 raw tokens into your AI coding agent.**
40
+ > `context-gen-cli` analyzes any codebase using native AST parsers and **Entropy-Guided Reference Distillation (EGRD)** to give Cursor, Antigravity, Claude Code, and VS Code an ultra-dense **~40-token Senior Engineer Context Plan**—or stops to ask targeted questions if your prompt is ambiguous.
41
+
42
+ ---
43
+
44
+ ### 💡 Package Name vs. Command Alias
45
+
46
+ | What you install | What you run in your terminal |
47
+ | :--- | :--- |
48
+ | `pip install context-gen-cli` | **`ctx`** |
49
+
50
+ > **Why `ctx`?** While the package is registered as `context-gen-cli` on PyPI and npm, you shouldn't have to type 15 characters every time you run a command. The binary alias **`ctx`** is automatically registered upon installation. (The full `context-gen` alias is also preserved for scripts).
51
+
52
+ ---
53
+
54
+ ## 🌟 Highlights
55
+
56
+ - **⚡ Fast Short Alias (`ctx`)**: Type `ctx` anywhere in your terminal.
57
+ - **🧠 Entropy-Guided Reference Distillation (EGRD)**: Calculates Shannon Entropy ($H$) over codebase signatures to filter 98.5% of prompt noise.
58
+ - **🛡️ Anti-Hallucination Clarification Gate**: If your prompt is ambiguous ($H \ge 1.50\text{ bits}$), `ctx` halts guessing and asks targeted questions using real paths from your repo.
59
+ - **🕸️ 100% Accurate AST Knowledge Graph**: Uses native AST traversal to resolve relative imports, exports, roles, and downstream **Blast Radius** (what files break if this changes).
60
+ - **🔋 Zero GPU / CUDA Bloat**: Strictly capped at 1–2 CPU cores. No 15GB PyTorch downloads or local embedding models.
61
+ - **📁 Clean Monorepo / Workspace Storage**: Saves context models neatly into `context/agent.md`, `context/agent.json`, and `context/agent.yaml`.
62
+ - **🔒 Security Filter**: Strips virtual environments (`.venv*`, `venv*`), `.env*` files, pem/key certificates, and secrets automatically.
63
+
64
+ ---
65
+
66
+ ## 📦 Installation
67
+
68
+ ```bash
69
+ # Standard installation
70
+ pip install context-gen-cli
71
+
72
+ # Or with pipx (recommended for isolated global CLI tools)
73
+ pipx install context-gen-cli
74
+
75
+ # Or with uv
76
+ uv tool install context-gen-cli
77
+ ```
78
+
79
+ Verify installation:
80
+ ```bash
81
+ ctx --help
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 🚀 Everyday Workflows & Examples
87
+
88
+ ### 1. ⚡ All-In-One Workspace Mode (`ctx -d`)
89
+ Generates triple context formats (`agent.md`, `agent.json`, `agent.yaml`) in `context/` and runs a live auto-sync watcher in the background:
90
+ ```bash
91
+ ctx -d
92
+ ```
93
+
94
+ ### 2. 🎯 Distill a Specific Prompt (`ctx distill`)
95
+ Generate a dense Senior Engineer Blueprint for any task:
96
+ ```bash
97
+ ctx distill "add jwt refresh token rotation to authentication"
98
+ ```
99
+
100
+ **Output:**
101
+ ```text
102
+ ╔═══════════════════════════════════════════════════════════════╗
103
+ ║ 🧠 SENIOR ENGINEER CONTEXT PLAN (EGRD Distilled) ║
104
+ ╚═══════════════════════════════════════════════════════════════╝
105
+
106
+ 🎯 Task: add jwt refresh token rotation to authentication
107
+ ⚙️ Engineering Mode: Architecture / Refactor
108
+
109
+ 📂 Primary Files to Reference:
110
+ ✔ src/services/auth.py
111
+ ✔ src/routes/auth_routes.py
112
+ ✔ src/models/user.py
113
+
114
+ 💥 Blast Radius (Downstream Callers):
115
+ src/middleware/guard.py, src/app.py
116
+
117
+ 🛡️ Architecture Guardrail:
118
+ Changes affect 2 downstream callers. Verify token payload backward compatibility.
119
+ ```
120
+
121
+ ### 3. ⚠️ The Clarification Gate (Ambiguous Prompts)
122
+ If you provide a vague prompt like:
123
+ ```bash
124
+ ctx distill "update config"
125
+ ```
126
+ Instead of hallucinating or dumping the entire repository, `ctx` pauses and shows:
127
+ ```text
128
+ ╔═══════════════════════════════════════════════════════════════╗
129
+ ║ ⚠️ CLARIFICATION NEEDED — Ambiguous Prompt Detected ║
130
+ ╚═══════════════════════════════════════════════════════════════╝
131
+
132
+ ▸ Prompt entropy H = 1.84 bits exceeds confident threshold (1.50 bits).
133
+ ▸ Disambiguate by specifying target:
134
+ 1. src/config/database.py
135
+ 2. src/config/server.py
136
+ 3. src/config/redis.py
137
+ ```
138
+
139
+ ### 4. 📊 Check Token Weight & Savings (`ctx --tokens`)
140
+ Inspect how much context weight your AI agent saves compared to raw directory dumps:
141
+ ```bash
142
+ ctx --tokens
143
+ ```
144
+
145
+ ---
146
+
147
+ ## 📖 CLI Reference
148
+
149
+ | Command | Description |
150
+ | :--- | :--- |
151
+ | `ctx` | Scans workspace and generates `agent.md`, `agent.json`, `agent.yaml` in `context/` |
152
+ | `ctx -d` / `ctx --default` | **⚡ All-in-One**: Generates context and starts live file-watching sync |
153
+ | `ctx distill "<prompt>"` | **🧠 EGRD Distiller**: Generates high-signal Senior Engineer Blueprint |
154
+ | `ctx -w` / `ctx --watch` | **👀 Watch Mode**: Watches codebase and auto-updates context files on save |
155
+ | `ctx --tokens` | **📊 Token Analytics**: Displays token counts and compression ratios |
156
+ | `ctx -o <dir>` | **📁 Custom Output**: Specify output directory (defaults to `context/`) |
157
+ | `ctx -f <format>` | **📄 Format Filter**: Choose `md`, `json`, `yaml`, or `all` |
158
+ | `ctx update` | **🔄 Quick Refresh**: Re-indexes the current workspace |
159
+ | `ctx --help` | View full options and flag descriptions |
160
+
161
+ ---
162
+
163
+ ## 🛠️ MCP (Model Context Protocol) Integration
164
+
165
+ `ctx` can act as an MCP server for **Cursor**, **Claude Desktop**, **Antigravity**, and **VS Code**:
166
+
167
+ Add to your MCP settings (`claude_desktop_config.json` or Cursor Settings):
168
+ ```json
169
+ {
170
+ "mcpServers": {
171
+ "context-gen": {
172
+ "command": "ctx",
173
+ "args": ["-d"]
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 🤝 Ecosystem & Links
182
+
183
+ - **Documentation & Showcase:** [https://resume.cedzlabs.com/labs](https://resume.cedzlabs.com/labs)
184
+ - **Node.js (npm):** `npx context-gen-cli@latest`
185
+ - **Homebrew (macOS):** `brew install context-gen-cli`
186
+ - **GitHub Repository:** [https://github.com/yakkshit/context-gen](https://github.com/yakkshit/context-gen)
187
+
188
+ ---
189
+
190
+ ## 📄 License
191
+
192
+ MIT © [Yakkshit](https://github.com/yakkshit) & [Cedzlabs](https://resume.cedzlabs.com/labs)
@@ -0,0 +1,164 @@
1
+ # ⚡ context-gen-cli (`ctx`) — Python Edition
2
+
3
+ <p align="center">
4
+ <a href="https://pypi.org/project/context-gen-cli/"><img src="https://img.shields.io/pypi/v/context-gen-cli.svg?color=3775a9" alt="PyPI version" /></a>
5
+ <a href="https://pypi.org/project/context-gen-cli/"><img src="https://img.shields.io/pypi/pyversions/context-gen-cli.svg" alt="Python Versions" /></a>
6
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Protocol%20Ready-6366f1.svg" alt="MCP Ready" /></a>
7
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License" /></a>
8
+ <a href="https://resume.cedzlabs.com/labs"><img src="https://img.shields.io/badge/Cedzlabs-Labs%20%E2%86%97-cyan.svg" alt="Cedzlabs Labs" /></a>
9
+ </p>
10
+
11
+ > **Stop dumping 50,000 raw tokens into your AI coding agent.**
12
+ > `context-gen-cli` analyzes any codebase using native AST parsers and **Entropy-Guided Reference Distillation (EGRD)** to give Cursor, Antigravity, Claude Code, and VS Code an ultra-dense **~40-token Senior Engineer Context Plan**—or stops to ask targeted questions if your prompt is ambiguous.
13
+
14
+ ---
15
+
16
+ ### 💡 Package Name vs. Command Alias
17
+
18
+ | What you install | What you run in your terminal |
19
+ | :--- | :--- |
20
+ | `pip install context-gen-cli` | **`ctx`** |
21
+
22
+ > **Why `ctx`?** While the package is registered as `context-gen-cli` on PyPI and npm, you shouldn't have to type 15 characters every time you run a command. The binary alias **`ctx`** is automatically registered upon installation. (The full `context-gen` alias is also preserved for scripts).
23
+
24
+ ---
25
+
26
+ ## 🌟 Highlights
27
+
28
+ - **⚡ Fast Short Alias (`ctx`)**: Type `ctx` anywhere in your terminal.
29
+ - **🧠 Entropy-Guided Reference Distillation (EGRD)**: Calculates Shannon Entropy ($H$) over codebase signatures to filter 98.5% of prompt noise.
30
+ - **🛡️ Anti-Hallucination Clarification Gate**: If your prompt is ambiguous ($H \ge 1.50\text{ bits}$), `ctx` halts guessing and asks targeted questions using real paths from your repo.
31
+ - **🕸️ 100% Accurate AST Knowledge Graph**: Uses native AST traversal to resolve relative imports, exports, roles, and downstream **Blast Radius** (what files break if this changes).
32
+ - **🔋 Zero GPU / CUDA Bloat**: Strictly capped at 1–2 CPU cores. No 15GB PyTorch downloads or local embedding models.
33
+ - **📁 Clean Monorepo / Workspace Storage**: Saves context models neatly into `context/agent.md`, `context/agent.json`, and `context/agent.yaml`.
34
+ - **🔒 Security Filter**: Strips virtual environments (`.venv*`, `venv*`), `.env*` files, pem/key certificates, and secrets automatically.
35
+
36
+ ---
37
+
38
+ ## 📦 Installation
39
+
40
+ ```bash
41
+ # Standard installation
42
+ pip install context-gen-cli
43
+
44
+ # Or with pipx (recommended for isolated global CLI tools)
45
+ pipx install context-gen-cli
46
+
47
+ # Or with uv
48
+ uv tool install context-gen-cli
49
+ ```
50
+
51
+ Verify installation:
52
+ ```bash
53
+ ctx --help
54
+ ```
55
+
56
+ ---
57
+
58
+ ## 🚀 Everyday Workflows & Examples
59
+
60
+ ### 1. ⚡ All-In-One Workspace Mode (`ctx -d`)
61
+ Generates triple context formats (`agent.md`, `agent.json`, `agent.yaml`) in `context/` and runs a live auto-sync watcher in the background:
62
+ ```bash
63
+ ctx -d
64
+ ```
65
+
66
+ ### 2. 🎯 Distill a Specific Prompt (`ctx distill`)
67
+ Generate a dense Senior Engineer Blueprint for any task:
68
+ ```bash
69
+ ctx distill "add jwt refresh token rotation to authentication"
70
+ ```
71
+
72
+ **Output:**
73
+ ```text
74
+ ╔═══════════════════════════════════════════════════════════════╗
75
+ ║ 🧠 SENIOR ENGINEER CONTEXT PLAN (EGRD Distilled) ║
76
+ ╚═══════════════════════════════════════════════════════════════╝
77
+
78
+ 🎯 Task: add jwt refresh token rotation to authentication
79
+ ⚙️ Engineering Mode: Architecture / Refactor
80
+
81
+ 📂 Primary Files to Reference:
82
+ ✔ src/services/auth.py
83
+ ✔ src/routes/auth_routes.py
84
+ ✔ src/models/user.py
85
+
86
+ 💥 Blast Radius (Downstream Callers):
87
+ src/middleware/guard.py, src/app.py
88
+
89
+ 🛡️ Architecture Guardrail:
90
+ Changes affect 2 downstream callers. Verify token payload backward compatibility.
91
+ ```
92
+
93
+ ### 3. ⚠️ The Clarification Gate (Ambiguous Prompts)
94
+ If you provide a vague prompt like:
95
+ ```bash
96
+ ctx distill "update config"
97
+ ```
98
+ Instead of hallucinating or dumping the entire repository, `ctx` pauses and shows:
99
+ ```text
100
+ ╔═══════════════════════════════════════════════════════════════╗
101
+ ║ ⚠️ CLARIFICATION NEEDED — Ambiguous Prompt Detected ║
102
+ ╚═══════════════════════════════════════════════════════════════╝
103
+
104
+ ▸ Prompt entropy H = 1.84 bits exceeds confident threshold (1.50 bits).
105
+ ▸ Disambiguate by specifying target:
106
+ 1. src/config/database.py
107
+ 2. src/config/server.py
108
+ 3. src/config/redis.py
109
+ ```
110
+
111
+ ### 4. 📊 Check Token Weight & Savings (`ctx --tokens`)
112
+ Inspect how much context weight your AI agent saves compared to raw directory dumps:
113
+ ```bash
114
+ ctx --tokens
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 📖 CLI Reference
120
+
121
+ | Command | Description |
122
+ | :--- | :--- |
123
+ | `ctx` | Scans workspace and generates `agent.md`, `agent.json`, `agent.yaml` in `context/` |
124
+ | `ctx -d` / `ctx --default` | **⚡ All-in-One**: Generates context and starts live file-watching sync |
125
+ | `ctx distill "<prompt>"` | **🧠 EGRD Distiller**: Generates high-signal Senior Engineer Blueprint |
126
+ | `ctx -w` / `ctx --watch` | **👀 Watch Mode**: Watches codebase and auto-updates context files on save |
127
+ | `ctx --tokens` | **📊 Token Analytics**: Displays token counts and compression ratios |
128
+ | `ctx -o <dir>` | **📁 Custom Output**: Specify output directory (defaults to `context/`) |
129
+ | `ctx -f <format>` | **📄 Format Filter**: Choose `md`, `json`, `yaml`, or `all` |
130
+ | `ctx update` | **🔄 Quick Refresh**: Re-indexes the current workspace |
131
+ | `ctx --help` | View full options and flag descriptions |
132
+
133
+ ---
134
+
135
+ ## 🛠️ MCP (Model Context Protocol) Integration
136
+
137
+ `ctx` can act as an MCP server for **Cursor**, **Claude Desktop**, **Antigravity**, and **VS Code**:
138
+
139
+ Add to your MCP settings (`claude_desktop_config.json` or Cursor Settings):
140
+ ```json
141
+ {
142
+ "mcpServers": {
143
+ "context-gen": {
144
+ "command": "ctx",
145
+ "args": ["-d"]
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 🤝 Ecosystem & Links
154
+
155
+ - **Documentation & Showcase:** [https://resume.cedzlabs.com/labs](https://resume.cedzlabs.com/labs)
156
+ - **Node.js (npm):** `npx context-gen-cli@latest`
157
+ - **Homebrew (macOS):** `brew install context-gen-cli`
158
+ - **GitHub Repository:** [https://github.com/yakkshit/context-gen](https://github.com/yakkshit/context-gen)
159
+
160
+ ---
161
+
162
+ ## 📄 License
163
+
164
+ MIT © [Yakkshit](https://github.com/yakkshit) & [Cedzlabs](https://resume.cedzlabs.com/labs)
@@ -0,0 +1,242 @@
1
+ """
2
+ context_gen.cli: Typer-based CLI entry point for context-gen-cli (Python Edition).
3
+ """
4
+
5
+ import json
6
+ import time
7
+ from datetime import datetime
8
+ from enum import Enum
9
+ from pathlib import Path
10
+ from typing import List, Optional
11
+ import typer
12
+ from rich.console import Console
13
+ from rich.panel import Panel
14
+ from rich.table import Table
15
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn, TimeElapsedColumn
16
+
17
+ from context_gen.scanner import scan_project
18
+ from context_gen.extractor import extract_metadata
19
+ from context_gen.graph import build_dependency_graph
20
+ from context_gen.generator import generate_agent_md, generate_agent_json, generate_agent_yaml
21
+ from context_gen.distill import distill_query
22
+
23
+ app = typer.Typer(
24
+ name="context-gen",
25
+ help="⚡ Generate graph-based project context & distill minimal AI prompts (ctx).",
26
+ add_completion=False,
27
+ no_args_is_help=False,
28
+ )
29
+ console = Console()
30
+
31
+
32
+ class OutputFormat(str, Enum):
33
+ ALL = "all"
34
+ MD = "md"
35
+ JSON = "json"
36
+ YAML = "yaml"
37
+
38
+
39
+ def print_python_banner() -> None:
40
+ banner = r"""
41
+ ___ _ _ __
42
+ / __| |_ \ \/ /
43
+ | (__| _| > <
44
+ \___|\__|/_/\_\
45
+ """
46
+ console.print(f"[bold magenta]{banner}[/bold magenta]")
47
+ console.print(
48
+ Panel.fit(
49
+ "[bold cyan]⚡ context-gen-cli (ctx)[/bold cyan] — [magenta]Senior Engineer Context & Knowledge Graph Engine[/magenta]",
50
+ border_style="cyan",
51
+ )
52
+ )
53
+ console.print("")
54
+
55
+
56
+ def execute_generation_with_progress(
57
+ target_dir: Path,
58
+ format_choice: OutputFormat,
59
+ output_override: Optional[Path] = None,
60
+ max_depth: int = 3,
61
+ ) -> dict:
62
+ with Progress(
63
+ SpinnerColumn("dots", style="cyan"),
64
+ TextColumn("[bold blue]{task.description}"),
65
+ BarColumn(bar_width=35, complete_style="magenta", finished_style="green"),
66
+ TaskProgressColumn(),
67
+ TimeElapsedColumn(),
68
+ console=console,
69
+ ) as progress:
70
+ t1 = progress.add_task("🔍 Scanning workspace files & security guards...", total=100)
71
+ scan_result = scan_project(str(target_dir), max_depth=max_depth)
72
+ progress.update(t1, completed=100)
73
+
74
+ t2 = progress.add_task("📦 Extracting metadata & tech stack signals...", total=100)
75
+ files = scan_result["files"]
76
+ tree = scan_result["tree"]
77
+ metadata = extract_metadata(str(target_dir), files)
78
+ progress.update(t2, completed=100)
79
+
80
+ t3 = progress.add_task("🕸️ Building AST module dependency graph...", total=100)
81
+ graph = build_dependency_graph(files, str(target_dir))
82
+ progress.update(t3, completed=100)
83
+
84
+ t4 = progress.add_task(f"✍️ Generating context artifacts ({format_choice.value})...", total=100)
85
+
86
+ output_dir_name = "context"
87
+ config_file = target_dir / "context" / ".context-gen.json"
88
+ if not config_file.is_file():
89
+ config_file = target_dir / ".context-gen.json"
90
+
91
+ if config_file.is_file():
92
+ try:
93
+ cfg = json.loads(config_file.read_text(encoding="utf-8"))
94
+ output_dir_name = cfg.get("outputDir", "context")
95
+ except Exception:
96
+ pass
97
+
98
+ dest_dir = target_dir / output_dir_name
99
+ dest_dir.mkdir(parents=True, exist_ok=True)
100
+ generated_files: List[Path] = []
101
+
102
+ if output_override:
103
+ out_file = output_override.resolve()
104
+ out_file.parent.mkdir(parents=True, exist_ok=True)
105
+ if format_choice == OutputFormat.JSON:
106
+ out_file.write_text(json.dumps(generate_agent_json(metadata, graph, tree, str(target_dir)), indent=2), encoding="utf-8")
107
+ elif format_choice == OutputFormat.YAML:
108
+ out_file.write_text(generate_agent_yaml(metadata, graph, tree, str(target_dir)), encoding="utf-8")
109
+ else:
110
+ out_file.write_text(generate_agent_md(metadata, graph, tree), encoding="utf-8")
111
+ generated_files.append(out_file)
112
+ else:
113
+ formats_to_build = ["md", "json", "yaml"] if format_choice == OutputFormat.ALL else [format_choice.value]
114
+ if "md" in formats_to_build:
115
+ f = dest_dir / "agent.md"
116
+ f.write_text(generate_agent_md(metadata, graph, tree), encoding="utf-8")
117
+ generated_files.append(f)
118
+ if "json" in formats_to_build:
119
+ f = dest_dir / "agent.json"
120
+ f.write_text(json.dumps(generate_agent_json(metadata, graph, tree, str(target_dir)), indent=2), encoding="utf-8")
121
+ generated_files.append(f)
122
+ if "yaml" in formats_to_build:
123
+ f = dest_dir / "agent.yaml"
124
+ f.write_text(generate_agent_yaml(metadata, graph, tree, str(target_dir)), encoding="utf-8")
125
+ generated_files.append(f)
126
+
127
+ progress.update(t4, completed=100)
128
+
129
+ console.print("")
130
+ return {
131
+ "files": files,
132
+ "graph": graph,
133
+ "metadata": metadata,
134
+ "generated_files": generated_files,
135
+ "output_dir": dest_dir,
136
+ }
137
+
138
+
139
+ def run_watch_loop(target_dir: Path, format_choice: OutputFormat, max_depth: int = 3) -> None:
140
+ console.print(
141
+ Panel(
142
+ f"[bold cyan]👀 Watch Mode Active[/bold cyan]\n"
143
+ f"[dim]Monitoring:[/dim] [green]{target_dir}[/green]\n"
144
+ f"[dim]Auto-updating context on save. Press [bold]Ctrl+C[/bold] to stop.[/dim]",
145
+ border_style="cyan",
146
+ )
147
+ )
148
+
149
+ def get_snapshot():
150
+ snap = {}
151
+ for p in target_dir.rglob("*"):
152
+ if p.is_file():
153
+ rel = p.relative_to(target_dir).as_posix()
154
+ if not any(t in rel for t in ["context/", "node_modules/", ".git/", "__pycache__/", ".venv/", "agent."]):
155
+ try:
156
+ snap[rel] = p.stat().st_mtime
157
+ except Exception:
158
+ pass
159
+ return snap
160
+
161
+ last_snapshot = get_snapshot()
162
+ try:
163
+ while True:
164
+ time.sleep(1.0)
165
+ current = get_snapshot()
166
+ if current != last_snapshot:
167
+ last_snapshot = current
168
+ ts = datetime.now().strftime("%H:%M:%S")
169
+ console.print(f"[dim][{ts}][/dim] [bold green]🔄 Change detected. Syncing context...[/bold green]")
170
+ execute_generation_with_progress(target_dir, format_choice, max_depth=max_depth)
171
+ except KeyboardInterrupt:
172
+ console.print("\n[bold yellow]👋 Stopping watch mode...[/bold yellow]")
173
+
174
+
175
+ @app.callback(invoke_without_command=True)
176
+ def main(
177
+ ctx: typer.Context,
178
+ path: Path = typer.Argument(default=Path("."), help="Target project directory."),
179
+ project: Optional[Path] = typer.Option(None, "--project", "-p", help="Target project directory."),
180
+ default_mode: bool = typer.Option(False, "--default", "-d", help="⚡ Generate all formats + live watch mode."),
181
+ format: OutputFormat = typer.Option(OutputFormat.ALL, "--format", "-f", help="Output format: all, md, json, yaml."),
182
+ output: Optional[Path] = typer.Option(None, "--output", "-o", help="Custom output path."),
183
+ watch: bool = typer.Option(False, "--watch", "-w", help="Watch directory for changes."),
184
+ max_depth: int = typer.Option(3, "--max-depth", min=1, max=10, help="Max scan depth."),
185
+ ) -> None:
186
+ if ctx.invoked_subcommand is not None:
187
+ return
188
+
189
+ target_dir = (project or path).resolve()
190
+ print_python_banner()
191
+ res = execute_generation_with_progress(target_dir, format, output_override=output, max_depth=max_depth)
192
+
193
+ table = Table(show_header=False, box=None)
194
+ table.add_row("[bold]📂 Scanned Files:[/bold]", f"[cyan]{len(res['files'])}[/cyan]")
195
+ table.add_row("[bold]🕸️ Graph Edges:[/bold]", f"[magenta]{len(res['graph']['edges'])}[/magenta]")
196
+ table.add_row("[bold]⚡ Tech Stack:[/bold]", f"[green]{', '.join(res['metadata']['techStack'])}[/green]")
197
+ table.add_row("[bold]📁 Destination:[/bold]", f"[yellow]{res['output_dir']}[/yellow]")
198
+ table.add_row("[bold]�� Artifacts:[/bold]", f"[bold cyan]{', '.join(f.name for f in res['generated_files'])}[/bold cyan]")
199
+
200
+ console.print(Panel(table, title="[bold green]✅ Context Generated Successfully[/bold green]", border_style="green"))
201
+ console.print(
202
+ Panel(
203
+ "[bold cyan]ctx distill \"add feature\"[/bold cyan] → 🧠 Get minimal Senior Engineer context plan\n"
204
+ "[bold cyan]ctx -d[/bold cyan] → ⚡ All-in-one generate + live watcher\n"
205
+ "[bold cyan]ctx update -f json[/bold cyan] → 🔄 Quick format refresh",
206
+ title="[bold]💡 Quick Commands[/bold]",
207
+ border_style="blue",
208
+ )
209
+ )
210
+
211
+ if default_mode or watch:
212
+ run_watch_loop(target_dir, format, max_depth=max_depth)
213
+
214
+
215
+ @app.command()
216
+ def distill(
217
+ prompt: str = typer.Argument(..., help="Task or feature request to distill context for."),
218
+ budget: int = typer.Option(250, "--budget", "-b", help="Max token budget."),
219
+ project: Path = typer.Option(Path("."), "--project", "-p", help="Target project directory."),
220
+ ) -> None:
221
+ """🧠 Distill minimal high-signal context using Entropy + Knowledge Graph."""
222
+ res = distill_query(str(project.resolve()), prompt, budget=budget)
223
+ if res["status"] == "needs_clarification":
224
+ console.print(Panel(res["output"], title="[bold yellow]⚠️ Clarification Needed[/bold yellow]", border_style="yellow"))
225
+ else:
226
+ console.print(Panel(res["output"], title="[bold cyan]🧠 Senior Engineer Context Plan[/bold cyan]", border_style="cyan"))
227
+
228
+
229
+ @app.command()
230
+ def update(
231
+ path: Path = typer.Argument(default=Path("."), help="Target project directory."),
232
+ format: OutputFormat = typer.Option(OutputFormat.ALL, "--format", "-f", help="Output format."),
233
+ output: Optional[Path] = typer.Option(None, "--output", "-o", help="Custom output path."),
234
+ ) -> None:
235
+ """🔄 Regenerate and update project context files."""
236
+ target_dir = path.resolve()
237
+ res = execute_generation_with_progress(target_dir, format, output_override=output)
238
+ console.print(f"[bold green]✓ Context updated in {res['output_dir']}![/bold green]")
239
+
240
+
241
+ if __name__ == "__main__":
242
+ app()