claude-dev-cli 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl

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.
@@ -9,7 +9,7 @@ Features:
9
9
  - Interactive and single-shot modes
10
10
  """
11
11
 
12
- __version__ = "0.11.0"
12
+ __version__ = "0.12.0"
13
13
  __author__ = "Julio"
14
14
  __license__ = "MIT"
15
15
 
claude_dev_cli/cli.py CHANGED
@@ -1060,6 +1060,315 @@ def gen_docs(
1060
1060
  sys.exit(1)
1061
1061
 
1062
1062
 
1063
+ @generate.command('code')
1064
+ @click.option('--description', help='Inline code specification')
1065
+ @click.option('-f', '--file', 'spec_file', type=click.Path(exists=True), help='Read specification from file')
1066
+ @click.option('--pdf', type=click.Path(exists=True), help='Read specification from PDF')
1067
+ @click.option('--url', help='Fetch specification from URL')
1068
+ @click.option('-o', '--output', required=True, type=click.Path(), help='Output file path (required)')
1069
+ @click.option('--language', help='Target language (auto-detected from output extension)')
1070
+ @click.option('-m', '--model', help='Model profile to use')
1071
+ @click.option('-a', '--api', help='API config to use')
1072
+ @click.option('-i', '--interactive', is_flag=True, help='Interactive refinement mode')
1073
+ @click.option('--auto-context', is_flag=True, help='Include project context')
1074
+ @click.pass_context
1075
+ def gen_code(
1076
+ ctx: click.Context,
1077
+ description: Optional[str],
1078
+ spec_file: Optional[str],
1079
+ pdf: Optional[str],
1080
+ url: Optional[str],
1081
+ output: str,
1082
+ language: Optional[str],
1083
+ model: Optional[str],
1084
+ api: Optional[str],
1085
+ interactive: bool,
1086
+ auto_context: bool
1087
+ ) -> None:
1088
+ """Generate code from a specification.
1089
+
1090
+ Reads specification from text, file, PDF, or URL and generates complete code.
1091
+
1092
+ Examples:
1093
+ cdc generate code --description "REST API client" -o client.py
1094
+ cdc generate code --file spec.md -o implementation.go
1095
+ cdc generate code --pdf requirements.pdf -o app.js
1096
+ cdc generate code --url https://example.com/spec -o service.py
1097
+ """
1098
+ console = ctx.obj['console']
1099
+ from claude_dev_cli.input_sources import get_input_content
1100
+ from pathlib import Path
1101
+
1102
+ try:
1103
+ # Get specification content
1104
+ spec_content, source_desc = get_input_content(
1105
+ description=description,
1106
+ file_path=spec_file,
1107
+ pdf_path=pdf,
1108
+ url=url,
1109
+ console=console
1110
+ )
1111
+
1112
+ # Detect language from output extension if not specified
1113
+ if not language:
1114
+ ext = Path(output).suffix.lstrip('.')
1115
+ language_map = {
1116
+ 'py': 'Python',
1117
+ 'js': 'JavaScript',
1118
+ 'ts': 'TypeScript',
1119
+ 'go': 'Go',
1120
+ 'rs': 'Rust',
1121
+ 'java': 'Java',
1122
+ 'cpp': 'C++',
1123
+ 'c': 'C',
1124
+ 'cs': 'C#',
1125
+ 'rb': 'Ruby',
1126
+ 'php': 'PHP',
1127
+ 'swift': 'Swift',
1128
+ 'kt': 'Kotlin',
1129
+ }
1130
+ language = language_map.get(ext, ext.upper() if ext else None)
1131
+
1132
+ console.print(f"[cyan]Generating code from:[/cyan] {source_desc}")
1133
+ if language:
1134
+ console.print(f"[cyan]Target language:[/cyan] {language}")
1135
+ console.print(f"[cyan]Output:[/cyan] {output}\n")
1136
+
1137
+ # Build prompt
1138
+ prompt = f"Specification:\n\n{spec_content}\n\n"
1139
+ if language:
1140
+ prompt += f"Generate complete, production-ready {language} code that implements this specification. "
1141
+ else:
1142
+ prompt += "Generate complete, production-ready code that implements this specification. "
1143
+ prompt += "Include proper error handling, documentation, and best practices."
1144
+
1145
+ # Add context if requested
1146
+ if auto_context:
1147
+ from claude_dev_cli.context import ContextGatherer
1148
+
1149
+ with console.status("[bold blue]Gathering project context..."):
1150
+ gatherer = ContextGatherer()
1151
+ # Gather context from current directory
1152
+ context = gatherer.gather_for_file(".", include_git=True)
1153
+ context_info = context.format_for_prompt()
1154
+
1155
+ console.print("[dim]✓ Context gathered[/dim]")
1156
+ prompt = f"{context_info}\n\n{prompt}"
1157
+
1158
+ # Generate code
1159
+ with console.status(f"[bold blue]Generating code..."):
1160
+ client = ClaudeClient(api_config_name=api, model=model)
1161
+ result = client.call(prompt)
1162
+
1163
+ # Interactive refinement
1164
+ if interactive:
1165
+ console.print("\n[bold]Initial Code:[/bold]\n")
1166
+ console.print(result)
1167
+
1168
+ client = ClaudeClient(api_config_name=api, model=model)
1169
+ conversation_context = [result]
1170
+
1171
+ while True:
1172
+ console.print("\n[dim]Commands: 'save' to save and exit, 'exit' to discard, or ask for changes[/dim]")
1173
+ user_input = console.input("[cyan]You:[/cyan] ").strip()
1174
+
1175
+ if user_input.lower() == 'exit':
1176
+ console.print("[yellow]Discarded changes[/yellow]")
1177
+ return
1178
+
1179
+ if user_input.lower() == 'save':
1180
+ result = conversation_context[-1]
1181
+ break
1182
+
1183
+ if not user_input:
1184
+ continue
1185
+
1186
+ # Get refinement
1187
+ refinement_prompt = f"Previous code:\n\n{conversation_context[-1]}\n\nUser request: {user_input}\n\nProvide the updated code."
1188
+
1189
+ console.print("\n[bold green]Claude:[/bold green] ", end='')
1190
+ response_parts = []
1191
+ for chunk in client.call_streaming(refinement_prompt):
1192
+ console.print(chunk, end='')
1193
+ response_parts.append(chunk)
1194
+ console.print()
1195
+
1196
+ result = ''.join(response_parts)
1197
+ conversation_context.append(result)
1198
+
1199
+ # Save output
1200
+ Path(output).write_text(result)
1201
+ console.print(f"\n[green]✓[/green] Code saved to: {output}")
1202
+
1203
+ except Exception as e:
1204
+ console.print(f"[red]Error: {e}[/red]")
1205
+ sys.exit(1)
1206
+
1207
+
1208
+ @generate.command('feature')
1209
+ @click.argument('paths', nargs=-1, type=click.Path(exists=True))
1210
+ @click.option('--description', help='Inline feature specification')
1211
+ @click.option('-f', '--file', 'spec_file', type=click.Path(exists=True), help='Read specification from file')
1212
+ @click.option('--pdf', type=click.Path(exists=True), help='Read specification from PDF')
1213
+ @click.option('--url', help='Fetch specification from URL')
1214
+ @click.option('--max-files', type=int, default=10, help='Maximum files to modify (default: 10)')
1215
+ @click.option('-m', '--model', help='Model profile to use')
1216
+ @click.option('-a', '--api', help='API config to use')
1217
+ @click.option('-i', '--interactive', is_flag=True, help='Interactive refinement mode')
1218
+ @click.option('--auto-context', is_flag=True, help='Include project context')
1219
+ @click.option('--preview', is_flag=True, help='Preview changes without applying')
1220
+ @click.pass_context
1221
+ def gen_feature(
1222
+ ctx: click.Context,
1223
+ paths: tuple,
1224
+ description: Optional[str],
1225
+ spec_file: Optional[str],
1226
+ pdf: Optional[str],
1227
+ url: Optional[str],
1228
+ max_files: int,
1229
+ model: Optional[str],
1230
+ api: Optional[str],
1231
+ interactive: bool,
1232
+ auto_context: bool,
1233
+ preview: bool
1234
+ ) -> None:
1235
+ """Generate code to add a feature to existing project.
1236
+
1237
+ Analyzes existing code and generates changes to implement a feature.
1238
+
1239
+ Examples:
1240
+ cdc generate feature --description "Add authentication" src/
1241
+ cdc generate feature --file feature-spec.md
1242
+ cdc generate feature --pdf requirements.pdf --preview
1243
+ cdc generate feature --url https://example.com/spec src/
1244
+ """
1245
+ console = ctx.obj['console']
1246
+ from claude_dev_cli.input_sources import get_input_content
1247
+ from claude_dev_cli.path_utils import expand_paths, auto_detect_files
1248
+
1249
+ try:
1250
+ # Get feature specification
1251
+ spec_content, source_desc = get_input_content(
1252
+ description=description,
1253
+ file_path=spec_file,
1254
+ pdf_path=pdf,
1255
+ url=url,
1256
+ console=console
1257
+ )
1258
+
1259
+ # Determine files to analyze
1260
+ if paths:
1261
+ files = expand_paths(list(paths), max_files=max_files)
1262
+ else:
1263
+ files = auto_detect_files()
1264
+ if files:
1265
+ console.print(f"[dim]Auto-detected {len(files)} file(s) from project[/dim]")
1266
+
1267
+ if not files:
1268
+ console.print("[yellow]No files found. Specify paths or run in a project directory.[/yellow]")
1269
+ return
1270
+
1271
+ console.print(f"[cyan]Feature specification from:[/cyan] {source_desc}")
1272
+ console.print(f"[cyan]Analyzing:[/cyan] {len(files)} file(s)\n")
1273
+
1274
+ # Show files
1275
+ if len(files) > 1:
1276
+ console.print(f"[bold]Files to analyze:[/bold]")
1277
+ for f in files[:5]:
1278
+ console.print(f" • {f}")
1279
+ if len(files) > 5:
1280
+ console.print(f" ... and {len(files) - 5} more")
1281
+ console.print()
1282
+
1283
+ # Build codebase content
1284
+ codebase_content = ""
1285
+ for file_path in files:
1286
+ try:
1287
+ with open(file_path, 'r') as f:
1288
+ content = f.read()
1289
+ codebase_content += f"\n\n## File: {file_path}\n\n```\n{content}\n```\n"
1290
+ except Exception as e:
1291
+ console.print(f"[yellow]Warning: Could not read {file_path}: {e}[/yellow]")
1292
+
1293
+ # Build prompt
1294
+ prompt = f"Feature Specification:\n\n{spec_content}\n\n"
1295
+ prompt += f"Existing Codebase:{codebase_content}\n\n"
1296
+ prompt += "Analyze the existing code and provide:\n"
1297
+ prompt += "1. Implementation plan for the feature\n"
1298
+ prompt += "2. List of files to modify or create\n"
1299
+ prompt += "3. Complete code changes (diffs or new files)\n"
1300
+ prompt += "4. Any necessary setup or configuration changes\n\n"
1301
+ prompt += "Be specific and provide complete, working code."
1302
+
1303
+ # Add context if requested
1304
+ if auto_context:
1305
+ from claude_dev_cli.context import ContextGatherer
1306
+
1307
+ with console.status("[bold blue]Gathering project context..."):
1308
+ gatherer = ContextGatherer()
1309
+ context = gatherer.gather_for_file(files[0], include_git=True)
1310
+ context_info = context.format_for_prompt()
1311
+
1312
+ console.print("[dim]✓ Context gathered[/dim]")
1313
+ prompt = f"{context_info}\n\n{prompt}"
1314
+
1315
+ # Generate feature implementation
1316
+ with console.status(f"[bold blue]Analyzing codebase and generating feature implementation..."):
1317
+ client = ClaudeClient(api_config_name=api, model=model)
1318
+ result = client.call(prompt)
1319
+
1320
+ # Show result
1321
+ from rich.markdown import Markdown
1322
+ md = Markdown(result)
1323
+ console.print(md)
1324
+
1325
+ if preview:
1326
+ console.print("\n[yellow]Preview mode - no changes applied[/yellow]")
1327
+ console.print("[dim]Remove --preview flag to apply changes[/dim]")
1328
+ return
1329
+
1330
+ # Interactive refinement
1331
+ if interactive:
1332
+ client = ClaudeClient(api_config_name=api, model=model)
1333
+ conversation_context = [result]
1334
+
1335
+ while True:
1336
+ console.print("\n[dim]Ask for changes, 'apply' to confirm, or 'exit' to cancel[/dim]")
1337
+ user_input = console.input("[cyan]You:[/cyan] ").strip()
1338
+
1339
+ if user_input.lower() == 'exit':
1340
+ console.print("[yellow]Cancelled[/yellow]")
1341
+ return
1342
+
1343
+ if user_input.lower() == 'apply':
1344
+ console.print("[green]✓[/green] Implementation plan ready")
1345
+ console.print("[dim]Apply the changes manually from the output above[/dim]")
1346
+ return
1347
+
1348
+ if not user_input:
1349
+ continue
1350
+
1351
+ # Get refinement
1352
+ refinement_prompt = f"Previous implementation plan:\n\n{conversation_context[-1]}\n\nUser request: {user_input}\n\nProvide the updated implementation."
1353
+
1354
+ console.print("\n[bold green]Claude:[/bold green] ", end='')
1355
+ response_parts = []
1356
+ for chunk in client.call_streaming(refinement_prompt):
1357
+ console.print(chunk, end='')
1358
+ response_parts.append(chunk)
1359
+ console.print()
1360
+
1361
+ result = ''.join(response_parts)
1362
+ conversation_context.append(result)
1363
+ else:
1364
+ console.print("\n[green]✓[/green] Feature implementation generated")
1365
+ console.print("[dim]Apply the changes manually from the output above[/dim]")
1366
+
1367
+ except Exception as e:
1368
+ console.print(f"[red]Error: {e}[/red]")
1369
+ sys.exit(1)
1370
+
1371
+
1063
1372
  @main.command('review')
1064
1373
  @click.argument('paths', nargs=-1, type=click.Path(exists=True))
1065
1374
  @click.option('-a', '--api', help='API config to use')
@@ -0,0 +1,231 @@
1
+ """Input source handlers for reading specifications from various sources."""
2
+
3
+ from pathlib import Path
4
+ from typing import Optional, Tuple
5
+ from rich.console import Console
6
+
7
+
8
+ def read_text_input(text: str) -> str:
9
+ """Read text input directly."""
10
+ return text
11
+
12
+
13
+ def read_file_input(file_path: str) -> str:
14
+ """Read input from a file.
15
+
16
+ Args:
17
+ file_path: Path to the file
18
+
19
+ Returns:
20
+ File contents as string
21
+
22
+ Raises:
23
+ FileNotFoundError: If file doesn't exist
24
+ IOError: If file can't be read
25
+ """
26
+ path = Path(file_path)
27
+ if not path.exists():
28
+ raise FileNotFoundError(f"File not found: {file_path}")
29
+
30
+ return path.read_text(encoding='utf-8')
31
+
32
+
33
+ def read_pdf_input(pdf_path: str) -> str:
34
+ """Read text content from a PDF file.
35
+
36
+ Args:
37
+ pdf_path: Path to the PDF file
38
+
39
+ Returns:
40
+ Extracted text from PDF
41
+
42
+ Raises:
43
+ ImportError: If pypdf is not installed
44
+ FileNotFoundError: If PDF doesn't exist
45
+ Exception: If PDF can't be parsed
46
+ """
47
+ try:
48
+ from pypdf import PdfReader
49
+ except ImportError:
50
+ raise ImportError(
51
+ "PDF support requires pypdf. Install with: "
52
+ "pip install 'claude-dev-cli[generation]'"
53
+ )
54
+
55
+ path = Path(pdf_path)
56
+ if not path.exists():
57
+ raise FileNotFoundError(f"PDF not found: {pdf_path}")
58
+
59
+ try:
60
+ reader = PdfReader(path)
61
+ text_parts = []
62
+ for page in reader.pages:
63
+ text = page.extract_text()
64
+ if text:
65
+ text_parts.append(text)
66
+
67
+ if not text_parts:
68
+ raise ValueError(f"No text could be extracted from PDF: {pdf_path}")
69
+
70
+ return "\n\n".join(text_parts)
71
+ except Exception as e:
72
+ raise Exception(f"Failed to read PDF {pdf_path}: {str(e)}")
73
+
74
+
75
+ def read_url_input(url: str) -> str:
76
+ """Fetch and extract text content from a URL.
77
+
78
+ Args:
79
+ url: URL to fetch
80
+
81
+ Returns:
82
+ Extracted text content
83
+
84
+ Raises:
85
+ ImportError: If requests or beautifulsoup4 are not installed
86
+ Exception: If URL can't be fetched or parsed
87
+ """
88
+ try:
89
+ import requests
90
+ from bs4 import BeautifulSoup
91
+ except ImportError:
92
+ raise ImportError(
93
+ "URL support requires requests and beautifulsoup4. Install with: "
94
+ "pip install 'claude-dev-cli[generation]'"
95
+ )
96
+
97
+ # Validate URL format
98
+ if not url.startswith(('http://', 'https://')):
99
+ raise ValueError(f"Invalid URL format: {url}")
100
+
101
+ try:
102
+ # Fetch content
103
+ response = requests.get(url, timeout=30, headers={
104
+ 'User-Agent': 'claude-dev-cli/0.11.0'
105
+ })
106
+ response.raise_for_status()
107
+
108
+ # Determine content type
109
+ content_type = response.headers.get('Content-Type', '').lower()
110
+
111
+ if 'text/plain' in content_type:
112
+ # Plain text - return as-is
113
+ return response.text
114
+
115
+ elif 'text/html' in content_type or 'application/xhtml' in content_type:
116
+ # HTML - extract text
117
+ soup = BeautifulSoup(response.content, 'html.parser')
118
+
119
+ # Remove script and style elements
120
+ for script in soup(['script', 'style', 'nav', 'footer', 'header']):
121
+ script.decompose()
122
+
123
+ # Get text
124
+ text = soup.get_text(separator='\n', strip=True)
125
+
126
+ # Clean up extra whitespace
127
+ lines = [line.strip() for line in text.splitlines() if line.strip()]
128
+ return '\n'.join(lines)
129
+
130
+ elif 'application/json' in content_type:
131
+ # JSON - return formatted
132
+ import json
133
+ return json.dumps(response.json(), indent=2)
134
+
135
+ else:
136
+ # Unknown content type - try to decode as text
137
+ return response.text
138
+
139
+ except requests.RequestException as e:
140
+ raise Exception(f"Failed to fetch URL {url}: {str(e)}")
141
+ except Exception as e:
142
+ raise Exception(f"Failed to parse content from {url}: {str(e)}")
143
+
144
+
145
+ def get_input_content(
146
+ description: Optional[str] = None,
147
+ file_path: Optional[str] = None,
148
+ pdf_path: Optional[str] = None,
149
+ url: Optional[str] = None,
150
+ console: Optional[Console] = None
151
+ ) -> Tuple[str, str]:
152
+ """Get input content from one of the available sources.
153
+
154
+ Args:
155
+ description: Direct text description
156
+ file_path: Path to file
157
+ pdf_path: Path to PDF
158
+ url: URL to fetch
159
+ console: Rich console for output
160
+
161
+ Returns:
162
+ Tuple of (content, source_description)
163
+
164
+ Raises:
165
+ ValueError: If multiple sources or no sources provided
166
+ Various exceptions from individual read functions
167
+ """
168
+ if console is None:
169
+ console = Console()
170
+
171
+ # Count how many sources are provided
172
+ sources = [
173
+ ('description', description),
174
+ ('file', file_path),
175
+ ('pdf', pdf_path),
176
+ ('url', url)
177
+ ]
178
+ provided_sources = [(name, value) for name, value in sources if value]
179
+
180
+ if len(provided_sources) == 0:
181
+ raise ValueError(
182
+ "No input source provided. Use one of:\n"
183
+ " --description TEXT\n"
184
+ " -f/--file PATH\n"
185
+ " --pdf PATH\n"
186
+ " --url URL"
187
+ )
188
+
189
+ if len(provided_sources) > 1:
190
+ source_names = [name for name, _ in provided_sources]
191
+ raise ValueError(
192
+ f"Multiple input sources provided: {', '.join(source_names)}. "
193
+ f"Please use only one."
194
+ )
195
+
196
+ source_type, source_value = provided_sources[0]
197
+
198
+ # Read from the appropriate source
199
+ if source_type == 'description':
200
+ content = read_text_input(source_value)
201
+ source_desc = "text description"
202
+
203
+ elif source_type == 'file':
204
+ console.print(f"[cyan]Reading from file:[/cyan] {source_value}")
205
+ content = read_file_input(source_value)
206
+ source_desc = f"file: {source_value}"
207
+
208
+ elif source_type == 'pdf':
209
+ console.print(f"[cyan]Extracting text from PDF:[/cyan] {source_value}")
210
+ try:
211
+ content = read_pdf_input(source_value)
212
+ console.print(f"[green]✓[/green] Extracted {len(content)} characters from PDF")
213
+ source_desc = f"PDF: {source_value}"
214
+ except ImportError as e:
215
+ console.print(f"[red]Error:[/red] {str(e)}")
216
+ raise
217
+
218
+ elif source_type == 'url':
219
+ console.print(f"[cyan]Fetching content from URL:[/cyan] {source_value}")
220
+ try:
221
+ content = read_url_input(source_value)
222
+ console.print(f"[green]✓[/green] Fetched {len(content)} characters from URL")
223
+ source_desc = f"URL: {source_value}"
224
+ except ImportError as e:
225
+ console.print(f"[red]Error:[/red] {str(e)}")
226
+ raise
227
+
228
+ else:
229
+ raise ValueError(f"Unknown source type: {source_type}")
230
+
231
+ return content, source_desc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-dev-cli
3
- Version: 0.11.0
3
+ Version: 0.12.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
@@ -33,6 +33,10 @@ Provides-Extra: toon
33
33
  Requires-Dist: toon-format>=0.1.0; extra == "toon"
34
34
  Provides-Extra: plugins
35
35
  Requires-Dist: pygments>=2.0.0; extra == "plugins"
36
+ Provides-Extra: generation
37
+ Requires-Dist: pypdf>=3.0.0; extra == "generation"
38
+ Requires-Dist: requests>=2.28.0; extra == "generation"
39
+ Requires-Dist: beautifulsoup4>=4.0.0; extra == "generation"
36
40
  Provides-Extra: dev
37
41
  Requires-Dist: pytest>=7.0.0; extra == "dev"
38
42
  Requires-Dist: black>=23.0.0; extra == "dev"
@@ -40,13 +44,16 @@ Requires-Dist: ruff>=0.1.0; extra == "dev"
40
44
  Requires-Dist: mypy>=1.0.0; extra == "dev"
41
45
  Requires-Dist: toon-format>=0.1.0; extra == "dev"
42
46
  Requires-Dist: pygments>=2.0.0; extra == "dev"
47
+ Requires-Dist: pypdf>=3.0.0; extra == "dev"
48
+ Requires-Dist: requests>=2.28.0; extra == "dev"
49
+ Requires-Dist: beautifulsoup4>=4.0.0; extra == "dev"
43
50
  Dynamic: license-file
44
51
 
45
52
  # Claude Dev CLI
46
53
 
47
54
  [![PyPI version](https://badge.fury.io/py/claude-dev-cli.svg)](https://badge.fury.io/py/claude-dev-cli)
48
55
  [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
49
- [![Tests](https://img.shields.io/badge/tests-285%20passing-brightgreen.svg)](https://github.com/thinmanj/claude-dev-cli)
56
+ [![Tests](https://img.shields.io/badge/tests-303%20passing-brightgreen.svg)](https://github.com/thinmanj/claude-dev-cli)
50
57
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
51
58
  [![Homebrew](https://img.shields.io/badge/homebrew-available-orange.svg)](https://github.com/thinmanj/homebrew-tap)
52
59
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
@@ -72,6 +79,26 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
72
79
  - `smart`: Claude Sonnet 4 ($3.00/$15.00 per Mtok) - default
73
80
  - `powerful`: Claude Opus 4 ($15.00/$75.00 per Mtok)
74
81
 
82
+ ### 🚀 Code Generation (v0.12.0+)
83
+ - **Generate Code from Specs**: Create new code from descriptions, files, PDFs, or URLs
84
+ - `cdc generate code --description "REST API client" -o client.py`
85
+ - Multiple input sources: text, files (.md, .txt), PDFs, URLs
86
+ - Auto-detects target language from file extension
87
+ - Interactive refinement mode
88
+ - **Add Features to Projects**: Analyze existing code and generate implementation plans
89
+ - `cdc generate feature --description "Add authentication" src/`
90
+ - Multi-file analysis and modification
91
+ - Preview mode to review changes before applying
92
+ - Supports same input sources as code generation
93
+ - **Multiple Input Sources**:
94
+ - `--description TEXT`: Inline specification
95
+ - `-f/--file PATH`: Read from file
96
+ - `--pdf PATH`: Extract from PDF
97
+ - `--url URL`: Fetch from URL
98
+ - **Optional Dependencies**: Install with `pip install 'claude-dev-cli[generation]'`
99
+ - Enables PDF and URL support
100
+ - Graceful fallback if not installed
101
+
75
102
  ### 📁 Multi-File Support (v0.11.0+)
76
103
  - **Batch Processing**: Review, refactor, test, or document multiple files at once
77
104
  - **Directory Support**: Process all code files in a directory with `--max-files` limit
@@ -149,8 +176,14 @@ brew install thinmanj/tap/claude-dev-cli
149
176
  # Basic installation
150
177
  pip install claude-dev-cli
151
178
 
179
+ # With code generation support (PDF & URL input)
180
+ pip install claude-dev-cli[generation]
181
+
152
182
  # With TOON support (30-60% token reduction)
153
183
  pip install claude-dev-cli[toon]
184
+
185
+ # With all optional features
186
+ pip install claude-dev-cli[generation,toon]
154
187
  ```
155
188
 
156
189
  ### Via pipx (Recommended for CLI tools)
@@ -159,8 +192,14 @@ pip install claude-dev-cli[toon]
159
192
  # Isolated installation
160
193
  pipx install claude-dev-cli
161
194
 
195
+ # With code generation support
196
+ pipx install claude-dev-cli[generation]
197
+
162
198
  # With TOON support
163
199
  pipx install claude-dev-cli[toon]
200
+
201
+ # With all optional features
202
+ pipx install claude-dev-cli[generation,toon]
164
203
  ```
165
204
 
166
205
  ## Quick Start
@@ -242,7 +281,35 @@ cdc review -m powerful complex_file.py # More thorough review
242
281
  cdc generate tests -m smart mymodule.py # Balanced approach
243
282
  ```
244
283
 
245
- ### 3. Developer Commands
284
+ ### 3. Code Generation Commands (NEW in v0.12.0)
285
+
286
+ ```bash
287
+ # Generate code from specification
288
+ cdc generate code --description "REST API client for weather data" -o client.py
289
+ cdc generate code --file spec.md -o implementation.go
290
+ cdc generate code --pdf requirements.pdf -o app.js
291
+ cdc generate code --url https://example.com/api-spec -o service.py
292
+
293
+ # Generate code with interactive refinement
294
+ cdc generate code --description "Database ORM" -o orm.py --interactive
295
+
296
+ # Generate code with project context
297
+ cdc generate code --file spec.md -o service.py --auto-context
298
+
299
+ # Add features to existing project
300
+ cdc generate feature --description "Add user authentication with JWT" src/
301
+ cdc generate feature --file feature-spec.md
302
+ cdc generate feature --pdf product-requirements.pdf --preview
303
+ cdc generate feature --url https://example.com/feature-spec
304
+
305
+ # Preview feature changes before applying
306
+ cdc generate feature --description "Add caching layer" src/ --preview
307
+
308
+ # Interactive feature implementation
309
+ cdc generate feature --description "Add logging" src/ --interactive
310
+ ```
311
+
312
+ ### 4. Developer Commands
246
313
 
247
314
  ```bash
248
315
  # Generate tests (single file)
@@ -316,7 +383,7 @@ git add .
316
383
  cdc git commit --auto-context
317
384
  ```
318
385
 
319
- ### 4. Context-Aware Operations (v0.8.0+)
386
+ ### 5. Context-Aware Operations (v0.8.0+)
320
387
 
321
388
  ```bash
322
389
  # Auto-context includes: git info, dependencies, related files
@@ -345,7 +412,7 @@ cdc refactor app.py --auto-context
345
412
  # Automatically includes imported modules and dependencies
346
413
  ```
347
414
 
348
- ### 5. Custom Templates
415
+ ### 6. Custom Templates
349
416
 
350
417
  ```bash
351
418
  # List all templates (built-in and user)
@@ -1,10 +1,11 @@
1
- claude_dev_cli/__init__.py,sha256=XSFQv1m1nRRX-T9POeBmjHrA0pylgusfmwtA92XCEzo,470
2
- claude_dev_cli/cli.py,sha256=RkoR4ocGUfP5A37yl_xObdNdd0QKeyqvEf2YOq1CL0U,79000
1
+ claude_dev_cli/__init__.py,sha256=Qaoj-1FmqkHY4Lz4nzM6MhKNF3sooMTTKgLyBq-aiM8,470
2
+ claude_dev_cli/cli.py,sha256=SKL0Sy1fyHziPoK3FQOVgJ6cwJK8cmmBWoAAP3oP720,91797
3
3
  claude_dev_cli/commands.py,sha256=RKGx2rv56PM6eErvA2uoQ20hY8babuI5jav8nCUyUOk,3964
4
4
  claude_dev_cli/config.py,sha256=ZnPvzwlXsoY9YhqTl4S__fwY1MzJXKIaYK0nIIelNXk,19978
5
5
  claude_dev_cli/context.py,sha256=1TlLzpREFZDEIuU7RAtlkjxARKWZpnxHHvK283sUAZE,26714
6
6
  claude_dev_cli/core.py,sha256=4tKBgPQzvhM-jtlHaIy2K54vc2yIb4ycNDPLpoIoqN0,6621
7
7
  claude_dev_cli/history.py,sha256=26EjNW68JuFQJhUp1j8UdB19S-eYz3eqevkpCOATwP0,10510
8
+ claude_dev_cli/input_sources.py,sha256=pFX5pU8uAUW_iujYdV3z1c_6F0KbKTWMNG0ChvKbxC8,7115
8
9
  claude_dev_cli/path_utils.py,sha256=FFwweSkXe9OiG2Dej_UDKcY8-ZCYjL89ow6c7LZGe80,5564
9
10
  claude_dev_cli/secure_storage.py,sha256=KcZuQMLTbQpMAi2Cyh-_JkNcK9vHzAITOgjTcM9sr98,8161
10
11
  claude_dev_cli/template_manager.py,sha256=wtcrNuxFoJLJIPmIxUzrPKrE8kUvdqEd53EnG3jARhg,9277
@@ -18,9 +19,9 @@ claude_dev_cli/plugins/base.py,sha256=H4HQet1I-a3WLCfE9F06Lp8NuFvVoIlou7sIgyJFK-
18
19
  claude_dev_cli/plugins/diff_editor/__init__.py,sha256=gqR5S2TyIVuq-sK107fegsutQ7Z-sgAIEbtc71FhXIM,101
19
20
  claude_dev_cli/plugins/diff_editor/plugin.py,sha256=M1bUoqpasD3ZNQo36Fu_8g92uySPZyG_ujMbj5UplsU,3073
20
21
  claude_dev_cli/plugins/diff_editor/viewer.py,sha256=1IOXIKw_01ppJx5C1dQt9Kr6U1TdAHT8_iUT5r_q0NM,17169
21
- claude_dev_cli-0.11.0.dist-info/licenses/LICENSE,sha256=DGueuJwMJtMwgLO5mWlS0TaeBrFwQuNpNZ22PU9J2bw,1062
22
- claude_dev_cli-0.11.0.dist-info/METADATA,sha256=5fvuAb55hqZwnB_j-wzQNFv6ZXZbdnvEbAzt9pvmxtM,21330
23
- claude_dev_cli-0.11.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
24
- claude_dev_cli-0.11.0.dist-info/entry_points.txt,sha256=zymgUIIVpFTARkFmxAuW2A4BQsNITh_L0uU-XunytHg,85
25
- claude_dev_cli-0.11.0.dist-info/top_level.txt,sha256=m7MF6LOIuTe41IT5Fgt0lc-DK1EgM4gUU_IZwWxK0pg,15
26
- claude_dev_cli-0.11.0.dist-info/RECORD,,
22
+ claude_dev_cli-0.12.0.dist-info/licenses/LICENSE,sha256=DGueuJwMJtMwgLO5mWlS0TaeBrFwQuNpNZ22PU9J2bw,1062
23
+ claude_dev_cli-0.12.0.dist-info/METADATA,sha256=S6ijTS_zClkYYgGuHO_hcCtTRO4TmXZS6rE_JCCjYzc,24018
24
+ claude_dev_cli-0.12.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
25
+ claude_dev_cli-0.12.0.dist-info/entry_points.txt,sha256=zymgUIIVpFTARkFmxAuW2A4BQsNITh_L0uU-XunytHg,85
26
+ claude_dev_cli-0.12.0.dist-info/top_level.txt,sha256=m7MF6LOIuTe41IT5Fgt0lc-DK1EgM4gUU_IZwWxK0pg,15
27
+ claude_dev_cli-0.12.0.dist-info/RECORD,,