daveloop 1.1.0__tar.gz → 1.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: daveloop
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Self-healing debug agent powered by Claude Code CLI
5
5
  Home-page: https://github.com/davebruzil/DaveLoop
6
6
  Author: Dave Bruzil
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: daveloop
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Self-healing debug agent powered by Claude Code CLI
5
5
  Home-page: https://github.com/davebruzil/DaveLoop
6
6
  Author: Dave Bruzil
@@ -79,70 +79,81 @@ if sys.platform == "win32":
79
79
  # ============================================================================
80
80
  # ASCII Art Banner
81
81
  # ============================================================================
82
- BANNER = f"""
83
- {C.BRIGHT_BLUE}{C.BOLD}
84
- ██████╗ █████╗ ██╗ ██╗███████╗██╗ ██████╗ ██████╗ ██████╗
85
- ██╔══██╗██╔══██╗██║ ██║██╔════╝██║ ██╔═══██╗██╔═══██╗██╔══██╗
86
- ██║ ██║███████║██║ ██║█████╗ ██║ ██║ ██║██║ ██║██████╔╝
87
- ██║ ██║██╔══██║╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║██║ ██║██╔═══╝
88
- ██████╔╝██║ ██║ ╚████╔╝ ███████╗███████╗╚██████╔╝╚██████╔╝██║
89
- ╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝
90
- {C.RESET}
91
- {C.BRIGHT_WHITE}{C.BOLD} Self-Healing Debug Agent{C.RESET}
92
- {C.WHITE} Powered by Claude Code - Autonomous Mode{C.RESET}
93
- """
82
+ BANNER = f"""{C.BRIGHT_BLUE} ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄{C.RESET}
83
+
84
+ {C.BRIGHT_BLUE}{C.BOLD} ██████╗ █████╗ ██╗ ██╗███████╗██╗ ██████╗ ██████╗ ██████╗
85
+ ██╔══██╗██╔══██╗██║ ██║██╔════╝██║ ██╔═══██╗██╔═══██╗██╔══██╗
86
+ ██║ ██║███████║██║ ██║█████╗ ██║ ██║ ██║██║ ██║██████╔╝
87
+ ██║ ██║██╔══██║╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║██║ ██║██╔═══╝
88
+ ██████╔╝██║ ██║ ╚████╔╝ ███████╗███████╗╚██████╔╝╚██████╔╝██║
89
+ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝{C.RESET}
90
+
91
+ {C.BRIGHT_BLUE} · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄ · ✦ · ❄{C.RESET}
92
+
93
+ {C.BRIGHT_WHITE}{C.BOLD} Self-Healing Debug Agent{C.RESET}
94
+ {C.DIM} Powered by Claude Code · Autonomous{C.RESET}"""
94
95
 
95
96
  # ============================================================================
96
97
  # UI Components
97
98
  # ============================================================================
98
99
  def print_header_box(title: str, color: str = C.BRIGHT_BLUE):
99
100
  """Print a header."""
100
- print(f"\n{color}{C.BOLD}{title}{C.RESET}")
101
- print(f"{color}{'─'*len(title)}{C.RESET}\n")
101
+ print(f"{color}{C.BOLD}┌─ {title} {'─' * (66 - len(title))}┐{C.RESET}")
102
102
 
103
103
  def print_section(title: str, color: str = C.BRIGHT_BLUE):
104
104
  """Print a section divider."""
105
- print(f"\n{color}{C.BOLD}{title}{C.RESET}")
106
- print(f"{color}{'─'*len(title)}{C.RESET}\n")
105
+ print(f"\n{color}{C.BOLD}{title}{C.RESET}")
106
+ print(f"{color}{'─' * 70}{C.RESET}")
107
107
 
108
108
  def print_status(label: str, value: str, color: str = C.WHITE):
109
109
  """Print a status line."""
110
- print(f" {C.WHITE}{label}:{C.RESET} {color}{value}{C.RESET}")
110
+ print(f" {C.BRIGHT_BLUE}{C.RESET} {C.DIM}{label}:{C.RESET} {color}{value}{C.RESET}")
111
111
 
112
112
  def print_iteration_header(iteration: int, max_iter: int):
113
113
  """Print the iteration header with visual progress."""
114
114
  progress = iteration / max_iter
115
- bar_width = 30
115
+ bar_width = 25
116
116
  filled = int(bar_width * progress)
117
- bar = f"{C.BLUE}{'█' * filled}{C.DIM}{'░' * (bar_width - filled)}{C.RESET}"
118
-
119
- iteration_text = f"ITERATION {iteration}/{max_iter}"
120
- percentage_text = f"{int(progress*100)}%"
117
+ empty = bar_width - filled
118
+ bar = '█' * filled + '░' * empty
121
119
 
122
- print(f"\n{C.BOLD}{C.WHITE}{iteration_text}{C.RESET} {bar} {C.BRIGHT_BLUE}{percentage_text}{C.RESET}\n")
120
+ print(f"""
121
+ {C.BRIGHT_BLUE} ──────────────────────────────────────────────────────────────────────{C.RESET}
122
+ {C.BRIGHT_WHITE}{C.BOLD} ITERATION {iteration}/{max_iter}{C.RESET}
123
+ {C.BRIGHT_BLUE} [{bar}] {int(progress*100)}%{C.RESET}
124
+ {C.BRIGHT_BLUE} ──────────────────────────────────────────────────────────────────────{C.RESET}
125
+ """)
123
126
 
124
- def print_success_box(message: str):
127
+ def print_success_box(message: str = ""):
125
128
  """Print an epic success message."""
126
- print(f"\n{C.BRIGHT_GREEN}{C.BOLD}")
127
- print(" ███████╗ ██╗ ██╗ ██████╗ ██████╗ ███████╗ ███████╗ ███████╗")
128
- print(" ██╔════╝ ██║ ██║ ██╔════╝ ██╔════╝ ██╔════╝ ██╔════╝ ██╔════╝")
129
- print(" ███████╗ ██║ ██║ ██║ ██║ █████╗ ███████╗ ███████╗")
130
- print(" ╚════██║ ██║ ██║ ██║ ██║ ██╔══╝ ╚════██║ ╚════██║")
131
- print(" ███████║ ╚██████╔╝ ╚██████╗ ╚██████╗ ███████╗ ███████║ ███████║")
132
- print(" ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚══════╝ ╚══════╝")
133
- print()
134
- print(f" {C.BRIGHT_YELLOW}★ ★ ★{C.RESET}{C.BRIGHT_GREEN}{C.BOLD} {C.BRIGHT_WHITE}BUG SUCCESSFULLY RESOLVED{C.RESET}{C.BRIGHT_GREEN}{C.BOLD} {C.BRIGHT_YELLOW}★ ★ ★{C.RESET}")
135
- print()
136
- print(f" {C.WHITE}{message}{C.RESET}")
137
- print(f"{C.RESET}\n")
129
+ print(f"""
130
+ {C.BRIGHT_GREEN}{C.BOLD} ███████╗██╗ ██╗ ██████╗ ██████╗███████╗███████╗███████╗
131
+ ██╔════╝██║ ██║██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝
132
+ ███████╗██║ ██║██║ ██║ █████╗ ███████╗███████╗
133
+ ╚════██║██║ ██║██║ ██║ ██╔══╝ ╚════██║╚════██║
134
+ ███████║╚██████╔╝╚██████╗╚██████╗███████╗███████║███████║
135
+ ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝╚══════╝╚══════╝╚══════╝{C.RESET}
136
+
137
+ {C.BRIGHT_WHITE}{C.BOLD}BUG SUCCESSFULLY RESOLVED{C.RESET}
138
+ """)
138
139
 
139
140
  def print_error_box(message: str):
140
141
  """Print an error message."""
141
- print(f"\n{C.BRIGHT_RED}{C.BOLD}✗ ERROR: {C.WHITE}{message}{C.RESET}\n")
142
+ print(f"""
143
+ {C.BRIGHT_RED}╭{'─' * 70}╮
144
+ │{C.RESET} {C.BOLD}{C.BRIGHT_RED}✗ ERROR{C.RESET} {C.BRIGHT_RED}│
145
+ │{C.RESET} {C.WHITE}{message[:66]}{C.RESET} {C.BRIGHT_RED}│
146
+ ╰{'─' * 70}╯{C.RESET}
147
+ """)
142
148
 
143
149
  def print_warning_box(message: str):
144
150
  """Print a warning message."""
145
- print(f"\n{C.BRIGHT_YELLOW}{C.BOLD}⚠ WARNING: {C.WHITE}{message}{C.RESET}\n")
151
+ print(f"""
152
+ {C.BRIGHT_YELLOW}╭{'─' * 70}╮
153
+ │{C.RESET} {C.BOLD}{C.BRIGHT_YELLOW}⚠ WARNING{C.RESET} {C.BRIGHT_YELLOW}│
154
+ │{C.RESET} {C.WHITE}{message[:66]}{C.RESET} {C.BRIGHT_YELLOW}│
155
+ ╰{'─' * 70}╯{C.RESET}
156
+ """)
146
157
 
147
158
  # ============================================================================
148
159
  # Spinner Animation
@@ -360,19 +371,8 @@ def run_claude_code(prompt: str, working_dir: str = None, continue_session: bool
360
371
  process.stdin.write(prompt)
361
372
  process.stdin.close()
362
373
 
363
- # Heartbeat thread to show we're alive
374
+ # Track start time
364
375
  start_time = time.time()
365
- heartbeat_active = True
366
-
367
- def heartbeat():
368
- while heartbeat_active:
369
- elapsed = int(time.time() - start_time)
370
- print(f"\r {C.BLUE}[{elapsed}s elapsed...]{C.RESET} ", end='')
371
- sys.stdout.flush()
372
- time.sleep(3)
373
-
374
- heartbeat_thread = threading.Thread(target=heartbeat, daemon=True)
375
- heartbeat_thread.start()
376
376
 
377
377
  # Read and display JSON stream output
378
378
  import json
@@ -380,8 +380,6 @@ def run_claude_code(prompt: str, working_dir: str = None, continue_session: bool
380
380
  full_text = []
381
381
 
382
382
  for line in process.stdout:
383
- # Clear heartbeat line
384
- print(f"\r{' '*40}\r", end='')
385
383
 
386
384
  line = line.strip()
387
385
  if not line:
@@ -391,6 +389,7 @@ def run_claude_code(prompt: str, working_dir: str = None, continue_session: bool
391
389
  data = json.loads(line)
392
390
  msg_type = data.get("type", "")
393
391
 
392
+
394
393
  # Handle different message types
395
394
  if msg_type == "assistant":
396
395
  # Assistant text message
@@ -402,6 +401,43 @@ def run_claude_code(prompt: str, working_dir: str = None, continue_session: bool
402
401
  formatted = format_output_line(line_text)
403
402
  print(formatted)
404
403
  full_text.append(text)
404
+ elif block.get("type") == "tool_use":
405
+ # Tool being called - show what Claude is doing
406
+ tool_name = block.get("name", "unknown")
407
+ tool_input = block.get("input", {})
408
+
409
+ # Format tool call based on type
410
+ if tool_name == "Bash":
411
+ cmd = tool_input.get("command", "")
412
+ cmd_display = cmd[:50] + "..." if len(cmd) > 50 else cmd
413
+ tool_display = f"{C.BRIGHT_BLUE}Bash{C.RESET}({C.WHITE}{cmd_display}{C.RESET})"
414
+ elif tool_name == "Read":
415
+ file_path = tool_input.get("file_path", "")
416
+ filename = file_path.split("\\")[-1].split("/")[-1]
417
+ tool_display = f"{C.BRIGHT_BLUE}Read{C.RESET}({C.WHITE}{filename}{C.RESET})"
418
+ elif tool_name == "Write":
419
+ file_path = tool_input.get("file_path", "")
420
+ filename = file_path.split("\\")[-1].split("/")[-1]
421
+ tool_display = f"{C.BRIGHT_BLUE}Write{C.RESET}({C.WHITE}{filename}{C.RESET})"
422
+ elif tool_name == "Edit":
423
+ file_path = tool_input.get("file_path", "")
424
+ filename = file_path.split("\\")[-1].split("/")[-1]
425
+ tool_display = f"{C.BRIGHT_BLUE}Edit{C.RESET}({C.WHITE}{filename}{C.RESET})"
426
+ elif tool_name == "Grep":
427
+ pattern = tool_input.get("pattern", "")
428
+ pattern_display = pattern[:25] + "..." if len(pattern) > 25 else pattern
429
+ tool_display = f"{C.BRIGHT_BLUE}Grep{C.RESET}({C.WHITE}{pattern_display}{C.RESET})"
430
+ elif tool_name == "Glob":
431
+ pattern = tool_input.get("pattern", "")
432
+ tool_display = f"{C.BRIGHT_BLUE}Glob{C.RESET}({C.WHITE}{pattern}{C.RESET})"
433
+ elif tool_name == "Task":
434
+ desc = tool_input.get("description", "")
435
+ tool_display = f"{C.BRIGHT_BLUE}Task{C.RESET}({C.WHITE}{desc}{C.RESET})"
436
+ else:
437
+ tool_display = f"{C.BRIGHT_BLUE}{tool_name}{C.RESET}"
438
+
439
+ print(f" {C.BRIGHT_BLUE}▶{C.RESET} {tool_display}")
440
+ sys.stdout.flush()
405
441
 
406
442
  elif msg_type == "content_block_delta":
407
443
  # Streaming text delta
@@ -412,13 +448,53 @@ def run_claude_code(prompt: str, working_dir: str = None, continue_session: bool
412
448
  full_text.append(text)
413
449
 
414
450
  elif msg_type == "tool_use":
415
- # Tool being used
451
+ # Tool being used - show what Claude is doing
416
452
  tool_name = data.get("name", "unknown")
417
- print(f"\n {C.BLUE}🔧 Using tool: {tool_name}{C.RESET}")
453
+ tool_input = data.get("input", {})
454
+
455
+ # Format tool call based on type
456
+ if tool_name == "Bash":
457
+ cmd = tool_input.get("command", "")
458
+ cmd_display = cmd[:50] + "..." if len(cmd) > 50 else cmd
459
+ tool_display = f"{C.BRIGHT_BLUE}Bash{C.RESET}({C.WHITE}{cmd_display}{C.RESET})"
460
+ elif tool_name == "Read":
461
+ file_path = tool_input.get("file_path", "")
462
+ filename = file_path.split("\\")[-1].split("/")[-1]
463
+ tool_display = f"{C.BRIGHT_BLUE}Read{C.RESET}({C.WHITE}{filename}{C.RESET})"
464
+ elif tool_name == "Write":
465
+ file_path = tool_input.get("file_path", "")
466
+ filename = file_path.split("\\")[-1].split("/")[-1]
467
+ tool_display = f"{C.BRIGHT_BLUE}Write{C.RESET}({C.WHITE}{filename}{C.RESET})"
468
+ elif tool_name == "Edit":
469
+ file_path = tool_input.get("file_path", "")
470
+ filename = file_path.split("\\")[-1].split("/")[-1]
471
+ tool_display = f"{C.BRIGHT_BLUE}Edit{C.RESET}({C.WHITE}{filename}{C.RESET})"
472
+ elif tool_name == "Grep":
473
+ pattern = tool_input.get("pattern", "")
474
+ pattern_display = pattern[:25] + "..." if len(pattern) > 25 else pattern
475
+ tool_display = f"{C.BRIGHT_BLUE}Grep{C.RESET}({C.WHITE}{pattern_display}{C.RESET})"
476
+ elif tool_name == "Glob":
477
+ pattern = tool_input.get("pattern", "")
478
+ tool_display = f"{C.BRIGHT_BLUE}Glob{C.RESET}({C.WHITE}{pattern}{C.RESET})"
479
+ elif tool_name == "Task":
480
+ desc = tool_input.get("description", "")
481
+ tool_display = f"{C.BRIGHT_BLUE}Task{C.RESET}({C.WHITE}{desc}{C.RESET})"
482
+ else:
483
+ tool_display = f"{C.BRIGHT_BLUE}{tool_name}{C.RESET}"
484
+
485
+ print(f" {C.BRIGHT_BLUE}▶{C.RESET} {tool_display}")
486
+ sys.stdout.flush()
418
487
 
419
488
  elif msg_type == "tool_result":
420
- # Tool result
421
- print(f" {C.BLUE} Tool completed{C.RESET}\n")
489
+ # Tool completed
490
+ print(f" {C.BRIGHT_BLUE}└─{C.RESET} {C.GREEN}✓{C.RESET}")
491
+
492
+ elif msg_type == "user":
493
+ # Tool results come back as user messages
494
+ content = data.get("message", {}).get("content", [])
495
+ for block in content:
496
+ if block.get("type") == "tool_result":
497
+ print(f" {C.BRIGHT_BLUE}└─{C.RESET} {C.GREEN}✓{C.RESET}")
422
498
 
423
499
  elif msg_type == "result":
424
500
  # Final result
@@ -442,9 +518,6 @@ def run_claude_code(prompt: str, working_dir: str = None, continue_session: bool
442
518
 
443
519
  output_lines.append(line)
444
520
 
445
- heartbeat_active = False
446
- print(f"\r{' '*40}\r", end='') # Clear final heartbeat
447
-
448
521
  process.wait(timeout=timeout)
449
522
  return '\n'.join(full_text)
450
523
  else:
@@ -476,36 +549,40 @@ def format_output_line(line: str) -> str:
476
549
  """Format a single line of Claude's output with colors."""
477
550
  # Reasoning markers
478
551
  if "=== DAVELOOP REASONING ===" in line:
479
- return f"\n{C.BRIGHT_BLUE}{'─'*50}\n 🧠 REASONING\n{'─'*50}{C.RESET}"
552
+ return f"""
553
+ {C.BRIGHT_BLUE} ┌─ 🧠 REASONING ─────────────────────────────────────────────────────┐{C.RESET}"""
480
554
  if "===========================" in line:
481
- return f"{C.BRIGHT_BLUE}{'─'*50}{C.RESET}\n"
555
+ return f"{C.BRIGHT_BLUE} └─────────────────────────────────────────────────────────────────────┘{C.RESET}"
482
556
 
483
557
  # Reasoning labels
484
558
  if line.startswith("KNOWN:"):
485
- return f" {C.BLUE}KNOWN:{C.RESET}{C.WHITE}{line[6:]}{C.RESET}"
559
+ return f" {C.BRIGHT_BLUE}│{C.RESET} {C.BRIGHT_BLUE}KNOWN:{C.RESET} {C.WHITE}{line[6:]}{C.RESET}"
486
560
  if line.startswith("UNKNOWN:"):
487
- return f" {C.BLUE}UNKNOWN:{C.RESET}{C.WHITE}{line[8:]}{C.RESET}"
561
+ return f" {C.BRIGHT_BLUE}│{C.RESET} {C.BRIGHT_BLUE}UNKNOWN:{C.RESET} {C.WHITE}{line[8:]}{C.RESET}"
488
562
  if line.startswith("HYPOTHESIS:"):
489
- return f" {C.BLUE}HYPOTHESIS:{C.RESET}{C.WHITE}{line[11:]}{C.RESET}"
563
+ return f" {C.BRIGHT_BLUE}│{C.RESET} {C.BRIGHT_BLUE}HYPOTHESIS:{C.RESET} {C.WHITE}{line[11:]}{C.RESET}"
490
564
  if line.startswith("NEXT ACTION:"):
491
- return f" {C.BLUE}NEXT ACTION:{C.RESET}{C.WHITE}{line[12:]}{C.RESET}"
565
+ return f" {C.BRIGHT_BLUE}│{C.RESET} {C.BRIGHT_BLUE}NEXT:{C.RESET} {C.WHITE}{line[12:]}{C.RESET}"
492
566
  if line.startswith("WHY:"):
493
- return f" {C.BLUE}WHY:{C.RESET}{C.WHITE}{line[4:]}{C.RESET}"
567
+ return f" {C.BRIGHT_BLUE}│{C.RESET} {C.BRIGHT_BLUE}WHY:{C.RESET} {C.WHITE}{line[4:]}{C.RESET}"
494
568
 
495
- # Exit signals - just dim them out in the stream, don't make them prominent
496
- # The actual success/error boxes will be shown after iteration completes
569
+ # Exit signals - hide them, the success/error box will show
497
570
  if "[DAVELOOP:RESOLVED]" in line:
498
- return f" {C.DIM}→ [Exit signal detected: RESOLVED]{C.RESET}"
571
+ return ""
499
572
  if "[DAVELOOP:BLOCKED]" in line:
500
- return f" {C.DIM}→ [Exit signal detected: BLOCKED]{C.RESET}"
573
+ return ""
501
574
  if "[DAVELOOP:CLARIFY]" in line:
502
- return f" {C.DIM}→ [Exit signal detected: CLARIFY]{C.RESET}"
575
+ return ""
503
576
 
504
- # Code blocks
577
+ # Code blocks - hide the markers
505
578
  if line.strip().startswith("```"):
506
- return f"{C.BLUE}{'─'*40}{C.RESET}"
579
+ return ""
580
+
581
+ # Empty lines - minimal spacing
582
+ if not line.strip():
583
+ return ""
507
584
 
508
- # Default - white text
585
+ # Default - white text with subtle indent
509
586
  return f" {C.WHITE}{line}{C.RESET}"
510
587
 
511
588
 
@@ -573,20 +650,18 @@ def main():
573
650
 
574
651
  # Session info
575
652
  print_header_box(f"SESSION: {session_id}", C.BRIGHT_BLUE)
576
- print_status("Working Directory", working_dir, C.WHITE)
577
- print_status("Max Iterations", str(args.max_iterations), C.WHITE)
578
- print_status("Timeout", f"{args.timeout // 60} min ({args.timeout}s) per iteration", C.WHITE)
579
- print_status("Context Mode", "PERSISTENT (--continue)", C.WHITE)
580
- print_status("System Prompt", f"{len(system_prompt)} chars loaded", C.WHITE)
581
- print()
653
+ print_status("Directory", working_dir, C.WHITE)
654
+ print_status("Iterations", str(args.max_iterations), C.WHITE)
655
+ print_status("Timeout", f"{args.timeout // 60}m per iteration", C.WHITE)
656
+ print_status("Mode", "Autonomous", C.WHITE)
657
+ print(f"{C.BRIGHT_BLUE}└{'─' * 70}┘{C.RESET}")
582
658
 
583
659
  print_section("BUG REPORT", C.BRIGHT_RED)
584
660
  # Wrap bug input nicely
585
- for line in bug_input.split('\n')[:10]:
586
- print(f" {C.RED}{line[:80]}{C.RESET}")
587
- if len(bug_input.split('\n')) > 10:
588
- print(f" {C.RED}... ({len(bug_input.split(chr(10))) - 10} more lines){C.RESET}")
589
- print()
661
+ for line in bug_input.split('\n')[:8]:
662
+ print(f" {C.BRIGHT_RED}{line[:70]}{C.RESET}")
663
+ if len(bug_input.split('\n')) > 8:
664
+ print(f" {C.RED}... +{len(bug_input.split(chr(10))) - 8} more lines{C.RESET}")
590
665
 
591
666
  sys.stdout.flush()
592
667
 
@@ -605,7 +680,6 @@ Then fix it. Use the reasoning protocol before each action.
605
680
  iteration_history = []
606
681
 
607
682
  for iteration in range(1, args.max_iterations + 1):
608
- print_iteration_header(iteration, args.max_iterations)
609
683
 
610
684
  if iteration == 1:
611
685
  full_prompt = f"{system_prompt}\n\n---\n\n{context}"
@@ -618,13 +692,13 @@ Then fix it. Use the reasoning protocol before each action.
618
692
  print(f" {C.DIM}[DEBUG] Prompt: {len(full_prompt)} chars, continue={continue_session}{C.RESET}")
619
693
 
620
694
  # Show "Claude is working" indicator
621
- print(f"\n {C.BRIGHT_BLUE} Claude is working...{C.RESET}\n")
695
+ print(f"\n {C.BRIGHT_BLUE} Agent active...{C.RESET}\n")
622
696
  sys.stdout.flush()
623
697
 
624
698
  # Run Claude with real-time streaming output
625
699
  output = run_claude_code(full_prompt, working_dir, continue_session=continue_session, stream=True, timeout=args.timeout)
626
700
 
627
- print(f"\n {C.BLUE} Iteration complete{C.RESET}\n")
701
+ print(f"\n{C.BRIGHT_BLUE} {'─' * 70}{C.RESET}")
628
702
 
629
703
  # Save log
630
704
  save_log(iteration, output, session_id)
@@ -635,10 +709,9 @@ Then fix it. Use the reasoning protocol before each action.
635
709
 
636
710
  if should_exit:
637
711
  if signal == "RESOLVED":
638
- print_success_box(f"Bug fixed in {iteration} iteration(s)!")
639
- print_status("Session", session_id, C.WHITE)
640
- print_status("Logs", str(LOG_DIR), C.WHITE)
641
- print()
712
+ print_success_box("")
713
+ print(f" {C.DIM}Session: {session_id}{C.RESET}")
714
+ print(f" {C.DIM}Logs: {LOG_DIR}{C.RESET}\n")
642
715
  return 0
643
716
  elif signal == "CLARIFY":
644
717
  print_warning_box("Claude needs clarification")
@@ -13,7 +13,7 @@ long_description = readme_file.read_text(encoding="utf-8") if readme_file.exists
13
13
 
14
14
  setup(
15
15
  name="daveloop",
16
- version="1.1.0",
16
+ version="1.2.0",
17
17
  description="Self-healing debug agent powered by Claude Code CLI",
18
18
  long_description=long_description,
19
19
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes
File without changes
File without changes