portacode 0.3.19.dev4__tar.gz → 0.3.19.dev5__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.
Files changed (45) hide show
  1. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/PKG-INFO +1 -1
  2. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/_version.py +2 -2
  3. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/project_state_handlers.py +96 -66
  4. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode.egg-info/PKG-INFO +1 -1
  5. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/restore.sh +0 -2
  6. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/.claude/agents/communication-manager.md +0 -0
  7. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/.claude/settings.local.json +0 -0
  8. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/.gitignore +0 -0
  9. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/.gitmodules +0 -0
  10. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/LICENSE +0 -0
  11. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/MANIFEST.in +0 -0
  12. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/Makefile +0 -0
  13. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/README.md +0 -0
  14. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/backup.sh +0 -0
  15. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/docker-compose.yaml +0 -0
  16. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/README.md +0 -0
  17. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/__init__.py +0 -0
  18. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/__main__.py +0 -0
  19. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/cli.py +0 -0
  20. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/README.md +0 -0
  21. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/__init__.py +0 -0
  22. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/client.py +0 -0
  23. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/README.md +0 -0
  24. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
  25. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/__init__.py +0 -0
  26. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/base.py +0 -0
  27. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/file_handlers.py +0 -0
  28. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/registry.py +0 -0
  29. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/session.py +0 -0
  30. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/system_handlers.py +0 -0
  31. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/tab_factory.py +0 -0
  32. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/handlers/terminal_handlers.py +0 -0
  33. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/multiplex.py +0 -0
  34. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/connection/terminal.py +0 -0
  35. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/data.py +0 -0
  36. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/keypair.py +0 -0
  37. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode/service.py +0 -0
  38. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode.egg-info/SOURCES.txt +0 -0
  39. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode.egg-info/dependency_links.txt +0 -0
  40. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode.egg-info/entry_points.txt +0 -0
  41. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode.egg-info/requires.txt +0 -0
  42. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/portacode.egg-info/top_level.txt +0 -0
  43. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/pyproject.toml +0 -0
  44. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/setup.cfg +0 -0
  45. {portacode-0.3.19.dev4 → portacode-0.3.19.dev5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: portacode
3
- Version: 0.3.19.dev4
3
+ Version: 0.3.19.dev5
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.3.19.dev4'
21
- __version_tuple__ = version_tuple = (0, 3, 19, 'dev4')
20
+ __version__ = version = '0.3.19.dev5'
21
+ __version_tuple__ = version_tuple = (0, 3, 19, 'dev5')
@@ -400,8 +400,8 @@ class GitManager:
400
400
  logger.debug("Error getting Pygments lexer: %s", e)
401
401
  return None
402
402
 
403
- def _generate_html_diff(self, original_content: str, modified_content: str, file_path: str) -> Optional[str]:
404
- """Generate unified HTML diff with intra-line highlighting using GitPython and diff-match-patch."""
403
+ def _generate_html_diff(self, original_content: str, modified_content: str, file_path: str) -> Optional[Dict[str, str]]:
404
+ """Generate unified HTML diff with intra-line highlighting. Returns both minimal and full context versions."""
405
405
  if not PYGMENTS_AVAILABLE:
406
406
  logger.debug("Pygments not available for HTML diff generation")
407
407
  return None
@@ -413,85 +413,115 @@ class GitManager:
413
413
  original_lines = original_content.splitlines(keepends=True)
414
414
  modified_lines = modified_content.splitlines(keepends=True)
415
415
 
416
- # Generate unified diff
417
- diff_lines = list(difflib.unified_diff(
416
+ # Generate both minimal (3 lines context) and full context diffs
417
+ minimal_diff_lines = list(difflib.unified_diff(
418
418
  original_lines,
419
419
  modified_lines,
420
420
  fromfile='a/' + os.path.basename(file_path),
421
421
  tofile='b/' + os.path.basename(file_path),
422
- lineterm=''
422
+ lineterm='',
423
+ n=3 # 3 lines of context (default)
423
424
  ))
424
425
 
425
- # Parse the unified diff and add intra-line highlighting
426
- parsed_diff = self._parse_unified_diff_with_intraline(diff_lines, original_lines, modified_lines)
426
+ full_diff_lines = list(difflib.unified_diff(
427
+ original_lines,
428
+ modified_lines,
429
+ fromfile='a/' + os.path.basename(file_path),
430
+ tofile='b/' + os.path.basename(file_path),
431
+ lineterm='',
432
+ n=len(original_lines) + len(modified_lines) # Show all lines
433
+ ))
427
434
 
428
- # Get Pygments lexer for syntax highlighting
429
- lexer = self._get_pygments_lexer(file_path)
435
+ # Parse both diffs
436
+ minimal_parsed = self._parse_unified_diff_with_intraline(minimal_diff_lines, original_lines, modified_lines)
437
+ full_parsed = self._parse_unified_diff_with_intraline(full_diff_lines, original_lines, modified_lines)
430
438
 
431
- # Build HTML
432
- html_parts = []
433
- html_parts.append('<div class="unified-diff-container">')
439
+ # Generate HTML for both versions
440
+ minimal_html = self._generate_diff_html(minimal_parsed, file_path, 'minimal')
441
+ full_html = self._generate_diff_html(full_parsed, file_path, 'full')
434
442
 
435
- # Add stats header
436
- line_additions = sum(1 for line in parsed_diff if line['type'] == 'add')
437
- line_deletions = sum(1 for line in parsed_diff if line['type'] == 'delete')
443
+ return {
444
+ 'minimal': minimal_html,
445
+ 'full': full_html
446
+ }
438
447
 
439
- html_parts.append(f'''
440
- <div class="diff-stats">
448
+ except Exception as e:
449
+ logger.error("Error generating HTML diff: %s", e)
450
+ return None
451
+
452
+ def _generate_diff_html(self, parsed_diff: List[Dict], file_path: str, view_mode: str) -> str:
453
+ """Generate HTML for a parsed diff."""
454
+ # Get Pygments lexer for syntax highlighting
455
+ lexer = self._get_pygments_lexer(file_path)
456
+
457
+ # Build HTML
458
+ html_parts = []
459
+ html_parts.append(f'<div class="unified-diff-container" data-view-mode="{view_mode}">')
460
+
461
+ # Add stats header with toggle
462
+ line_additions = sum(1 for line in parsed_diff if line['type'] == 'add')
463
+ line_deletions = sum(1 for line in parsed_diff if line['type'] == 'delete')
464
+
465
+ html_parts.append(f'''
466
+ <div class="diff-stats">
467
+ <div class="diff-stats-left">
441
468
  <span class="additions">+{line_additions}</span>
442
469
  <span class="deletions">-{line_deletions}</span>
443
470
  <span class="file-path">{os.path.basename(file_path)}</span>
444
471
  </div>
445
- ''')
446
-
447
- # Generate unified diff view
448
- html_parts.append('<div class="diff-content">')
449
- html_parts.append('<table class="diff-table">')
450
-
451
- for line_info in parsed_diff:
452
- if line_info['type'] == 'header':
453
- continue # Skip diff headers
454
-
455
- line_type = line_info['type']
456
- old_line_num = line_info.get('old_line_num', '')
457
- new_line_num = line_info.get('new_line_num', '')
458
- content = line_info['content']
459
- intraline_html = line_info.get('intraline_html', '')
472
+ <div class="diff-stats-right">
473
+ <button class="diff-toggle-btn" data-current-mode="{view_mode}">
474
+ <i class="fas fa-eye"></i>
475
+ <span class="toggle-text">{''}</span>
476
+ </button>
477
+ </div>
478
+ </div>
479
+ ''')
480
+
481
+ # Generate unified diff view
482
+ html_parts.append('<div class="diff-content">')
483
+ html_parts.append('<table class="diff-table">')
484
+
485
+ for line_info in parsed_diff:
486
+ if line_info['type'] == 'header':
487
+ continue # Skip diff headers
460
488
 
461
- # Use intra-line highlighted content if available, otherwise apply syntax highlighting
462
- if intraline_html:
463
- final_content = intraline_html
464
- elif lexer and content.strip():
465
- try:
466
- # Apply syntax highlighting to the content (without the +/- prefix)
467
- clean_content = content[1:] if content and content[0] in '+-' else content
468
- highlighted = highlight(clean_content, lexer, HtmlFormatter(nowrap=True, noclasses=False))
469
- final_content = content[0] + highlighted if content and content[0] in '+-' else highlighted
470
- except Exception:
471
- final_content = self._escape_html(content)
472
- else:
489
+ line_type = line_info['type']
490
+ old_line_num = line_info.get('old_line_num', '')
491
+ new_line_num = line_info.get('new_line_num', '')
492
+ content = line_info['content']
493
+ intraline_html = line_info.get('intraline_html', '')
494
+
495
+ # Use intra-line highlighted content if available, otherwise apply syntax highlighting
496
+ if intraline_html:
497
+ final_content = intraline_html
498
+ elif lexer and content.strip():
499
+ try:
500
+ # Apply syntax highlighting to the content (without the +/- prefix)
501
+ clean_content = content[1:] if content and content[0] in '+-' else content
502
+ highlighted = highlight(clean_content, lexer, HtmlFormatter(nowrap=True, noclasses=False))
503
+ final_content = content[0] + highlighted if content and content[0] in '+-' else highlighted
504
+ except Exception:
473
505
  final_content = self._escape_html(content)
474
-
475
- # CSS classes for different line types
476
- row_class = f'diff-line diff-{line_type}'
477
-
478
- html_parts.append(f'''
479
- <tr class="{row_class}">
480
- <td class="line-num old-line-num">{old_line_num}</td>
481
- <td class="line-num new-line-num">{new_line_num}</td>
482
- <td class="line-content">{final_content}</td>
483
- </tr>
484
- ''')
485
-
486
- html_parts.append('</table>')
487
- html_parts.append('</div>')
488
- html_parts.append('</div>')
506
+ else:
507
+ final_content = self._escape_html(content)
489
508
 
490
- return ''.join(html_parts)
509
+ # CSS classes for different line types
510
+ row_class = f'diff-line diff-{line_type}'
491
511
 
492
- except Exception as e:
493
- logger.error("Error generating HTML diff: %s", e)
494
- return None
512
+ html_parts.append(f'''
513
+ <tr class="{row_class}">
514
+ <td class="line-num old-line-num">{old_line_num}</td>
515
+ <td class="line-num new-line-num">{new_line_num}</td>
516
+ <td class="line-content">{final_content}</td>
517
+ </tr>
518
+ ''')
519
+
520
+ html_parts.append('</table>')
521
+ html_parts.append('</div>')
522
+ html_parts.append('</div>')
523
+
524
+ return ''.join(html_parts)
495
525
 
496
526
  def _parse_unified_diff_with_intraline(self, diff_lines, original_lines, modified_lines):
497
527
  """Parse unified diff and add intra-line character highlighting."""
@@ -1556,8 +1586,8 @@ class ProjectStateManager:
1556
1586
  # Compute diff details for the client
1557
1587
  diff_details = git_manager._compute_diff_details(original_content, modified_content)
1558
1588
 
1559
- # Generate HTML diff with syntax highlighting
1560
- html_diff = git_manager._generate_html_diff(original_content, modified_content, file_path)
1589
+ # Generate HTML diff with syntax highlighting (both minimal and full context)
1590
+ html_diff_versions = git_manager._generate_html_diff(original_content, modified_content, file_path)
1561
1591
 
1562
1592
  # Create a descriptive title for the diff
1563
1593
  title_parts = []
@@ -1585,7 +1615,7 @@ class ProjectStateManager:
1585
1615
  'from_hash': from_hash,
1586
1616
  'to_hash': to_hash,
1587
1617
  'diff_timeline': True,
1588
- 'html_diff': html_diff
1618
+ 'html_diff_versions': html_diff_versions
1589
1619
  })
1590
1620
 
1591
1621
  project_state.open_tabs[tab_key] = diff_tab
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: portacode
3
- Version: 0.3.19.dev4
3
+ Version: 0.3.19.dev5
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -8,8 +8,6 @@ BACKUP_DIR="${1:-$PWD/../backups}"
8
8
  VOLUME_NAME="portacode_pgdata"
9
9
  SERVICE="db"
10
10
 
11
- SDFSD
12
-
13
11
  # ─── PICK A BACKUP ────────────────────────────────────────────────────────
14
12
  mapfile -t BACKUPS < <(
15
13
  find "$BACKUP_DIR" -maxdepth 1 -type f -name "pgdata-*.tar.gz" \
File without changes