claude-dev-cli 0.7.0__tar.gz → 0.8.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.

Potentially problematic release.


This version of claude-dev-cli might be problematic. Click here for more details.

Files changed (40) hide show
  1. {claude_dev_cli-0.7.0/src/claude_dev_cli.egg-info → claude_dev_cli-0.8.0}/PKG-INFO +37 -5
  2. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/README.md +36 -4
  3. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/pyproject.toml +1 -1
  4. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/__init__.py +1 -1
  5. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/cli.py +90 -14
  6. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/config.py +6 -0
  7. claude_dev_cli-0.8.0/src/claude_dev_cli/context.py +494 -0
  8. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0/src/claude_dev_cli.egg-info}/PKG-INFO +37 -5
  9. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli.egg-info/SOURCES.txt +1 -0
  10. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/LICENSE +0 -0
  11. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/MANIFEST.in +0 -0
  12. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/setup.cfg +0 -0
  13. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/commands.py +0 -0
  14. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/core.py +0 -0
  15. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/history.py +0 -0
  16. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/plugins/__init__.py +0 -0
  17. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/plugins/base.py +0 -0
  18. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/plugins/diff_editor/__init__.py +0 -0
  19. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/plugins/diff_editor/plugin.py +0 -0
  20. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/plugins/diff_editor/viewer.py +0 -0
  21. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/secure_storage.py +0 -0
  22. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/template_manager.py +0 -0
  23. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/templates.py +0 -0
  24. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/toon_utils.py +0 -0
  25. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/usage.py +0 -0
  26. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/warp_integration.py +0 -0
  27. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli/workflows.py +0 -0
  28. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli.egg-info/dependency_links.txt +0 -0
  29. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli.egg-info/entry_points.txt +0 -0
  30. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli.egg-info/requires.txt +0 -0
  31. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/src/claude_dev_cli.egg-info/top_level.txt +0 -0
  32. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_cli.py +0 -0
  33. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_commands.py +0 -0
  34. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_config.py +0 -0
  35. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_core.py +0 -0
  36. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_diff_editor.py +0 -0
  37. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_secure_storage.py +0 -0
  38. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_template_manager.py +0 -0
  39. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_toon_utils.py +0 -0
  40. {claude_dev_cli-0.7.0 → claude_dev_cli-0.8.0}/tests/test_usage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-dev-cli
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: A powerful CLI tool for developers using Claude AI with multi-API routing, test generation, code review, and usage tracking
5
5
  Author-email: Julio <thinmanj@users.noreply.github.com>
6
6
  License: MIT
@@ -79,6 +79,13 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
79
79
  - **Variable Substitution**: Use {{variable}} placeholders for dynamic content
80
80
  - **Categories**: Organize templates by category (review, testing, debugging, etc.)
81
81
 
82
+ ### 🧠 Context Intelligence (NEW in v0.8.0)
83
+ - **Auto-Context**: `--auto-context` flag for intelligent context gathering
84
+ - **Git Integration**: Automatically include branch, commits, modified files
85
+ - **Dependency Analysis**: Parse imports and include related files
86
+ - **Error Parsing**: Structured Python traceback parsing
87
+ - **Project Memory**: Remember preferences per project
88
+
82
89
  ### 🎒 TOON Format Support (Optional)
83
90
  - **Token Reduction**: 30-60% fewer tokens than JSON
84
91
  - **Cost Savings**: Reduce API costs significantly
@@ -152,11 +159,14 @@ cdc generate tests mymodule.py --interactive
152
159
  # Code review
153
160
  cdc review mymodule.py
154
161
 
162
+ # Code review with auto-context (includes git, dependencies, tests)
163
+ cdc review mymodule.py --auto-context
164
+
155
165
  # Code review with interactive follow-up questions
156
166
  cdc review mymodule.py --interactive
157
167
 
158
- # Debug errors
159
- python script.py 2>&1 | cdc debug
168
+ # Debug errors with intelligent error parsing
169
+ python script.py 2>&1 | cdc debug --auto-context
160
170
 
161
171
  # Generate documentation
162
172
  cdc generate docs mymodule.py
@@ -164,8 +174,8 @@ cdc generate docs mymodule.py
164
174
  # Generate docs with interactive refinement
165
175
  cdc generate docs mymodule.py --interactive
166
176
 
167
- # Refactor suggestions
168
- cdc refactor legacy_code.py
177
+ # Refactor with context (includes related files)
178
+ cdc refactor legacy_code.py --auto-context
169
179
 
170
180
  # Refactor with interactive refinement
171
181
  cdc refactor legacy_code.py --interactive
@@ -175,6 +185,28 @@ git add .
175
185
  cdc git commit
176
186
  ```
177
187
 
188
+ ### 4. Context-Aware Operations (NEW in v0.8.0)
189
+
190
+ ```bash
191
+ # Auto-context includes: git info, dependencies, related files
192
+
193
+ # Review with full project context
194
+ cdc review mymodule.py --auto-context
195
+ # ✓ Context gathered (git, dependencies, tests)
196
+
197
+ # Debug with parsed error details
198
+ python broken.py 2>&1 | cdc debug -f broken.py --auto-context
199
+ # ✓ Context gathered (error details, git context)
200
+
201
+ # Ask questions with file context
202
+ cdc ask -f mycode.py --auto-context "how can I improve this?"
203
+ # ✓ Context gathered
204
+
205
+ # Refactor with related files
206
+ cdc refactor app.py --auto-context
207
+ # Automatically includes imported modules and dependencies
208
+ ```
209
+
178
210
  ### 5. Custom Templates
179
211
 
180
212
  ```bash
@@ -35,6 +35,13 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
35
35
  - **Variable Substitution**: Use {{variable}} placeholders for dynamic content
36
36
  - **Categories**: Organize templates by category (review, testing, debugging, etc.)
37
37
 
38
+ ### 🧠 Context Intelligence (NEW in v0.8.0)
39
+ - **Auto-Context**: `--auto-context` flag for intelligent context gathering
40
+ - **Git Integration**: Automatically include branch, commits, modified files
41
+ - **Dependency Analysis**: Parse imports and include related files
42
+ - **Error Parsing**: Structured Python traceback parsing
43
+ - **Project Memory**: Remember preferences per project
44
+
38
45
  ### 🎒 TOON Format Support (Optional)
39
46
  - **Token Reduction**: 30-60% fewer tokens than JSON
40
47
  - **Cost Savings**: Reduce API costs significantly
@@ -108,11 +115,14 @@ cdc generate tests mymodule.py --interactive
108
115
  # Code review
109
116
  cdc review mymodule.py
110
117
 
118
+ # Code review with auto-context (includes git, dependencies, tests)
119
+ cdc review mymodule.py --auto-context
120
+
111
121
  # Code review with interactive follow-up questions
112
122
  cdc review mymodule.py --interactive
113
123
 
114
- # Debug errors
115
- python script.py 2>&1 | cdc debug
124
+ # Debug errors with intelligent error parsing
125
+ python script.py 2>&1 | cdc debug --auto-context
116
126
 
117
127
  # Generate documentation
118
128
  cdc generate docs mymodule.py
@@ -120,8 +130,8 @@ cdc generate docs mymodule.py
120
130
  # Generate docs with interactive refinement
121
131
  cdc generate docs mymodule.py --interactive
122
132
 
123
- # Refactor suggestions
124
- cdc refactor legacy_code.py
133
+ # Refactor with context (includes related files)
134
+ cdc refactor legacy_code.py --auto-context
125
135
 
126
136
  # Refactor with interactive refinement
127
137
  cdc refactor legacy_code.py --interactive
@@ -131,6 +141,28 @@ git add .
131
141
  cdc git commit
132
142
  ```
133
143
 
144
+ ### 4. Context-Aware Operations (NEW in v0.8.0)
145
+
146
+ ```bash
147
+ # Auto-context includes: git info, dependencies, related files
148
+
149
+ # Review with full project context
150
+ cdc review mymodule.py --auto-context
151
+ # ✓ Context gathered (git, dependencies, tests)
152
+
153
+ # Debug with parsed error details
154
+ python broken.py 2>&1 | cdc debug -f broken.py --auto-context
155
+ # ✓ Context gathered (error details, git context)
156
+
157
+ # Ask questions with file context
158
+ cdc ask -f mycode.py --auto-context "how can I improve this?"
159
+ # ✓ Context gathered
160
+
161
+ # Refactor with related files
162
+ cdc refactor app.py --auto-context
163
+ # Automatically includes imported modules and dependencies
164
+ ```
165
+
134
166
  ### 5. Custom Templates
135
167
 
136
168
  ```bash
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "claude-dev-cli"
7
- version = "0.7.0"
7
+ version = "0.8.0"
8
8
  description = "A powerful CLI tool for developers using Claude AI with multi-API routing, test generation, code review, and usage tracking"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -9,7 +9,7 @@ Features:
9
9
  - Interactive and single-shot modes
10
10
  """
11
11
 
12
- __version__ = "0.7.0"
12
+ __version__ = "0.8.0"
13
13
  __author__ = "Julio"
14
14
  __license__ = "MIT"
15
15
 
@@ -57,6 +57,7 @@ except Exception:
57
57
  @click.option('-a', '--api', help='API config to use')
58
58
  @click.option('-m', '--model', help='Claude model to use')
59
59
  @click.option('--stream/--no-stream', default=True, help='Stream response')
60
+ @click.option('--auto-context', is_flag=True, help='Automatically include git, dependencies, and related files')
60
61
  @click.pass_context
61
62
  def ask(
62
63
  ctx: click.Context,
@@ -65,7 +66,8 @@ def ask(
65
66
  system: Optional[str],
66
67
  api: Optional[str],
67
68
  model: Optional[str],
68
- stream: bool
69
+ stream: bool,
70
+ auto_context: bool
69
71
  ) -> None:
70
72
  """Ask Claude a question (single-shot mode)."""
71
73
  console = ctx.obj['console']
@@ -73,7 +75,18 @@ def ask(
73
75
  # Build prompt
74
76
  prompt_parts = []
75
77
 
76
- if file:
78
+ # Gather context if requested
79
+ if auto_context and file:
80
+ from claude_dev_cli.context import ContextGatherer
81
+
82
+ with console.status("[bold blue]Gathering context..."):
83
+ gatherer = ContextGatherer()
84
+ context = gatherer.gather_for_file(Path(file))
85
+ context_info = context.format_for_prompt()
86
+
87
+ console.print("[dim]✓ Context gathered[/dim]")
88
+ prompt_parts.append(context_info)
89
+ elif file:
77
90
  with open(file, 'r') as f:
78
91
  file_content = f.read()
79
92
  prompt_parts.append(f"File: {file}\n\n{file_content}\n\n")
@@ -584,19 +597,42 @@ def gen_docs(
584
597
  @click.argument('file_path', type=click.Path(exists=True))
585
598
  @click.option('-a', '--api', help='API config to use')
586
599
  @click.option('-i', '--interactive', is_flag=True, help='Interactive follow-up questions')
600
+ @click.option('--auto-context', is_flag=True, help='Automatically include git, dependencies, and related files')
587
601
  @click.pass_context
588
602
  def review(
589
603
  ctx: click.Context,
590
604
  file_path: str,
591
605
  api: Optional[str],
592
- interactive: bool
606
+ interactive: bool,
607
+ auto_context: bool
593
608
  ) -> None:
594
609
  """Review code for bugs and improvements."""
595
610
  console = ctx.obj['console']
596
611
 
597
612
  try:
613
+ # Gather context if requested
614
+ context_info = ""
615
+ if auto_context:
616
+ from claude_dev_cli.context import ContextGatherer
617
+
618
+ with console.status("[bold blue]Gathering context..."):
619
+ gatherer = ContextGatherer()
620
+ context = gatherer.gather_for_review(Path(file_path))
621
+ context_info = context.format_for_prompt()
622
+
623
+ console.print("[dim]✓ Context gathered (git, dependencies, tests)[/dim]")
624
+
598
625
  with console.status("[bold blue]Reviewing code..."):
599
- result = code_review(file_path, api_config_name=api)
626
+ # If we have context, prepend it to the file analysis
627
+ if context_info:
628
+ # Read file separately for context-aware review
629
+ result = code_review(file_path, api_config_name=api)
630
+ # The context module already includes the file, so we use it differently
631
+ client = ClaudeClient(api_config_name=api)
632
+ enhanced_prompt = f"{context_info}\n\nPlease review this code for bugs and improvements."
633
+ result = client.call(enhanced_prompt)
634
+ else:
635
+ result = code_review(file_path, api_config_name=api)
600
636
 
601
637
  md = Markdown(result)
602
638
  console.print(md)
@@ -633,12 +669,14 @@ def review(
633
669
  @click.option('-f', '--file', type=click.Path(exists=True), help='File to debug')
634
670
  @click.option('-e', '--error', help='Error message to analyze')
635
671
  @click.option('-a', '--api', help='API config to use')
672
+ @click.option('--auto-context', is_flag=True, help='Automatically include git context and parse error details')
636
673
  @click.pass_context
637
674
  def debug(
638
675
  ctx: click.Context,
639
676
  file: Optional[str],
640
677
  error: Optional[str],
641
- api: Optional[str]
678
+ api: Optional[str],
679
+ auto_context: bool
642
680
  ) -> None:
643
681
  """Debug code and analyze errors."""
644
682
  console = ctx.obj['console']
@@ -648,13 +686,33 @@ def debug(
648
686
  if not sys.stdin.isatty():
649
687
  stdin_content = sys.stdin.read().strip()
650
688
 
689
+ error_text = error or stdin_content
690
+
651
691
  try:
652
- with console.status("[bold blue]Analyzing error..."):
653
- result = debug_code(
654
- file_path=file,
655
- error_message=error or stdin_content,
656
- api_config_name=api
657
- )
692
+ # Gather context if requested
693
+ if auto_context and error_text:
694
+ from claude_dev_cli.context import ContextGatherer
695
+
696
+ with console.status("[bold blue]Gathering context..."):
697
+ gatherer = ContextGatherer()
698
+ file_path = Path(file) if file else None
699
+ context = gatherer.gather_for_error(error_text, file_path=file_path)
700
+ context_info = context.format_for_prompt()
701
+
702
+ console.print("[dim]✓ Context gathered (error details, git context)[/dim]")
703
+
704
+ # Use context-aware analysis
705
+ client = ClaudeClient(api_config_name=api)
706
+ enhanced_prompt = f"{context_info}\n\nPlease analyze this error and suggest fixes."
707
+ result = client.call(enhanced_prompt)
708
+ else:
709
+ # Original behavior
710
+ with console.status("[bold blue]Analyzing error..."):
711
+ result = debug_code(
712
+ file_path=file,
713
+ error_message=error_text,
714
+ api_config_name=api
715
+ )
658
716
 
659
717
  md = Markdown(result)
660
718
  console.print(md)
@@ -669,20 +727,38 @@ def debug(
669
727
  @click.option('-o', '--output', type=click.Path(), help='Output file path')
670
728
  @click.option('-a', '--api', help='API config to use')
671
729
  @click.option('-i', '--interactive', is_flag=True, help='Interactive refinement mode')
730
+ @click.option('--auto-context', is_flag=True, help='Automatically include git, dependencies, and related files')
672
731
  @click.pass_context
673
732
  def refactor(
674
733
  ctx: click.Context,
675
734
  file_path: str,
676
735
  output: Optional[str],
677
736
  api: Optional[str],
678
- interactive: bool
737
+ interactive: bool,
738
+ auto_context: bool
679
739
  ) -> None:
680
740
  """Suggest refactoring improvements."""
681
741
  console = ctx.obj['console']
682
742
 
683
743
  try:
684
- with console.status("[bold blue]Analyzing code..."):
685
- result = refactor_code(file_path, api_config_name=api)
744
+ # Gather context if requested
745
+ if auto_context:
746
+ from claude_dev_cli.context import ContextGatherer
747
+
748
+ with console.status("[bold blue]Gathering context..."):
749
+ gatherer = ContextGatherer()
750
+ context = gatherer.gather_for_file(Path(file_path))
751
+ context_info = context.format_for_prompt()
752
+
753
+ console.print("[dim]✓ Context gathered[/dim]")
754
+
755
+ # Use context-aware refactoring
756
+ client = ClaudeClient(api_config_name=api)
757
+ enhanced_prompt = f"{context_info}\n\nPlease suggest refactoring improvements for the main file."
758
+ result = client.call(enhanced_prompt)
759
+ else:
760
+ with console.status("[bold blue]Analyzing code..."):
761
+ result = refactor_code(file_path, api_config_name=api)
686
762
 
687
763
  if interactive:
688
764
  console.print("\n[bold]Initial Refactoring:[/bold]\n")
@@ -25,6 +25,12 @@ class ProjectProfile(BaseModel):
25
25
  api_config: str # Name of the API config to use
26
26
  system_prompt: Optional[str] = None
27
27
  allowed_commands: List[str] = Field(default_factory=lambda: ["all"])
28
+
29
+ # Project memory - preferences and patterns
30
+ auto_context: bool = False # Default value for --auto-context flag
31
+ coding_style: Optional[str] = None # Preferred coding style
32
+ test_framework: Optional[str] = None # Preferred test framework
33
+ preferences: Dict[str, str] = Field(default_factory=dict) # Custom preferences
28
34
 
29
35
 
30
36
  class Config:
@@ -0,0 +1,494 @@
1
+ """Intelligent context gathering for AI operations."""
2
+
3
+ import ast
4
+ import json
5
+ import re
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import Any, Dict, List, Optional, Set
9
+ from dataclasses import dataclass, field
10
+
11
+
12
+ @dataclass
13
+ class ContextItem:
14
+ """A single piece of context information."""
15
+ type: str # 'file', 'git', 'dependency', 'error'
16
+ content: str
17
+ metadata: Dict[str, Any] = field(default_factory=dict)
18
+
19
+ def format_for_prompt(self) -> str:
20
+ """Format this context item for inclusion in a prompt."""
21
+ if self.type == 'file':
22
+ path = self.metadata.get('path', 'unknown')
23
+ return f"# File: {path}\n\n{self.content}\n"
24
+ elif self.type == 'git':
25
+ return f"# Git Context\n\n{self.content}\n"
26
+ elif self.type == 'dependency':
27
+ return f"# Dependencies\n\n{self.content}\n"
28
+ elif self.type == 'error':
29
+ return f"# Error Context\n\n{self.content}\n"
30
+ else:
31
+ return self.content
32
+
33
+
34
+ @dataclass
35
+ class Context:
36
+ """Collection of context items."""
37
+ items: List[ContextItem] = field(default_factory=list)
38
+
39
+ def add(self, item: ContextItem) -> None:
40
+ """Add a context item."""
41
+ self.items.append(item)
42
+
43
+ def format_for_prompt(self) -> str:
44
+ """Format all context items for inclusion in a prompt."""
45
+ if not self.items:
46
+ return ""
47
+
48
+ parts = ["# Context Information\n"]
49
+ for item in self.items:
50
+ parts.append(item.format_for_prompt())
51
+
52
+ return "\n".join(parts)
53
+
54
+ def get_by_type(self, context_type: str) -> List[ContextItem]:
55
+ """Get all context items of a specific type."""
56
+ return [item for item in self.items if item.type == context_type]
57
+
58
+
59
+ class GitContext:
60
+ """Gather Git-related context."""
61
+
62
+ def __init__(self, cwd: Optional[Path] = None):
63
+ self.cwd = cwd or Path.cwd()
64
+
65
+ def is_git_repo(self) -> bool:
66
+ """Check if current directory is a git repository."""
67
+ try:
68
+ result = subprocess.run(
69
+ ['git', 'rev-parse', '--git-dir'],
70
+ cwd=self.cwd,
71
+ capture_output=True,
72
+ text=True
73
+ )
74
+ return result.returncode == 0
75
+ except Exception:
76
+ return False
77
+
78
+ def get_current_branch(self) -> Optional[str]:
79
+ """Get the current git branch."""
80
+ try:
81
+ result = subprocess.run(
82
+ ['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
83
+ cwd=self.cwd,
84
+ capture_output=True,
85
+ text=True,
86
+ check=True
87
+ )
88
+ return result.stdout.strip()
89
+ except Exception:
90
+ return None
91
+
92
+ def get_recent_commits(self, count: int = 5) -> List[Dict[str, str]]:
93
+ """Get recent commit messages."""
94
+ try:
95
+ result = subprocess.run(
96
+ ['git', '--no-pager', 'log', f'-{count}', '--pretty=format:%h|%s|%an|%ar'],
97
+ cwd=self.cwd,
98
+ capture_output=True,
99
+ text=True,
100
+ check=True
101
+ )
102
+
103
+ commits = []
104
+ for line in result.stdout.strip().split('\n'):
105
+ if line:
106
+ parts = line.split('|', 3)
107
+ if len(parts) == 4:
108
+ commits.append({
109
+ 'hash': parts[0],
110
+ 'message': parts[1],
111
+ 'author': parts[2],
112
+ 'date': parts[3]
113
+ })
114
+ return commits
115
+ except Exception:
116
+ return []
117
+
118
+ def get_staged_diff(self) -> Optional[str]:
119
+ """Get diff of staged changes."""
120
+ try:
121
+ result = subprocess.run(
122
+ ['git', '--no-pager', 'diff', '--cached'],
123
+ cwd=self.cwd,
124
+ capture_output=True,
125
+ text=True,
126
+ check=True
127
+ )
128
+ return result.stdout if result.stdout else None
129
+ except Exception:
130
+ return None
131
+
132
+ def get_unstaged_diff(self) -> Optional[str]:
133
+ """Get diff of unstaged changes."""
134
+ try:
135
+ result = subprocess.run(
136
+ ['git', '--no-pager', 'diff'],
137
+ cwd=self.cwd,
138
+ capture_output=True,
139
+ text=True,
140
+ check=True
141
+ )
142
+ return result.stdout if result.stdout else None
143
+ except Exception:
144
+ return None
145
+
146
+ def get_modified_files(self) -> List[str]:
147
+ """Get list of modified files."""
148
+ try:
149
+ result = subprocess.run(
150
+ ['git', 'status', '--porcelain'],
151
+ cwd=self.cwd,
152
+ capture_output=True,
153
+ text=True,
154
+ check=True
155
+ )
156
+
157
+ files = []
158
+ for line in result.stdout.strip().split('\n'):
159
+ if line:
160
+ # Format: "XY filename"
161
+ parts = line.strip().split(maxsplit=1)
162
+ if len(parts) == 2:
163
+ files.append(parts[1])
164
+ return files
165
+ except Exception:
166
+ return []
167
+
168
+ def gather(self, include_diff: bool = False) -> ContextItem:
169
+ """Gather all git context."""
170
+ parts = []
171
+
172
+ branch = self.get_current_branch()
173
+ if branch:
174
+ parts.append(f"Branch: {branch}")
175
+
176
+ commits = self.get_recent_commits(5)
177
+ if commits:
178
+ parts.append("\nRecent commits:")
179
+ for commit in commits:
180
+ parts.append(f" {commit['hash']} - {commit['message']} ({commit['date']})")
181
+
182
+ modified = self.get_modified_files()
183
+ if modified:
184
+ parts.append(f"\nModified files: {', '.join(modified[:10])}")
185
+
186
+ if include_diff:
187
+ staged = self.get_staged_diff()
188
+ if staged:
189
+ parts.append(f"\nStaged changes:\n{staged[:1000]}...") # Limit size
190
+
191
+ content = "\n".join(parts) if parts else "No git context available"
192
+
193
+ return ContextItem(
194
+ type='git',
195
+ content=content,
196
+ metadata={'branch': branch, 'modified_count': len(modified)}
197
+ )
198
+
199
+
200
+ class DependencyAnalyzer:
201
+ """Analyze project dependencies and imports."""
202
+
203
+ def __init__(self, project_root: Path):
204
+ self.project_root = project_root
205
+
206
+ def find_python_imports(self, file_path: Path) -> Set[str]:
207
+ """Extract imports from a Python file."""
208
+ imports = set()
209
+
210
+ try:
211
+ with open(file_path, 'r') as f:
212
+ tree = ast.parse(f.read())
213
+
214
+ for node in ast.walk(tree):
215
+ if isinstance(node, ast.Import):
216
+ for name in node.names:
217
+ imports.add(name.name.split('.')[0])
218
+ elif isinstance(node, ast.ImportFrom):
219
+ if node.module:
220
+ imports.add(node.module.split('.')[0])
221
+ except Exception:
222
+ pass
223
+
224
+ return imports
225
+
226
+ def find_related_files(self, file_path: Path, max_depth: int = 2) -> List[Path]:
227
+ """Find files related to the given file through imports."""
228
+ if not file_path.suffix == '.py':
229
+ return []
230
+
231
+ related = []
232
+ imports = self.find_python_imports(file_path)
233
+
234
+ # Look for local modules
235
+ for imp in imports:
236
+ # Try as module file
237
+ module_file = self.project_root / f"{imp}.py"
238
+ if module_file.exists() and module_file != file_path:
239
+ related.append(module_file)
240
+
241
+ # Try as package
242
+ package_init = self.project_root / imp / "__init__.py"
243
+ if package_init.exists():
244
+ related.append(package_init)
245
+
246
+ return related[:5] # Limit to avoid too many files
247
+
248
+ def get_dependency_files(self) -> List[Path]:
249
+ """Find dependency configuration files."""
250
+ files = []
251
+
252
+ # Python
253
+ for name in ['requirements.txt', 'setup.py', 'pyproject.toml', 'Pipfile']:
254
+ file = self.project_root / name
255
+ if file.exists():
256
+ files.append(file)
257
+
258
+ # Node.js
259
+ for name in ['package.json', 'package-lock.json']:
260
+ file = self.project_root / name
261
+ if file.exists():
262
+ files.append(file)
263
+
264
+ # Other
265
+ for name in ['Gemfile', 'go.mod', 'Cargo.toml']:
266
+ file = self.project_root / name
267
+ if file.exists():
268
+ files.append(file)
269
+
270
+ return files
271
+
272
+ def gather(self, target_file: Optional[Path] = None) -> ContextItem:
273
+ """Gather dependency context."""
274
+ parts = []
275
+
276
+ # Include dependency files
277
+ dep_files = self.get_dependency_files()
278
+ if dep_files:
279
+ parts.append("Dependency files:")
280
+ for file in dep_files[:3]: # Limit
281
+ parts.append(f" - {file.name}")
282
+ try:
283
+ content = file.read_text()
284
+ # Include only relevant parts
285
+ if file.suffix == '.json':
286
+ data = json.loads(content)
287
+ if 'dependencies' in data:
288
+ parts.append(f" Dependencies: {', '.join(list(data['dependencies'].keys())[:10])}")
289
+ elif file.suffix == '.txt':
290
+ lines = content.split('\n')[:20]
291
+ parts.append(f" Requirements: {', '.join([l.split('==')[0] for l in lines if l and not l.startswith('#')])}")
292
+ except Exception:
293
+ pass
294
+
295
+ # Related files if target specified
296
+ if target_file and target_file.exists():
297
+ related = self.find_related_files(target_file)
298
+ if related:
299
+ parts.append(f"\nRelated files for {target_file.name}:")
300
+ for file in related:
301
+ parts.append(f" - {file.relative_to(self.project_root)}")
302
+
303
+ content = "\n".join(parts) if parts else "No dependency context found"
304
+
305
+ return ContextItem(
306
+ type='dependency',
307
+ content=content,
308
+ metadata={'dependency_files': [str(f) for f in dep_files]}
309
+ )
310
+
311
+
312
+ class ErrorContext:
313
+ """Parse and format error context."""
314
+
315
+ @staticmethod
316
+ def parse_traceback(error_text: str) -> Dict[str, Any]:
317
+ """Parse Python traceback into structured data."""
318
+ lines = error_text.split('\n')
319
+
320
+ # Find traceback start
321
+ traceback_start = -1
322
+ for i, line in enumerate(lines):
323
+ if 'Traceback' in line:
324
+ traceback_start = i
325
+ break
326
+
327
+ if traceback_start == -1:
328
+ return {'raw': error_text}
329
+
330
+ # Extract frames
331
+ frames = []
332
+ current_frame = {}
333
+
334
+ for line in lines[traceback_start + 1:]:
335
+ if line.startswith(' File '):
336
+ if current_frame:
337
+ frames.append(current_frame)
338
+
339
+ # Parse: File "path", line X, in function
340
+ match = re.match(r'\s*File "([^"]+)", line (\d+), in (.+)', line)
341
+ if match:
342
+ current_frame = {
343
+ 'file': match.group(1),
344
+ 'line': int(match.group(2)),
345
+ 'function': match.group(3)
346
+ }
347
+ elif line.startswith(' ') and current_frame:
348
+ current_frame['code'] = line.strip()
349
+ elif line and not line.startswith(' '):
350
+ # Error message
351
+ if current_frame:
352
+ frames.append(current_frame)
353
+ current_frame = {}
354
+
355
+ error_type = line.split(':')[0] if ':' in line else line
356
+ error_message = line.split(':', 1)[1].strip() if ':' in line else ''
357
+
358
+ return {
359
+ 'frames': frames,
360
+ 'error_type': error_type,
361
+ 'error_message': error_message,
362
+ 'raw': error_text
363
+ }
364
+
365
+ return {'frames': frames, 'raw': error_text}
366
+
367
+ @staticmethod
368
+ def format_for_ai(error_text: str) -> str:
369
+ """Format error for AI consumption."""
370
+ parsed = ErrorContext.parse_traceback(error_text)
371
+
372
+ if 'error_type' not in parsed:
373
+ return error_text
374
+
375
+ parts = [
376
+ f"Error Type: {parsed['error_type']}",
377
+ f"Error Message: {parsed.get('error_message', 'N/A')}",
378
+ "\nStack Trace:"
379
+ ]
380
+
381
+ for i, frame in enumerate(parsed.get('frames', []), 1):
382
+ parts.append(f" {i}. {frame.get('file', 'unknown')}:{frame.get('line', '?')} in {frame.get('function', 'unknown')}")
383
+ if 'code' in frame:
384
+ parts.append(f" > {frame['code']}")
385
+
386
+ return "\n".join(parts)
387
+
388
+ def gather(self, error_text: str) -> ContextItem:
389
+ """Gather error context."""
390
+ formatted = self.format_for_ai(error_text)
391
+ parsed = self.parse_traceback(error_text)
392
+
393
+ return ContextItem(
394
+ type='error',
395
+ content=formatted,
396
+ metadata=parsed
397
+ )
398
+
399
+
400
+ class ContextGatherer:
401
+ """Main context gathering coordinator."""
402
+
403
+ def __init__(self, project_root: Optional[Path] = None):
404
+ self.project_root = project_root or Path.cwd()
405
+ self.git = GitContext(self.project_root)
406
+ self.dependencies = DependencyAnalyzer(self.project_root)
407
+ self.error_parser = ErrorContext()
408
+
409
+ def gather_for_file(
410
+ self,
411
+ file_path: Path,
412
+ include_git: bool = True,
413
+ include_dependencies: bool = True,
414
+ include_related: bool = True
415
+ ) -> Context:
416
+ """Gather context for a specific file operation."""
417
+ context = Context()
418
+
419
+ # Add the file itself
420
+ if file_path.exists():
421
+ context.add(ContextItem(
422
+ type='file',
423
+ content=file_path.read_text(),
424
+ metadata={'path': str(file_path)}
425
+ ))
426
+
427
+ # Add git context
428
+ if include_git and self.git.is_git_repo():
429
+ context.add(self.git.gather(include_diff=False))
430
+
431
+ # Add dependency context
432
+ if include_dependencies:
433
+ context.add(self.dependencies.gather(target_file=file_path if include_related else None))
434
+
435
+ return context
436
+
437
+ def gather_for_error(
438
+ self,
439
+ error_text: str,
440
+ file_path: Optional[Path] = None,
441
+ include_git: bool = True
442
+ ) -> Context:
443
+ """Gather context for error debugging."""
444
+ context = Context()
445
+
446
+ # Add error context
447
+ context.add(self.error_parser.gather(error_text))
448
+
449
+ # Add file if provided
450
+ if file_path and file_path.exists():
451
+ context.add(ContextItem(
452
+ type='file',
453
+ content=file_path.read_text(),
454
+ metadata={'path': str(file_path)}
455
+ ))
456
+
457
+ # Add git context
458
+ if include_git and self.git.is_git_repo():
459
+ context.add(self.git.gather(include_diff=False))
460
+
461
+ return context
462
+
463
+ def gather_for_review(
464
+ self,
465
+ file_path: Path,
466
+ include_git: bool = True,
467
+ include_tests: bool = True
468
+ ) -> Context:
469
+ """Gather context for code review."""
470
+ context = self.gather_for_file(
471
+ file_path,
472
+ include_git=include_git,
473
+ include_dependencies=True,
474
+ include_related=True
475
+ )
476
+
477
+ # Try to find test file
478
+ if include_tests:
479
+ test_patterns = [
480
+ self.project_root / "tests" / f"test_{file_path.name}",
481
+ self.project_root / f"test_{file_path.name}",
482
+ file_path.parent / f"test_{file_path.name}"
483
+ ]
484
+
485
+ for test_file in test_patterns:
486
+ if test_file.exists():
487
+ context.add(ContextItem(
488
+ type='file',
489
+ content=test_file.read_text(),
490
+ metadata={'path': str(test_file), 'is_test': True}
491
+ ))
492
+ break
493
+
494
+ return context
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-dev-cli
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: A powerful CLI tool for developers using Claude AI with multi-API routing, test generation, code review, and usage tracking
5
5
  Author-email: Julio <thinmanj@users.noreply.github.com>
6
6
  License: MIT
@@ -79,6 +79,13 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
79
79
  - **Variable Substitution**: Use {{variable}} placeholders for dynamic content
80
80
  - **Categories**: Organize templates by category (review, testing, debugging, etc.)
81
81
 
82
+ ### 🧠 Context Intelligence (NEW in v0.8.0)
83
+ - **Auto-Context**: `--auto-context` flag for intelligent context gathering
84
+ - **Git Integration**: Automatically include branch, commits, modified files
85
+ - **Dependency Analysis**: Parse imports and include related files
86
+ - **Error Parsing**: Structured Python traceback parsing
87
+ - **Project Memory**: Remember preferences per project
88
+
82
89
  ### 🎒 TOON Format Support (Optional)
83
90
  - **Token Reduction**: 30-60% fewer tokens than JSON
84
91
  - **Cost Savings**: Reduce API costs significantly
@@ -152,11 +159,14 @@ cdc generate tests mymodule.py --interactive
152
159
  # Code review
153
160
  cdc review mymodule.py
154
161
 
162
+ # Code review with auto-context (includes git, dependencies, tests)
163
+ cdc review mymodule.py --auto-context
164
+
155
165
  # Code review with interactive follow-up questions
156
166
  cdc review mymodule.py --interactive
157
167
 
158
- # Debug errors
159
- python script.py 2>&1 | cdc debug
168
+ # Debug errors with intelligent error parsing
169
+ python script.py 2>&1 | cdc debug --auto-context
160
170
 
161
171
  # Generate documentation
162
172
  cdc generate docs mymodule.py
@@ -164,8 +174,8 @@ cdc generate docs mymodule.py
164
174
  # Generate docs with interactive refinement
165
175
  cdc generate docs mymodule.py --interactive
166
176
 
167
- # Refactor suggestions
168
- cdc refactor legacy_code.py
177
+ # Refactor with context (includes related files)
178
+ cdc refactor legacy_code.py --auto-context
169
179
 
170
180
  # Refactor with interactive refinement
171
181
  cdc refactor legacy_code.py --interactive
@@ -175,6 +185,28 @@ git add .
175
185
  cdc git commit
176
186
  ```
177
187
 
188
+ ### 4. Context-Aware Operations (NEW in v0.8.0)
189
+
190
+ ```bash
191
+ # Auto-context includes: git info, dependencies, related files
192
+
193
+ # Review with full project context
194
+ cdc review mymodule.py --auto-context
195
+ # ✓ Context gathered (git, dependencies, tests)
196
+
197
+ # Debug with parsed error details
198
+ python broken.py 2>&1 | cdc debug -f broken.py --auto-context
199
+ # ✓ Context gathered (error details, git context)
200
+
201
+ # Ask questions with file context
202
+ cdc ask -f mycode.py --auto-context "how can I improve this?"
203
+ # ✓ Context gathered
204
+
205
+ # Refactor with related files
206
+ cdc refactor app.py --auto-context
207
+ # Automatically includes imported modules and dependencies
208
+ ```
209
+
178
210
  ### 5. Custom Templates
179
211
 
180
212
  ```bash
@@ -6,6 +6,7 @@ src/claude_dev_cli/__init__.py
6
6
  src/claude_dev_cli/cli.py
7
7
  src/claude_dev_cli/commands.py
8
8
  src/claude_dev_cli/config.py
9
+ src/claude_dev_cli/context.py
9
10
  src/claude_dev_cli/core.py
10
11
  src/claude_dev_cli/history.py
11
12
  src/claude_dev_cli/secure_storage.py
File without changes
File without changes