claude-dev-cli 0.8.1__tar.gz → 0.8.2__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 (41) hide show
  1. {claude_dev_cli-0.8.1/src/claude_dev_cli.egg-info → claude_dev_cli-0.8.2}/PKG-INFO +12 -4
  2. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/README.md +11 -3
  3. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/pyproject.toml +1 -1
  4. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/__init__.py +1 -1
  5. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/cli.py +101 -0
  6. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/context.py +179 -5
  7. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2/src/claude_dev_cli.egg-info}/PKG-INFO +12 -4
  8. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_context.py +136 -0
  9. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/LICENSE +0 -0
  10. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/MANIFEST.in +0 -0
  11. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/setup.cfg +0 -0
  12. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/commands.py +0 -0
  13. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/config.py +0 -0
  14. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/core.py +0 -0
  15. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/history.py +0 -0
  16. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/plugins/__init__.py +0 -0
  17. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/plugins/base.py +0 -0
  18. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/plugins/diff_editor/__init__.py +0 -0
  19. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/plugins/diff_editor/plugin.py +0 -0
  20. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/plugins/diff_editor/viewer.py +0 -0
  21. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/secure_storage.py +0 -0
  22. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/template_manager.py +0 -0
  23. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/templates.py +0 -0
  24. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/toon_utils.py +0 -0
  25. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/usage.py +0 -0
  26. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/warp_integration.py +0 -0
  27. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli/workflows.py +0 -0
  28. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli.egg-info/SOURCES.txt +0 -0
  29. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli.egg-info/dependency_links.txt +0 -0
  30. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli.egg-info/entry_points.txt +0 -0
  31. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli.egg-info/requires.txt +0 -0
  32. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/src/claude_dev_cli.egg-info/top_level.txt +0 -0
  33. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_cli.py +0 -0
  34. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_commands.py +0 -0
  35. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_config.py +0 -0
  36. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_core.py +0 -0
  37. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_diff_editor.py +0 -0
  38. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_secure_storage.py +0 -0
  39. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_template_manager.py +0 -0
  40. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/tests/test_toon_utils.py +0 -0
  41. {claude_dev_cli-0.8.1 → claude_dev_cli-0.8.2}/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.8.1
3
+ Version: 0.8.2
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
@@ -85,7 +85,8 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
85
85
  - `git commit`, `generate tests`, `generate docs` (v0.8.1)
86
86
  - **Git Integration**: Automatically include branch, commits, modified files
87
87
  - **Dependency Analysis**: Parse imports and include related files
88
- - **Error Parsing**: Structured Python traceback parsing
88
+ - **Multi-Language Error Parsing** (v0.8.2): Python, JavaScript/TypeScript, Go, Rust, Java
89
+ - **Context Summary** (v0.8.2): Preview context before API calls with `cdc context summary`
89
90
  - **Smart Truncation**: Prevent token limits with configurable file size limits
90
91
  - **Project Memory**: Remember preferences per project
91
92
  - **Global Config**: Set context defaults in `~/.claude-dev-cli/config.json`
@@ -199,7 +200,7 @@ git add .
199
200
  cdc git commit --auto-context
200
201
  ```
201
202
 
202
- ### 4. Context-Aware Operations (NEW in v0.8.0)
203
+ ### 4. Context-Aware Operations (v0.8.0+)
203
204
 
204
205
  ```bash
205
206
  # Auto-context includes: git info, dependencies, related files
@@ -208,9 +209,16 @@ cdc git commit --auto-context
208
209
  cdc review mymodule.py --auto-context
209
210
  # ✓ Context gathered (git, dependencies, tests)
210
211
 
211
- # Debug with parsed error details
212
+ # Debug with parsed error details (multi-language support)
212
213
  python broken.py 2>&1 | cdc debug -f broken.py --auto-context
214
+ node app.js 2>&1 | cdc debug --auto-context # JavaScript/TypeScript
215
+ go run main.go 2>&1 | cdc debug --auto-context # Go
213
216
  # ✓ Context gathered (error details, git context)
217
+ # Supports: Python, JavaScript, TypeScript, Go, Rust, Java
218
+
219
+ # Preview context before making API calls - NEW in v0.8.2
220
+ cdc context summary mymodule.py
221
+ # Shows: files, sizes, lines, estimated tokens, truncation warnings
214
222
 
215
223
  # Ask questions with file context
216
224
  cdc ask -f mycode.py --auto-context "how can I improve this?"
@@ -41,7 +41,8 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
41
41
  - `git commit`, `generate tests`, `generate docs` (v0.8.1)
42
42
  - **Git Integration**: Automatically include branch, commits, modified files
43
43
  - **Dependency Analysis**: Parse imports and include related files
44
- - **Error Parsing**: Structured Python traceback parsing
44
+ - **Multi-Language Error Parsing** (v0.8.2): Python, JavaScript/TypeScript, Go, Rust, Java
45
+ - **Context Summary** (v0.8.2): Preview context before API calls with `cdc context summary`
45
46
  - **Smart Truncation**: Prevent token limits with configurable file size limits
46
47
  - **Project Memory**: Remember preferences per project
47
48
  - **Global Config**: Set context defaults in `~/.claude-dev-cli/config.json`
@@ -155,7 +156,7 @@ git add .
155
156
  cdc git commit --auto-context
156
157
  ```
157
158
 
158
- ### 4. Context-Aware Operations (NEW in v0.8.0)
159
+ ### 4. Context-Aware Operations (v0.8.0+)
159
160
 
160
161
  ```bash
161
162
  # Auto-context includes: git info, dependencies, related files
@@ -164,9 +165,16 @@ cdc git commit --auto-context
164
165
  cdc review mymodule.py --auto-context
165
166
  # ✓ Context gathered (git, dependencies, tests)
166
167
 
167
- # Debug with parsed error details
168
+ # Debug with parsed error details (multi-language support)
168
169
  python broken.py 2>&1 | cdc debug -f broken.py --auto-context
170
+ node app.js 2>&1 | cdc debug --auto-context # JavaScript/TypeScript
171
+ go run main.go 2>&1 | cdc debug --auto-context # Go
169
172
  # ✓ Context gathered (error details, git context)
173
+ # Supports: Python, JavaScript, TypeScript, Go, Rust, Java
174
+
175
+ # Preview context before making API calls - NEW in v0.8.2
176
+ cdc context summary mymodule.py
177
+ # Shows: files, sizes, lines, estimated tokens, truncation warnings
170
178
 
171
179
  # Ask questions with file context
172
180
  cdc ask -f mycode.py --auto-context "how can I improve this?"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "claude-dev-cli"
7
- version = "0.8.1"
7
+ version = "0.8.2"
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.8.1"
12
+ __version__ = "0.8.2"
13
13
  __author__ = "Julio"
14
14
  __license__ = "MIT"
15
15
 
@@ -884,6 +884,107 @@ def git_commit(ctx: click.Context, api: Optional[str], auto_context: bool) -> No
884
884
  sys.exit(1)
885
885
 
886
886
 
887
+ @main.group()
888
+ def context() -> None:
889
+ """Context gathering tools and information."""
890
+ pass
891
+
892
+
893
+ @context.command('summary')
894
+ @click.argument('file_path', type=click.Path(exists=True))
895
+ @click.option('--include-git/--no-git', default=True, help='Include git context')
896
+ @click.option('--include-deps/--no-deps', default=True, help='Include dependencies')
897
+ @click.option('--include-tests/--no-tests', default=True, help='Include test files')
898
+ @click.pass_context
899
+ def context_summary(
900
+ ctx: click.Context,
901
+ file_path: str,
902
+ include_git: bool,
903
+ include_deps: bool,
904
+ include_tests: bool
905
+ ) -> None:
906
+ """Show what context would be gathered for a file."""
907
+ from claude_dev_cli.context import ContextGatherer
908
+ from rich.table import Table
909
+
910
+ console = ctx.obj['console']
911
+
912
+ try:
913
+ file_path_obj = Path(file_path)
914
+ gatherer = ContextGatherer()
915
+
916
+ # Gather context
917
+ with console.status("[bold blue]Analyzing context..."):
918
+ context = gatherer.gather_for_review(
919
+ file_path_obj,
920
+ include_git=include_git,
921
+ include_tests=include_tests
922
+ )
923
+
924
+ # Display summary
925
+ console.print(f"\n[bold cyan]Context Summary for:[/bold cyan] {file_path}\n")
926
+
927
+ table = Table(show_header=True, header_style="bold magenta")
928
+ table.add_column("Type", style="cyan")
929
+ table.add_column("Content", style="white")
930
+ table.add_column("Size", justify="right", style="yellow")
931
+ table.add_column("Lines", justify="right", style="green")
932
+ table.add_column("Truncated", justify="center", style="red")
933
+
934
+ total_chars = 0
935
+ total_lines = 0
936
+
937
+ for item in context.items:
938
+ lines = len(item.content.split('\n'))
939
+ chars = len(item.content)
940
+ truncated = "✓" if item.metadata.get('truncated') else ""
941
+
942
+ # Format content preview
943
+ if item.type == 'file':
944
+ content = item.metadata.get('path', 'unknown')
945
+ if item.metadata.get('is_test'):
946
+ content += " [TEST]"
947
+ elif item.type == 'git':
948
+ branch = item.metadata.get('branch', 'unknown')
949
+ modified = item.metadata.get('modified_count', 0)
950
+ content = f"Branch: {branch}, {modified} modified files"
951
+ elif item.type == 'dependency':
952
+ dep_files = item.metadata.get('dependency_files', [])
953
+ content = f"{len(dep_files)} dependency files"
954
+ else:
955
+ content = item.type
956
+
957
+ table.add_row(
958
+ item.type.title(),
959
+ content[:60] + "..." if len(content) > 60 else content,
960
+ f"{chars:,}",
961
+ f"{lines:,}",
962
+ truncated
963
+ )
964
+
965
+ total_chars += chars
966
+ total_lines += lines
967
+
968
+ console.print(table)
969
+
970
+ # Show totals
971
+ console.print(f"\n[bold]Total:[/bold]")
972
+ console.print(f" Characters: [yellow]{total_chars:,}[/yellow]")
973
+ console.print(f" Lines: [green]{total_lines:,}[/green]")
974
+ console.print(f" Estimated tokens: [cyan]~{total_chars // 4:,}[/cyan] (rough estimate)")
975
+
976
+ # Show any truncation warnings
977
+ truncated_items = [item for item in context.items if item.metadata.get('truncated')]
978
+ if truncated_items:
979
+ console.print(f"\n[yellow]⚠ {len(truncated_items)} item(s) truncated to fit size limits[/yellow]")
980
+
981
+ console.print(f"\n[dim]Use --auto-context with commands to include this context[/dim]")
982
+
983
+ except Exception as e:
984
+ console.print(f"[red]Error: {e}[/red]")
985
+ sys.exit(1)
986
+
987
+
887
988
  @main.command('usage')
888
989
  @click.option('--days', type=int, help='Filter by days')
889
990
  @click.option('--api', help='Filter by API config')
@@ -339,10 +339,25 @@ class DependencyAnalyzer:
339
339
 
340
340
 
341
341
  class ErrorContext:
342
- """Parse and format error context."""
342
+ """Parse and format error context for multiple languages."""
343
343
 
344
344
  @staticmethod
345
- def parse_traceback(error_text: str) -> Dict[str, Any]:
345
+ def detect_language(error_text: str) -> str:
346
+ """Detect programming language from error format."""
347
+ if 'Traceback (most recent call last):' in error_text or 'File "' in error_text:
348
+ return 'python'
349
+ elif 'at ' in error_text and ('.js:' in error_text or '.ts:' in error_text):
350
+ return 'javascript'
351
+ elif 'panic:' in error_text and '.go:' in error_text:
352
+ return 'go'
353
+ elif 'thread' in error_text and 'panicked at' in error_text and '.rs:' in error_text:
354
+ return 'rust'
355
+ elif 'at ' in error_text and '.java:' in error_text:
356
+ return 'java'
357
+ return 'unknown'
358
+
359
+ @staticmethod
360
+ def parse_python_traceback(error_text: str) -> Dict[str, Any]:
346
361
  """Parse Python traceback into structured data."""
347
362
  lines = error_text.split('\n')
348
363
 
@@ -391,24 +406,183 @@ class ErrorContext:
391
406
  'raw': error_text
392
407
  }
393
408
 
394
- return {'frames': frames, 'raw': error_text}
409
+ return {'frames': frames, 'raw': error_text, 'language': 'python'}
410
+
411
+ @staticmethod
412
+ def parse_javascript_stack(error_text: str) -> Dict[str, Any]:
413
+ """Parse JavaScript/TypeScript stack trace."""
414
+ lines = error_text.split('\n')
415
+ frames = []
416
+ error_type = None
417
+ error_message = None
418
+
419
+ for line in lines:
420
+ # Error message usually first: "Error: message" or "TypeError: message"
421
+ if not error_type and (':' in line and not line.strip().startswith('at')):
422
+ parts = line.split(':', 1)
423
+ error_type = parts[0].strip()
424
+ error_message = parts[1].strip() if len(parts) > 1 else ''
425
+ # Stack frame: "at functionName (file.js:line:col)" or "at file.js:line:col"
426
+ elif line.strip().startswith('at '):
427
+ match = re.search(r'at\s+(?:(.+?)\s+)?\(([^)]+)\)|(\S+)$', line)
428
+ if match:
429
+ function = match.group(1) or 'anonymous'
430
+ location = match.group(2) or match.group(3)
431
+ if location and ':' in location:
432
+ parts = location.rsplit(':', 2)
433
+ frames.append({
434
+ 'file': parts[0],
435
+ 'line': int(parts[1]) if len(parts) > 1 and parts[1].isdigit() else None,
436
+ 'column': int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else None,
437
+ 'function': function
438
+ })
439
+
440
+ return {
441
+ 'frames': frames,
442
+ 'error_type': error_type,
443
+ 'error_message': error_message,
444
+ 'raw': error_text,
445
+ 'language': 'javascript'
446
+ }
447
+
448
+ @staticmethod
449
+ def parse_go_panic(error_text: str) -> Dict[str, Any]:
450
+ """Parse Go panic trace."""
451
+ lines = error_text.split('\n')
452
+ frames = []
453
+ error_message = None
454
+
455
+ for line in lines:
456
+ # Panic message: "panic: message"
457
+ if line.startswith('panic:'):
458
+ error_message = line.replace('panic:', '').strip()
459
+ # Stack frame: "function(args)" followed by "\tfile.go:line +0xhex"
460
+ elif '\t' in line and '.go:' in line:
461
+ match = re.search(r'([^/\s]+\.go):(\d+)', line)
462
+ if match:
463
+ frames.append({
464
+ 'file': match.group(1),
465
+ 'line': int(match.group(2)),
466
+ 'function': 'goroutine'
467
+ })
468
+
469
+ return {
470
+ 'frames': frames,
471
+ 'error_type': 'panic',
472
+ 'error_message': error_message,
473
+ 'raw': error_text,
474
+ 'language': 'go'
475
+ }
476
+
477
+ @staticmethod
478
+ def parse_rust_panic(error_text: str) -> Dict[str, Any]:
479
+ """Parse Rust panic message."""
480
+ lines = error_text.split('\n')
481
+ frames = []
482
+ error_message = None
483
+
484
+ for line in lines:
485
+ # Panic message: "thread 'main' panicked at 'message', file.rs:line:col"
486
+ if 'panicked at' in line:
487
+ match = re.search(r"panicked at '([^']+)', ([^:]+):(\d+):(\d+)", line)
488
+ if match:
489
+ error_message = match.group(1)
490
+ frames.append({
491
+ 'file': match.group(2),
492
+ 'line': int(match.group(3)),
493
+ 'column': int(match.group(4)),
494
+ 'function': 'panic'
495
+ })
496
+ # Stack backtrace frames
497
+ elif '.rs:' in line:
498
+ match = re.search(r'([^/\s]+\.rs):(\d+):(\d+)', line)
499
+ if match:
500
+ frames.append({
501
+ 'file': match.group(1),
502
+ 'line': int(match.group(2)),
503
+ 'column': int(match.group(3)),
504
+ 'function': 'unknown'
505
+ })
506
+
507
+ return {
508
+ 'frames': frames,
509
+ 'error_type': 'panic',
510
+ 'error_message': error_message,
511
+ 'raw': error_text,
512
+ 'language': 'rust'
513
+ }
514
+
515
+ @staticmethod
516
+ def parse_java_stack(error_text: str) -> Dict[str, Any]:
517
+ """Parse Java stack trace."""
518
+ lines = error_text.split('\n')
519
+ frames = []
520
+ error_type = None
521
+ error_message = None
522
+
523
+ for line in lines:
524
+ # Exception message: "java.lang.NullPointerException: message"
525
+ if not error_type and 'Exception' in line or 'Error' in line:
526
+ parts = line.split(':', 1)
527
+ error_type = parts[0].strip().split('.')[-1] # Get last part of package
528
+ error_message = parts[1].strip() if len(parts) > 1 else ''
529
+ # Stack frame: "at package.Class.method(File.java:line)"
530
+ elif line.strip().startswith('at '):
531
+ match = re.search(r'at\s+([^(]+)\(([^:]+\.java):(\d+)\)', line)
532
+ if match:
533
+ frames.append({
534
+ 'function': match.group(1),
535
+ 'file': match.group(2),
536
+ 'line': int(match.group(3))
537
+ })
538
+
539
+ return {
540
+ 'frames': frames,
541
+ 'error_type': error_type,
542
+ 'error_message': error_message,
543
+ 'raw': error_text,
544
+ 'language': 'java'
545
+ }
546
+
547
+ @staticmethod
548
+ def parse_traceback(error_text: str) -> Dict[str, Any]:
549
+ """Parse error/traceback with language auto-detection."""
550
+ language = ErrorContext.detect_language(error_text)
551
+
552
+ if language == 'python':
553
+ return ErrorContext.parse_python_traceback(error_text)
554
+ elif language == 'javascript':
555
+ return ErrorContext.parse_javascript_stack(error_text)
556
+ elif language == 'go':
557
+ return ErrorContext.parse_go_panic(error_text)
558
+ elif language == 'rust':
559
+ return ErrorContext.parse_rust_panic(error_text)
560
+ elif language == 'java':
561
+ return ErrorContext.parse_java_stack(error_text)
562
+ else:
563
+ return {'raw': error_text, 'language': 'unknown'}
395
564
 
396
565
  @staticmethod
397
566
  def format_for_ai(error_text: str) -> str:
398
- """Format error for AI consumption."""
567
+ """Format error for AI consumption with language detection."""
399
568
  parsed = ErrorContext.parse_traceback(error_text)
400
569
 
401
570
  if 'error_type' not in parsed:
402
571
  return error_text
403
572
 
573
+ language = parsed.get('language', 'unknown')
404
574
  parts = [
575
+ f"Language: {language.title()}",
405
576
  f"Error Type: {parsed['error_type']}",
406
577
  f"Error Message: {parsed.get('error_message', 'N/A')}",
407
578
  "\nStack Trace:"
408
579
  ]
409
580
 
410
581
  for i, frame in enumerate(parsed.get('frames', []), 1):
411
- parts.append(f" {i}. {frame.get('file', 'unknown')}:{frame.get('line', '?')} in {frame.get('function', 'unknown')}")
582
+ file_loc = f"{frame.get('file', 'unknown')}:{frame.get('line', '?')}"
583
+ if 'column' in frame:
584
+ file_loc += f":{frame.get('column', '?')}"
585
+ parts.append(f" {i}. {file_loc} in {frame.get('function', 'unknown')}")
412
586
  if 'code' in frame:
413
587
  parts.append(f" > {frame['code']}")
414
588
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-dev-cli
3
- Version: 0.8.1
3
+ Version: 0.8.2
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
@@ -85,7 +85,8 @@ A powerful command-line tool for developers using Claude AI with multi-API routi
85
85
  - `git commit`, `generate tests`, `generate docs` (v0.8.1)
86
86
  - **Git Integration**: Automatically include branch, commits, modified files
87
87
  - **Dependency Analysis**: Parse imports and include related files
88
- - **Error Parsing**: Structured Python traceback parsing
88
+ - **Multi-Language Error Parsing** (v0.8.2): Python, JavaScript/TypeScript, Go, Rust, Java
89
+ - **Context Summary** (v0.8.2): Preview context before API calls with `cdc context summary`
89
90
  - **Smart Truncation**: Prevent token limits with configurable file size limits
90
91
  - **Project Memory**: Remember preferences per project
91
92
  - **Global Config**: Set context defaults in `~/.claude-dev-cli/config.json`
@@ -199,7 +200,7 @@ git add .
199
200
  cdc git commit --auto-context
200
201
  ```
201
202
 
202
- ### 4. Context-Aware Operations (NEW in v0.8.0)
203
+ ### 4. Context-Aware Operations (v0.8.0+)
203
204
 
204
205
  ```bash
205
206
  # Auto-context includes: git info, dependencies, related files
@@ -208,9 +209,16 @@ cdc git commit --auto-context
208
209
  cdc review mymodule.py --auto-context
209
210
  # ✓ Context gathered (git, dependencies, tests)
210
211
 
211
- # Debug with parsed error details
212
+ # Debug with parsed error details (multi-language support)
212
213
  python broken.py 2>&1 | cdc debug -f broken.py --auto-context
214
+ node app.js 2>&1 | cdc debug --auto-context # JavaScript/TypeScript
215
+ go run main.go 2>&1 | cdc debug --auto-context # Go
213
216
  # ✓ Context gathered (error details, git context)
217
+ # Supports: Python, JavaScript, TypeScript, Go, Rust, Java
218
+
219
+ # Preview context before making API calls - NEW in v0.8.2
220
+ cdc context summary mymodule.py
221
+ # Shows: files, sizes, lines, estimated tokens, truncation warnings
214
222
 
215
223
  # Ask questions with file context
216
224
  cdc ask -f mycode.py --auto-context "how can I improve this?"
@@ -410,6 +410,31 @@ import json.decoder
410
410
  class TestErrorContext:
411
411
  """Tests for ErrorContext class."""
412
412
 
413
+ def test_detect_language_python(self) -> None:
414
+ """Test Python language detection."""
415
+ error_text = "Traceback (most recent call last):\n File \"test.py\", line 10"
416
+ assert ErrorContext.detect_language(error_text) == 'python'
417
+
418
+ def test_detect_language_javascript(self) -> None:
419
+ """Test JavaScript language detection."""
420
+ error_text = "Error: test\n at func (app.js:10:5)"
421
+ assert ErrorContext.detect_language(error_text) == 'javascript'
422
+
423
+ def test_detect_language_go(self) -> None:
424
+ """Test Go language detection."""
425
+ error_text = "panic: test\n\tmain.go:15"
426
+ assert ErrorContext.detect_language(error_text) == 'go'
427
+
428
+ def test_detect_language_rust(self) -> None:
429
+ """Test Rust language detection."""
430
+ error_text = "thread 'main' panicked at 'test', main.rs:10:5"
431
+ assert ErrorContext.detect_language(error_text) == 'rust'
432
+
433
+ def test_detect_language_java(self) -> None:
434
+ """Test Java language detection."""
435
+ error_text = "Exception in thread\nat Test.java:10"
436
+ assert ErrorContext.detect_language(error_text) == 'java'
437
+
413
438
  def test_parse_simple_traceback(self) -> None:
414
439
  """Test parsing a simple Python traceback."""
415
440
  error_text = """
@@ -505,6 +530,117 @@ TypeError: execute() missing 1 required positional argument
505
530
  assert "TypeError" in context_item.content
506
531
  assert "main.py" in context_item.content
507
532
  assert "error_type" in context_item.metadata
533
+
534
+ def test_parse_javascript_stack(self) -> None:
535
+ """Test JavaScript stack trace parsing."""
536
+ error_text = """
537
+ TypeError: Cannot read property 'foo' of undefined
538
+ at myFunction (app.js:42:15)
539
+ at main (index.js:10:5)
540
+ at startup.js:100:1
541
+ """
542
+
543
+ parsed = ErrorContext.parse_javascript_stack(error_text)
544
+
545
+ assert parsed['language'] == 'javascript'
546
+ assert parsed['error_type'] == 'TypeError'
547
+ assert "Cannot read property" in parsed['error_message']
548
+ assert len(parsed['frames']) == 3
549
+
550
+ frame1 = parsed['frames'][0]
551
+ assert frame1['file'] == 'app.js'
552
+ assert frame1['line'] == 42
553
+ assert frame1['column'] == 15
554
+ assert frame1['function'] == 'myFunction'
555
+
556
+ def test_parse_go_panic(self) -> None:
557
+ """Test Go panic trace parsing."""
558
+ error_text = """
559
+ panic: runtime error: index out of range
560
+
561
+ goroutine 1 [running]:
562
+ main.process()
563
+ /path/to/main.go:45 +0x1a3
564
+ main.main()
565
+ /path/to/main.go:20 +0x2e
566
+ """
567
+
568
+ parsed = ErrorContext.parse_go_panic(error_text)
569
+
570
+ assert parsed['language'] == 'go'
571
+ assert parsed['error_type'] == 'panic'
572
+ assert 'index out of range' in parsed['error_message']
573
+ assert len(parsed['frames']) >= 2
574
+
575
+ # Check that we found the files
576
+ files = [f['file'] for f in parsed['frames']]
577
+ assert any('main.go' in f for f in files)
578
+
579
+ def test_parse_rust_panic(self) -> None:
580
+ """Test Rust panic message parsing."""
581
+ error_text = """
582
+ thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value', src/main.rs:42:9
583
+ stack backtrace:
584
+ 0: rust_begin_unwind
585
+ at /rustc/lib.rs:1:1
586
+ 1: core::panicking::panic_fmt
587
+ at src/panicking.rs:50:5
588
+ 2: myapp::process
589
+ at ./src/lib.rs:100:13
590
+ """
591
+
592
+ parsed = ErrorContext.parse_rust_panic(error_text)
593
+
594
+ assert parsed['language'] == 'rust'
595
+ assert parsed['error_type'] == 'panic'
596
+ assert 'Result::unwrap()' in parsed['error_message']
597
+ assert len(parsed['frames']) >= 1
598
+
599
+ # First frame should be from the panic location
600
+ frame1 = parsed['frames'][0]
601
+ assert 'main.rs' in frame1['file']
602
+ assert frame1['line'] == 42
603
+ assert frame1['column'] == 9
604
+
605
+ def test_parse_java_stack(self) -> None:
606
+ """Test Java stack trace parsing."""
607
+ error_text = """
608
+ java.lang.NullPointerException: Cannot invoke method on null object
609
+ at com.example.MyClass.doSomething(MyClass.java:45)
610
+ at com.example.Main.run(Main.java:20)
611
+ at com.example.Main.main(Main.java:10)
612
+ """
613
+
614
+ parsed = ErrorContext.parse_java_stack(error_text)
615
+
616
+ assert parsed['language'] == 'java'
617
+ assert parsed['error_type'] == 'NullPointerException'
618
+ assert 'Cannot invoke' in parsed['error_message']
619
+ assert len(parsed['frames']) == 3
620
+
621
+ frame1 = parsed['frames'][0]
622
+ assert 'MyClass.java' in frame1['file']
623
+ assert frame1['line'] == 45
624
+ assert 'doSomething' in frame1['function']
625
+
626
+ def test_parse_traceback_auto_detects_language(self) -> None:
627
+ """Test that parse_traceback auto-detects language."""
628
+ js_error = "Error: test\n at func (app.js:10:5)"
629
+ parsed = ErrorContext.parse_traceback(js_error)
630
+ assert parsed['language'] == 'javascript'
631
+
632
+ go_error = "panic: test\n\tmain.go:15"
633
+ parsed = ErrorContext.parse_traceback(go_error)
634
+ assert parsed['language'] == 'go'
635
+
636
+ def test_format_for_ai_includes_language(self) -> None:
637
+ """Test that formatted output includes language."""
638
+ error_text = "TypeError: test\n at func (app.js:10:5)"
639
+ formatted = ErrorContext.format_for_ai(error_text)
640
+
641
+ assert 'Language: Javascript' in formatted
642
+ assert 'Error Type: TypeError' in formatted
643
+ assert 'app.js:10:5' in formatted
508
644
 
509
645
 
510
646
  class TestContextGatherer:
File without changes
File without changes