portacode 1.3.31__tar.gz → 1.3.32__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 portacode might be problematic. Click here for more details.

Files changed (97) hide show
  1. {portacode-1.3.31 → portacode-1.3.32}/PKG-INFO +1 -1
  2. {portacode-1.3.31 → portacode-1.3.32}/portacode/_version.py +2 -2
  3. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/git_manager.py +11 -3
  4. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/handlers.py +9 -9
  5. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/manager.py +25 -11
  6. {portacode-1.3.31 → portacode-1.3.32}/portacode.egg-info/PKG-INFO +1 -1
  7. {portacode-1.3.31 → portacode-1.3.32}/.claude/agents/communication-manager.md +0 -0
  8. {portacode-1.3.31 → portacode-1.3.32}/.claude/settings.local.json +0 -0
  9. {portacode-1.3.31 → portacode-1.3.32}/.gitignore +0 -0
  10. {portacode-1.3.31 → portacode-1.3.32}/.gitmodules +0 -0
  11. {portacode-1.3.31 → portacode-1.3.32}/LICENSE +0 -0
  12. {portacode-1.3.31 → portacode-1.3.32}/MANIFEST.in +0 -0
  13. {portacode-1.3.31 → portacode-1.3.32}/Makefile +0 -0
  14. {portacode-1.3.31 → portacode-1.3.32}/README.md +0 -0
  15. {portacode-1.3.31 → portacode-1.3.32}/backup.sh +0 -0
  16. {portacode-1.3.31 → portacode-1.3.32}/connect.py +0 -0
  17. {portacode-1.3.31 → portacode-1.3.32}/connect.sh +0 -0
  18. {portacode-1.3.31 → portacode-1.3.32}/docker-compose.yaml +0 -0
  19. {portacode-1.3.31 → portacode-1.3.32}/portacode/README.md +0 -0
  20. {portacode-1.3.31 → portacode-1.3.32}/portacode/__init__.py +0 -0
  21. {portacode-1.3.31 → portacode-1.3.32}/portacode/__main__.py +0 -0
  22. {portacode-1.3.31 → portacode-1.3.32}/portacode/cli.py +0 -0
  23. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/README.md +0 -0
  24. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/__init__.py +0 -0
  25. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/client.py +0 -0
  26. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/README.md +0 -0
  27. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
  28. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/__init__.py +0 -0
  29. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/base.py +0 -0
  30. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/chunked_content.py +0 -0
  31. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/file_handlers.py +0 -0
  32. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
  33. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/README.md +0 -0
  34. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/__init__.py +0 -0
  35. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
  36. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/models.py +0 -0
  37. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state/utils.py +0 -0
  38. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/project_state_handlers.py +0 -0
  39. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/registry.py +0 -0
  40. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/session.py +0 -0
  41. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/system_handlers.py +0 -0
  42. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/tab_factory.py +0 -0
  43. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/handlers/terminal_handlers.py +0 -0
  44. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/multiplex.py +0 -0
  45. {portacode-1.3.31 → portacode-1.3.32}/portacode/connection/terminal.py +0 -0
  46. {portacode-1.3.31 → portacode-1.3.32}/portacode/data.py +0 -0
  47. {portacode-1.3.31 → portacode-1.3.32}/portacode/keypair.py +0 -0
  48. {portacode-1.3.31 → portacode-1.3.32}/portacode/logging_categories.py +0 -0
  49. {portacode-1.3.31 → portacode-1.3.32}/portacode/service.py +0 -0
  50. {portacode-1.3.31 → portacode-1.3.32}/portacode/static/js/test-ntp-clock.html +0 -0
  51. {portacode-1.3.31 → portacode-1.3.32}/portacode/static/js/utils/ntp-clock.js +0 -0
  52. {portacode-1.3.31 → portacode-1.3.32}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
  53. {portacode-1.3.31 → portacode-1.3.32}/portacode/utils/__init__.py +0 -0
  54. {portacode-1.3.31 → portacode-1.3.32}/portacode/utils/ntp_clock.py +0 -0
  55. {portacode-1.3.31 → portacode-1.3.32}/portacode.egg-info/SOURCES.txt +0 -0
  56. {portacode-1.3.31 → portacode-1.3.32}/portacode.egg-info/dependency_links.txt +0 -0
  57. {portacode-1.3.31 → portacode-1.3.32}/portacode.egg-info/entry_points.txt +0 -0
  58. {portacode-1.3.31 → portacode-1.3.32}/portacode.egg-info/requires.txt +0 -0
  59. {portacode-1.3.31 → portacode-1.3.32}/portacode.egg-info/top_level.txt +0 -0
  60. {portacode-1.3.31 → portacode-1.3.32}/pyproject.toml +0 -0
  61. {portacode-1.3.31 → portacode-1.3.32}/restore.sh +0 -0
  62. {portacode-1.3.31 → portacode-1.3.32}/run_tests.py +0 -0
  63. {portacode-1.3.31 → portacode-1.3.32}/setup.cfg +0 -0
  64. {portacode-1.3.31 → portacode-1.3.32}/setup.py +0 -0
  65. {portacode-1.3.31 → portacode-1.3.32}/test.sh +0 -0
  66. {portacode-1.3.31 → portacode-1.3.32}/test_modules/README.md +0 -0
  67. {portacode-1.3.31 → portacode-1.3.32}/test_modules/__init__.py +0 -0
  68. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_device_online.py +0 -0
  69. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_file_operations.py +0 -0
  70. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_git_status_ui.py +0 -0
  71. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_login_flow.py +0 -0
  72. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_navigate_testing_folder.py +0 -0
  73. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_terminal_buffer_performance.py +0 -0
  74. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_terminal_interaction.py +0 -0
  75. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_terminal_loading_race_condition.py +0 -0
  76. {portacode-1.3.31 → portacode-1.3.32}/test_modules/test_terminal_start.py +0 -0
  77. {portacode-1.3.31 → portacode-1.3.32}/test_request_id.py +0 -0
  78. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/.env.example +0 -0
  79. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/README.md +0 -0
  80. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/__init__.py +0 -0
  81. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/cli.py +0 -0
  82. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/__init__.py +0 -0
  83. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/base_test.py +0 -0
  84. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/cli_manager.py +0 -0
  85. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/hierarchical_runner.py +0 -0
  86. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/playwright_manager.py +0 -0
  87. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/runner.py +0 -0
  88. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/shared_cli_manager.py +0 -0
  89. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/core/test_discovery.py +0 -0
  90. {portacode-1.3.31 → portacode-1.3.32}/testing_framework/requirements.txt +0 -0
  91. {portacode-1.3.31 → portacode-1.3.32}/todo/agent_context_management.md +0 -0
  92. {portacode-1.3.31 → portacode-1.3.32}/todo/issues/device_performance_degradation.md +0 -0
  93. {portacode-1.3.31 → portacode-1.3.32}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
  94. {portacode-1.3.31 → portacode-1.3.32}/todo/issues/indefinite_resource_loading.md +0 -0
  95. {portacode-1.3.31 → portacode-1.3.32}/todo/issues/premature_terminal_exit.md +0 -0
  96. {portacode-1.3.31 → portacode-1.3.32}/todo/issues/terminals_exit_upon_starting.md +0 -0
  97. {portacode-1.3.31 → portacode-1.3.32}/tools/test_python_ntp_clock.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 1.3.31
3
+ Version: 1.3.32
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.3.31'
32
- __version_tuple__ = version_tuple = (1, 3, 31)
31
+ __version__ = version = '1.3.32'
32
+ __version_tuple__ = version_tuple = (1, 3, 32)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -350,9 +350,18 @@ class GitManager:
350
350
  status_output = self.repo.git.status(*rel_paths, porcelain=True)
351
351
  if status_output.strip():
352
352
  for line in status_output.strip().split('\n'):
353
+ # Git porcelain format: XY path (X=index, Y=worktree, then space, then path)
354
+ # Some files may have renamed format: XY path -> new_path
353
355
  if len(line) >= 3:
354
- file_path_from_status = line[3:] if len(line) > 3 else ""
355
- status_map[file_path_from_status] = line
356
+ # Skip first 3 characters (2 status + 1 space) to get the file path
357
+ # But git uses exactly 2 chars for status then space, so position 3 onwards is path
358
+ parts = line.split(None, 1) # Split on first whitespace to separate status from path
359
+ if len(parts) >= 2:
360
+ file_path_from_status = parts[1]
361
+ # Handle renames (format: "old_path -> new_path")
362
+ if ' -> ' in file_path_from_status:
363
+ file_path_from_status = file_path_from_status.split(' -> ')[1]
364
+ status_map[file_path_from_status] = line
356
365
  except Exception as e:
357
366
  logger.debug("Error getting batch status: %s", e)
358
367
 
@@ -469,7 +478,6 @@ class GitManager:
469
478
  elif index_status == 'D' or worktree_status == 'D':
470
479
  has_deleted = True
471
480
 
472
- # Priority order: untracked > modified/deleted > clean
473
481
  if has_untracked:
474
482
  return {"is_tracked": False, "status": "untracked", "is_ignored": False, "is_staged": is_staged}
475
483
  elif has_deleted:
@@ -408,10 +408,10 @@ class ProjectStateGitStageHandler(AsyncHandler):
408
408
  success = git_manager.stage_file(file_paths_to_stage[0])
409
409
  else:
410
410
  success = git_manager.stage_files(file_paths_to_stage)
411
-
411
+
412
412
  if success:
413
- # Refresh entire project state to ensure consistency
414
- await manager._refresh_project_state(source_client_session)
413
+ # Refresh git status only (no filesystem changes from staging)
414
+ await manager._refresh_project_state(source_client_session, git_only=True)
415
415
 
416
416
  # Build response
417
417
  response = {
@@ -482,10 +482,10 @@ class ProjectStateGitUnstageHandler(AsyncHandler):
482
482
  success = git_manager.unstage_file(file_paths_to_unstage[0])
483
483
  else:
484
484
  success = git_manager.unstage_files(file_paths_to_unstage)
485
-
485
+
486
486
  if success:
487
- # Refresh entire project state to ensure consistency
488
- await manager._refresh_project_state(source_client_session)
487
+ # Refresh git status only (no filesystem changes from unstaging)
488
+ await manager._refresh_project_state(source_client_session, git_only=True)
489
489
 
490
490
  # Build response
491
491
  response = {
@@ -620,9 +620,9 @@ class ProjectStateGitCommitHandler(AsyncHandler):
620
620
  if success:
621
621
  # Get the commit hash of the new commit
622
622
  commit_hash = git_manager.get_head_commit_hash()
623
-
624
- # Refresh entire project state to ensure consistency
625
- await manager._refresh_project_state(source_client_session)
623
+
624
+ # Refresh git status only (no filesystem changes from commit)
625
+ await manager._refresh_project_state(source_client_session, git_only=True)
626
626
  except Exception as e:
627
627
  error_message = str(e)
628
628
  logger.error("Error during commit: %s", error_message)
@@ -152,7 +152,8 @@ class ProjectStateManager:
152
152
  async def git_change_callback():
153
153
  """Callback when git status changes are detected."""
154
154
  logger.debug("Git change detected, refreshing project state for %s", client_session_id)
155
- await self._refresh_project_state(client_session_id)
155
+ # Git directory changes only affect git status, not filesystem
156
+ await self._refresh_project_state(client_session_id, git_only=True)
156
157
 
157
158
  git_manager = GitManager(project_folder_path, change_callback=git_change_callback)
158
159
  self.git_managers[client_session_id] = git_manager
@@ -877,9 +878,17 @@ class ProjectStateManager:
877
878
  self._pending_changes.clear()
878
879
  logger.debug("🔍 [TRACE] ✅ Finished processing file changes")
879
880
 
880
- async def _refresh_project_state(self, client_session_id: str):
881
- """Refresh project state after file changes."""
882
- logger.debug("🔍 [TRACE] _refresh_project_state called for session: %s", client_session_id)
881
+ async def _refresh_project_state(self, client_session_id: str, git_only: bool = False):
882
+ """Refresh project state after file changes.
883
+
884
+ Args:
885
+ client_session_id: The client session ID
886
+ git_only: If True, only git status changed (skip filesystem operations like
887
+ detecting new directories and syncing file state). Use this for
888
+ git operations (stage, unstage, revert) to avoid unnecessary work.
889
+ """
890
+ logger.debug("🔍 [TRACE] _refresh_project_state called for session: %s (git_only=%s)",
891
+ client_session_id, git_only)
883
892
 
884
893
  if client_session_id not in self.projects:
885
894
  logger.debug("🔍 [TRACE] ❌ Session not found in projects: %s", client_session_id)
@@ -930,15 +939,20 @@ class ProjectStateManager:
930
939
  old_status_summary, project_state.git_status_summary)
931
940
  else:
932
941
  logger.debug("🔍 [TRACE] ❌ No git manager found for session: %s", client_session_id)
933
-
934
- # Detect and add new directories in expanded folders before syncing
935
- logger.debug("🔍 [TRACE] Detecting and adding new directories...")
936
- await self._detect_and_add_new_directories(project_state)
937
-
938
- # Sync all dependent state (items, watchdog) with updated monitored folders
942
+
943
+ # For git-only operations, skip scanning for new directories
944
+ # but still sync items to update git attributes for UI
945
+ if not git_only:
946
+ # Detect and add new directories in expanded folders before syncing
947
+ logger.debug("🔍 [TRACE] Detecting and adding new directories...")
948
+ await self._detect_and_add_new_directories(project_state)
949
+ else:
950
+ logger.debug("🔍 [TRACE] Skipping directory detection (git_only=True)")
951
+
952
+ # Always sync state to update git attributes on items (needed for UI updates)
939
953
  logger.debug("🔍 [TRACE] Syncing all state with monitored folders...")
940
954
  await self._sync_all_state_with_monitored_folders(project_state)
941
-
955
+
942
956
  # Send update to clients
943
957
  logger.debug("🔍 [TRACE] About to send project state update...")
944
958
  await self._send_project_state_update(project_state)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 1.3.31
3
+ Version: 1.3.32
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes