claude-dev-cli 0.6.0__py3-none-any.whl → 0.8.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.

Potentially problematic release.


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

@@ -9,7 +9,7 @@ Features:
9
9
  - Interactive and single-shot modes
10
10
  """
11
11
 
12
- __version__ = "0.6.0"
12
+ __version__ = "0.8.0"
13
13
  __author__ = "Julio"
14
14
  __license__ = "MIT"
15
15
 
claude_dev_cli/cli.py CHANGED
@@ -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")
@@ -447,12 +460,14 @@ def generate() -> None:
447
460
  @click.argument('file_path', type=click.Path(exists=True))
448
461
  @click.option('-o', '--output', type=click.Path(), help='Output file path')
449
462
  @click.option('-a', '--api', help='API config to use')
463
+ @click.option('-i', '--interactive', is_flag=True, help='Interactive refinement mode')
450
464
  @click.pass_context
451
465
  def gen_tests(
452
466
  ctx: click.Context,
453
467
  file_path: str,
454
468
  output: Optional[str],
455
- api: Optional[str]
469
+ api: Optional[str],
470
+ interactive: bool
456
471
  ) -> None:
457
472
  """Generate pytest tests for a Python file."""
458
473
  console = ctx.obj['console']
@@ -461,11 +476,48 @@ def gen_tests(
461
476
  with console.status("[bold blue]Generating tests..."):
462
477
  result = generate_tests(file_path, api_config_name=api)
463
478
 
479
+ if interactive:
480
+ # Show initial result
481
+ console.print("\n[bold]Initial Tests:[/bold]\n")
482
+ console.print(result)
483
+
484
+ # Interactive refinement loop
485
+ client = ClaudeClient(api_config_name=api)
486
+ conversation_context = [result]
487
+
488
+ while True:
489
+ console.print("\n[dim]Commands: 'save' to save and exit, 'exit' to discard, or ask for changes[/dim]")
490
+ user_input = console.input("[cyan]You:[/cyan] ").strip()
491
+
492
+ if user_input.lower() == 'exit':
493
+ console.print("[yellow]Discarded changes[/yellow]")
494
+ return
495
+
496
+ if user_input.lower() == 'save':
497
+ result = conversation_context[-1]
498
+ break
499
+
500
+ if not user_input:
501
+ continue
502
+
503
+ # Get refinement
504
+ refinement_prompt = f"Previous tests:\n\n{conversation_context[-1]}\n\nUser request: {user_input}\n\nProvide the updated tests."
505
+
506
+ console.print("\n[bold green]Claude:[/bold green] ", end='')
507
+ response_parts = []
508
+ for chunk in client.call_streaming(refinement_prompt):
509
+ console.print(chunk, end='')
510
+ response_parts.append(chunk)
511
+ console.print()
512
+
513
+ result = ''.join(response_parts)
514
+ conversation_context.append(result)
515
+
464
516
  if output:
465
517
  with open(output, 'w') as f:
466
518
  f.write(result)
467
- console.print(f"[green]✓[/green] Tests saved to: {output}")
468
- else:
519
+ console.print(f"\n[green]✓[/green] Tests saved to: {output}")
520
+ elif not interactive:
469
521
  console.print(result)
470
522
 
471
523
  except Exception as e:
@@ -477,12 +529,14 @@ def gen_tests(
477
529
  @click.argument('file_path', type=click.Path(exists=True))
478
530
  @click.option('-o', '--output', type=click.Path(), help='Output file path')
479
531
  @click.option('-a', '--api', help='API config to use')
532
+ @click.option('-i', '--interactive', is_flag=True, help='Interactive refinement mode')
480
533
  @click.pass_context
481
534
  def gen_docs(
482
535
  ctx: click.Context,
483
536
  file_path: str,
484
537
  output: Optional[str],
485
- api: Optional[str]
538
+ api: Optional[str],
539
+ interactive: bool
486
540
  ) -> None:
487
541
  """Generate documentation for a Python file."""
488
542
  console = ctx.obj['console']
@@ -491,11 +545,46 @@ def gen_docs(
491
545
  with console.status("[bold blue]Generating documentation..."):
492
546
  result = generate_docs(file_path, api_config_name=api)
493
547
 
548
+ if interactive:
549
+ console.print("\n[bold]Initial Documentation:[/bold]\n")
550
+ md = Markdown(result)
551
+ console.print(md)
552
+
553
+ client = ClaudeClient(api_config_name=api)
554
+ conversation_context = [result]
555
+
556
+ while True:
557
+ console.print("\n[dim]Commands: 'save' to save and exit, 'exit' to discard, or ask for changes[/dim]")
558
+ user_input = console.input("[cyan]You:[/cyan] ").strip()
559
+
560
+ if user_input.lower() == 'exit':
561
+ console.print("[yellow]Discarded changes[/yellow]")
562
+ return
563
+
564
+ if user_input.lower() == 'save':
565
+ result = conversation_context[-1]
566
+ break
567
+
568
+ if not user_input:
569
+ continue
570
+
571
+ refinement_prompt = f"Previous documentation:\n\n{conversation_context[-1]}\n\nUser request: {user_input}\n\nProvide the updated documentation."
572
+
573
+ console.print("\n[bold green]Claude:[/bold green] ", end='')
574
+ response_parts = []
575
+ for chunk in client.call_streaming(refinement_prompt):
576
+ console.print(chunk, end='')
577
+ response_parts.append(chunk)
578
+ console.print()
579
+
580
+ result = ''.join(response_parts)
581
+ conversation_context.append(result)
582
+
494
583
  if output:
495
584
  with open(output, 'w') as f:
496
585
  f.write(result)
497
- console.print(f"[green]✓[/green] Documentation saved to: {output}")
498
- else:
586
+ console.print(f"\n[green]✓[/green] Documentation saved to: {output}")
587
+ elif not interactive:
499
588
  md = Markdown(result)
500
589
  console.print(md)
501
590
 
@@ -507,21 +596,69 @@ def gen_docs(
507
596
  @main.command('review')
508
597
  @click.argument('file_path', type=click.Path(exists=True))
509
598
  @click.option('-a', '--api', help='API config to use')
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')
510
601
  @click.pass_context
511
602
  def review(
512
603
  ctx: click.Context,
513
604
  file_path: str,
514
- api: Optional[str]
605
+ api: Optional[str],
606
+ interactive: bool,
607
+ auto_context: bool
515
608
  ) -> None:
516
609
  """Review code for bugs and improvements."""
517
610
  console = ctx.obj['console']
518
611
 
519
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
+
520
625
  with console.status("[bold blue]Reviewing code..."):
521
- 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)
522
636
 
523
637
  md = Markdown(result)
524
638
  console.print(md)
639
+
640
+ if interactive:
641
+ client = ClaudeClient(api_config_name=api)
642
+ with open(file_path, 'r') as f:
643
+ file_content = f.read()
644
+
645
+ console.print("\n[dim]Ask follow-up questions about the review, or 'exit' to quit[/dim]")
646
+
647
+ while True:
648
+ user_input = console.input("\n[cyan]You:[/cyan] ").strip()
649
+
650
+ if user_input.lower() == 'exit':
651
+ break
652
+
653
+ if not user_input:
654
+ continue
655
+
656
+ follow_up_prompt = f"Code review:\n\n{result}\n\nOriginal code:\n\n{file_content}\n\nUser question: {user_input}"
657
+
658
+ console.print("\n[bold green]Claude:[/bold green] ", end='')
659
+ for chunk in client.call_streaming(follow_up_prompt):
660
+ console.print(chunk, end='')
661
+ console.print()
525
662
 
526
663
  except Exception as e:
527
664
  console.print(f"[red]Error: {e}[/red]")
@@ -532,12 +669,14 @@ def review(
532
669
  @click.option('-f', '--file', type=click.Path(exists=True), help='File to debug')
533
670
  @click.option('-e', '--error', help='Error message to analyze')
534
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')
535
673
  @click.pass_context
536
674
  def debug(
537
675
  ctx: click.Context,
538
676
  file: Optional[str],
539
677
  error: Optional[str],
540
- api: Optional[str]
678
+ api: Optional[str],
679
+ auto_context: bool
541
680
  ) -> None:
542
681
  """Debug code and analyze errors."""
543
682
  console = ctx.obj['console']
@@ -547,13 +686,33 @@ def debug(
547
686
  if not sys.stdin.isatty():
548
687
  stdin_content = sys.stdin.read().strip()
549
688
 
689
+ error_text = error or stdin_content
690
+
550
691
  try:
551
- with console.status("[bold blue]Analyzing error..."):
552
- result = debug_code(
553
- file_path=file,
554
- error_message=error or stdin_content,
555
- api_config_name=api
556
- )
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
+ )
557
716
 
558
717
  md = Markdown(result)
559
718
  console.print(md)
@@ -567,25 +726,80 @@ def debug(
567
726
  @click.argument('file_path', type=click.Path(exists=True))
568
727
  @click.option('-o', '--output', type=click.Path(), help='Output file path')
569
728
  @click.option('-a', '--api', help='API config to use')
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')
570
731
  @click.pass_context
571
732
  def refactor(
572
733
  ctx: click.Context,
573
734
  file_path: str,
574
735
  output: Optional[str],
575
- api: Optional[str]
736
+ api: Optional[str],
737
+ interactive: bool,
738
+ auto_context: bool
576
739
  ) -> None:
577
740
  """Suggest refactoring improvements."""
578
741
  console = ctx.obj['console']
579
742
 
580
743
  try:
581
- with console.status("[bold blue]Analyzing code..."):
582
- 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)
762
+
763
+ if interactive:
764
+ console.print("\n[bold]Initial Refactoring:[/bold]\n")
765
+ md = Markdown(result)
766
+ console.print(md)
767
+
768
+ client = ClaudeClient(api_config_name=api)
769
+ conversation_context = [result]
770
+
771
+ while True:
772
+ console.print("\n[dim]Commands: 'save' to save and exit, 'exit' to discard, or ask for changes[/dim]")
773
+ user_input = console.input("[cyan]You:[/cyan] ").strip()
774
+
775
+ if user_input.lower() == 'exit':
776
+ console.print("[yellow]Discarded changes[/yellow]")
777
+ return
778
+
779
+ if user_input.lower() == 'save':
780
+ result = conversation_context[-1]
781
+ break
782
+
783
+ if not user_input:
784
+ continue
785
+
786
+ refinement_prompt = f"Previous refactoring:\n\n{conversation_context[-1]}\n\nUser request: {user_input}\n\nProvide the updated refactoring suggestions."
787
+
788
+ console.print("\n[bold green]Claude:[/bold green] ", end='')
789
+ response_parts = []
790
+ for chunk in client.call_streaming(refinement_prompt):
791
+ console.print(chunk, end='')
792
+ response_parts.append(chunk)
793
+ console.print()
794
+
795
+ result = ''.join(response_parts)
796
+ conversation_context.append(result)
583
797
 
584
798
  if output:
585
799
  with open(output, 'w') as f:
586
800
  f.write(result)
587
- console.print(f"[green]✓[/green] Refactored code saved to: {output}")
588
- else:
801
+ console.print(f"\n[green]✓[/green] Refactored code saved to: {output}")
802
+ elif not interactive:
589
803
  md = Markdown(result)
590
804
  console.print(md)
591
805
 
@@ -957,5 +1171,221 @@ def template_use(ctx: click.Context, name: str, api: Optional[str], model: Optio
957
1171
  sys.exit(1)
958
1172
 
959
1173
 
1174
+ @main.group()
1175
+ def warp() -> None:
1176
+ """Warp terminal integration."""
1177
+ pass
1178
+
1179
+
1180
+ @warp.command('export-workflows')
1181
+ @click.option('-o', '--output', type=click.Path(), help='Output directory')
1182
+ @click.pass_context
1183
+ def warp_export_workflows(ctx: click.Context, output: Optional[str]) -> None:
1184
+ """Export Warp workflows for claude-dev-cli commands."""
1185
+ console = ctx.obj['console']
1186
+
1187
+ try:
1188
+ from claude_dev_cli.warp_integration import export_builtin_workflows
1189
+
1190
+ config = Config()
1191
+ output_dir = Path(output) if output else config.config_dir / "warp" / "workflows"
1192
+
1193
+ created_files = export_builtin_workflows(output_dir)
1194
+
1195
+ console.print(f"[green]✓[/green] Exported {len(created_files)} Warp workflows to:")
1196
+ console.print(f" {output_dir}")
1197
+ console.print("\n[bold]Workflows:[/bold]")
1198
+ for file in created_files:
1199
+ console.print(f" • {file.name}")
1200
+
1201
+ except Exception as e:
1202
+ console.print(f"[red]Error: {e}[/red]")
1203
+ sys.exit(1)
1204
+
1205
+
1206
+ @warp.command('export-launch-configs')
1207
+ @click.option('-o', '--output', type=click.Path(), help='Output file path')
1208
+ @click.pass_context
1209
+ def warp_export_launch_configs(ctx: click.Context, output: Optional[str]) -> None:
1210
+ """Export Warp launch configurations."""
1211
+ console = ctx.obj['console']
1212
+
1213
+ try:
1214
+ from claude_dev_cli.warp_integration import export_launch_configs
1215
+
1216
+ config = Config()
1217
+ output_path = Path(output) if output else config.config_dir / "warp" / "launch_configs.json"
1218
+
1219
+ export_launch_configs(output_path)
1220
+
1221
+ console.print(f"[green]✓[/green] Exported Warp launch configurations to:")
1222
+ console.print(f" {output_path}")
1223
+
1224
+ except Exception as e:
1225
+ console.print(f"[red]Error: {e}[/red]")
1226
+ sys.exit(1)
1227
+
1228
+
1229
+ @main.group()
1230
+ def workflow() -> None:
1231
+ """Manage and run workflows."""
1232
+ pass
1233
+
1234
+
1235
+ @workflow.command('run')
1236
+ @click.argument('workflow_file', type=click.Path(exists=True))
1237
+ @click.option('--var', '-v', multiple=True, help='Set variables (key=value)')
1238
+ @click.pass_context
1239
+ def workflow_run(
1240
+ ctx: click.Context,
1241
+ workflow_file: str,
1242
+ var: tuple
1243
+ ) -> None:
1244
+ """Run a workflow from YAML file."""
1245
+ console = ctx.obj['console']
1246
+
1247
+ # Parse variables
1248
+ variables = {}
1249
+ for v in var:
1250
+ if '=' in v:
1251
+ key, value = v.split('=', 1)
1252
+ variables[key] = value
1253
+
1254
+ try:
1255
+ from claude_dev_cli.workflows import WorkflowEngine
1256
+
1257
+ engine = WorkflowEngine(console=console)
1258
+ workflow_path = Path(workflow_file)
1259
+
1260
+ context = engine.execute(workflow_path, initial_vars=variables)
1261
+
1262
+ # Show summary
1263
+ if context.step_results:
1264
+ console.print("\n[bold]Results Summary:[/bold]")
1265
+ for step_name, result in context.step_results.items():
1266
+ status = "[green]✓[/green]" if result.success else "[red]✗[/red]"
1267
+ console.print(f"{status} {step_name}")
1268
+
1269
+ except Exception as e:
1270
+ console.print(f"[red]Error: {e}[/red]")
1271
+ sys.exit(1)
1272
+
1273
+
1274
+ @workflow.command('list')
1275
+ @click.pass_context
1276
+ def workflow_list(ctx: click.Context) -> None:
1277
+ """List available workflows."""
1278
+ console = ctx.obj['console']
1279
+ config = Config()
1280
+ workflow_dir = config.config_dir / "workflows"
1281
+
1282
+ from claude_dev_cli.workflows import list_workflows
1283
+ workflows = list_workflows(workflow_dir)
1284
+
1285
+ if not workflows:
1286
+ console.print("[yellow]No workflows found.[/yellow]")
1287
+ console.print(f"\nCreate workflows in: {workflow_dir}")
1288
+ return
1289
+
1290
+ from rich.table import Table
1291
+
1292
+ table = Table(show_header=True, header_style="bold magenta")
1293
+ table.add_column("Name", style="cyan")
1294
+ table.add_column("Steps", style="yellow")
1295
+ table.add_column("Description")
1296
+
1297
+ for wf in workflows:
1298
+ table.add_row(
1299
+ wf['name'],
1300
+ str(wf['steps']),
1301
+ wf['description']
1302
+ )
1303
+
1304
+ console.print(table)
1305
+ console.print(f"\n[dim]Workflow directory: {workflow_dir}[/dim]")
1306
+
1307
+
1308
+ @workflow.command('show')
1309
+ @click.argument('workflow_file', type=click.Path(exists=True))
1310
+ @click.pass_context
1311
+ def workflow_show(ctx: click.Context, workflow_file: str) -> None:
1312
+ """Show workflow details."""
1313
+ console = ctx.obj['console']
1314
+
1315
+ try:
1316
+ from claude_dev_cli.workflows import WorkflowEngine
1317
+
1318
+ engine = WorkflowEngine(console=console)
1319
+ workflow = engine.load_workflow(Path(workflow_file))
1320
+
1321
+ console.print(Panel(
1322
+ f"[bold]{workflow.get('name', 'Unnamed')}[/bold]\n\n"
1323
+ f"[dim]{workflow.get('description', 'No description')}[/dim]\n\n"
1324
+ f"Steps: [yellow]{len(workflow.get('steps', []))}[/yellow]",
1325
+ title="Workflow Info",
1326
+ border_style="blue"
1327
+ ))
1328
+
1329
+ # Show steps
1330
+ steps = workflow.get('steps', [])
1331
+ if steps:
1332
+ console.print("\n[bold]Steps:[/bold]\n")
1333
+ for i, step in enumerate(steps, 1):
1334
+ step_name = step.get('name', f'step-{i}')
1335
+ step_type = 'command' if 'command' in step else 'shell' if 'shell' in step else 'set'
1336
+ console.print(f" {i}. [cyan]{step_name}[/cyan] ({step_type})")
1337
+
1338
+ if step.get('approval_required'):
1339
+ console.print(f" [yellow]⚠ Requires approval[/yellow]")
1340
+ if 'if' in step:
1341
+ console.print(f" [dim]Condition: {step['if']}[/dim]")
1342
+
1343
+ except Exception as e:
1344
+ console.print(f"[red]Error: {e}[/red]")
1345
+ sys.exit(1)
1346
+
1347
+
1348
+ @workflow.command('validate')
1349
+ @click.argument('workflow_file', type=click.Path(exists=True))
1350
+ @click.pass_context
1351
+ def workflow_validate(ctx: click.Context, workflow_file: str) -> None:
1352
+ """Validate workflow syntax."""
1353
+ console = ctx.obj['console']
1354
+
1355
+ try:
1356
+ from claude_dev_cli.workflows import WorkflowEngine
1357
+
1358
+ engine = WorkflowEngine(console=console)
1359
+ workflow = engine.load_workflow(Path(workflow_file))
1360
+
1361
+ # Basic validation
1362
+ errors = []
1363
+
1364
+ if 'name' not in workflow:
1365
+ errors.append("Missing 'name' field")
1366
+
1367
+ if 'steps' not in workflow:
1368
+ errors.append("Missing 'steps' field")
1369
+ elif not isinstance(workflow['steps'], list):
1370
+ errors.append("'steps' must be a list")
1371
+ else:
1372
+ for i, step in enumerate(workflow['steps'], 1):
1373
+ if not any(k in step for k in ['command', 'shell', 'set']):
1374
+ errors.append(f"Step {i}: Must have 'command', 'shell', or 'set'")
1375
+
1376
+ if errors:
1377
+ console.print("[red]✗ Validation failed:[/red]\n")
1378
+ for error in errors:
1379
+ console.print(f" • {error}")
1380
+ sys.exit(1)
1381
+ else:
1382
+ console.print(f"[green]✓[/green] Workflow is valid: {workflow.get('name')}")
1383
+ console.print(f" Steps: {len(workflow.get('steps', []))}")
1384
+
1385
+ except Exception as e:
1386
+ console.print(f"[red]Error: {e}[/red]")
1387
+ sys.exit(1)
1388
+
1389
+
960
1390
  if __name__ == '__main__':
961
1391
  main(obj={})
claude_dev_cli/config.py CHANGED
@@ -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: