railmux 0.4.2.dev3__tar.gz → 0.4.2.dev4__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.
- {railmux-0.4.2.dev3/src/railmux.egg-info → railmux-0.4.2.dev4}/PKG-INFO +1 -1
- railmux-0.4.2.dev4/src/railmux/__init__.py +1 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/fast_display_server.py +84 -3
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/tmux_server.py +66 -6
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4/src/railmux.egg-info}/PKG-INFO +1 -1
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fast_display_server.py +79 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_server.py +60 -0
- railmux-0.4.2.dev3/src/railmux/__init__.py +0 -1
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/LICENSE +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/MANIFEST.in +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/README.md +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/pyproject.toml +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/setup.cfg +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/__main__.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/atomic_file.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/background_index.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/cli.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/codex_index.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/config.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/config_cli.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/diagnostic_contract.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/diagnostics.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/discovery.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/display_transport.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/entrypoint.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/fast_display_client.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/fast_display_history.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/fast_display_input.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/fast_display_protocol.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/favorites.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/fuzzy.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/help_workspace.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/image_paste.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/launcher.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/legacy_sessions.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/local_clipboard.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/local_open.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/models.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/modes.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/mouse_manager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/orphan_marker.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/pane_surface.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/path_codec.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/preview_pager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/project_favorites.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/provider_paths.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/release_version.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/remote_config.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/renames.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/restart_state.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/runtime_config.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/scroll_agent.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/scroll_manager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/selection_isolation.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/self_update.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/session_cache.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/session_index.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/session_lease.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/setting_contracts.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/settings.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ssh_args.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ssh_compat.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ssh_display_diagnostics.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ssh_doctor.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ssh_preflight.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/system_deps.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/terminal_screen.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/terminal_status.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/tmux_binding_manager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/tmux_capabilities.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/tmux_ctl.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/tmux_health.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/tool_panes.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/transcript.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/__init__.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/_widgets.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/app.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/keymap.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/modals.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/projects_pane.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/running_pane.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/sessions_pane.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/sidebar.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/statusbar.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/ui/workspace.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_attach_relay.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_bootstrap.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_install_log.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_msys2.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_pacman.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_paths.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_tmux_lifecycle.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux/windows_ui_transition.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux.egg-info/SOURCES.txt +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux.egg-info/dependency_links.txt +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux.egg-info/entry_points.txt +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux.egg-info/requires.txt +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/src/railmux.egg-info/top_level.txt +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/app_test_harness.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_agent_workspace.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_app_codex_placeholder.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_app_quit.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_app_restart_restore.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_app_running_recovery.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_atomic_file.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_background_index.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_cli.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_code_map.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_codex_delete.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_codex_index.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_codex_lineage.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_codex_transcript.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_config.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_config_cli.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_denested_transport_benchmark.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_diagnostics.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_discovery.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_display_transport.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fast_display_bootstrap.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fast_display_history.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fast_display_protocol.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fast_display_selection.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fast_display_terminal.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_focus_highlight.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fullscreen_binding.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_fuzzy.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_help_agent.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_help_workspace.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_history_cleanup.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_image_paste.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_keymap.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_launcher.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_layout_profile.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_legacy_sessions.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_local_clipboard.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_local_open.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_modals.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_mode_selection.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_modes.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_mouse_manager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_new_project.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_options.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_orphan_recovery.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_pane_surface.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_path_codec.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_preview_pager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_project_favorites.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_projects_pane.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_provider_paths.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_release_notes.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_release_version.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_release_workflow.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_remote_config.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_renames.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_restart_state.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_running_pane.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_running_sort.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_runtime_config.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_scroll_agent.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_scroll_manager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_selection_isolation.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_self_update.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_session_cache.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_session_index.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_session_lease.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_sessions_pane.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_setting_contracts.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_settings.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_sidebar.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_ssh_args.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_ssh_compat.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_ssh_display_benchmark.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_ssh_display_diagnostics.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_ssh_doctor.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_status.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_statusbar.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_system_deps.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_terminal_size.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_terminal_status.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_termux_local_touch.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_binding_manager.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_capabilities.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_ctl.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_health.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_integration.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tmux_status.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_tool_panes.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_transcript.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_utf8_state.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_web_demo_recorder.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_wheel_smoke.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_widgets.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_attach_relay.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_bootstrap.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_install_log.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_msys2.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_pacman.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_paths.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_synchronized_screen.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_tmux_lifecycle.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_ui_transition.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_windows_wrapper_contract.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tests/test_yolo_prompt.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tools/denested_transport_benchmark.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tools/release_notes.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tools/wheel_smoke.py +0 -0
- {railmux-0.4.2.dev3 → railmux-0.4.2.dev4}/tools/windows_archive_smoke.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.2.dev4"
|
|
@@ -1747,6 +1747,83 @@ def _transcript_rows(
|
|
|
1747
1747
|
os.close(fd)
|
|
1748
1748
|
|
|
1749
1749
|
|
|
1750
|
+
_OVERLAP_STYLE_RE = re.compile(rb"\x1b\[[0-9;]*m")
|
|
1751
|
+
_OVERLAP_SPACE_RE = re.compile(r"\s+")
|
|
1752
|
+
_OVERLAP_ANCHOR_CHARS = 12
|
|
1753
|
+
_OVERLAP_SINGLE_ANCHOR_CHARS = 24
|
|
1754
|
+
_OVERLAP_SEARCH_SCREENS = 4
|
|
1755
|
+
_OVERLAP_MIN_SEARCH_ROWS = 200
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
def _overlap_text(row: bytes) -> str:
|
|
1759
|
+
"""Return a row's visible text without styling or any whitespace.
|
|
1760
|
+
|
|
1761
|
+
The transcript and the provider wrap and indent the same message
|
|
1762
|
+
differently, so only the whitespace-free character stream is comparable.
|
|
1763
|
+
"""
|
|
1764
|
+
text = _OVERLAP_STYLE_RE.sub(b"", row).decode("utf-8", errors="replace")
|
|
1765
|
+
return _OVERLAP_SPACE_RE.sub("", text)
|
|
1766
|
+
|
|
1767
|
+
|
|
1768
|
+
def _transcript_rows_before_screen(
|
|
1769
|
+
transcript_rows: Sequence[bytes],
|
|
1770
|
+
screen_rows: Sequence[bytes],
|
|
1771
|
+
) -> int:
|
|
1772
|
+
"""Return how many transcript rows precede the live screen's content.
|
|
1773
|
+
|
|
1774
|
+
Transcript-backed history appends the live viewport after the transcript,
|
|
1775
|
+
whose tail usually holds the same newest message. Locate the screen's
|
|
1776
|
+
text in the transcript tail through distinctive anchor rows and cut the
|
|
1777
|
+
transcript where the screen begins. Two anchors must agree on that start
|
|
1778
|
+
unless one long anchor is the only candidate; without a credible match
|
|
1779
|
+
every transcript row is kept.
|
|
1780
|
+
"""
|
|
1781
|
+
total = len(transcript_rows)
|
|
1782
|
+
window = max(
|
|
1783
|
+
_OVERLAP_MIN_SEARCH_ROWS, _OVERLAP_SEARCH_SCREENS * len(screen_rows))
|
|
1784
|
+
first = max(0, total - window)
|
|
1785
|
+
row_starts: list[int] = []
|
|
1786
|
+
parts: list[str] = []
|
|
1787
|
+
offset = 0
|
|
1788
|
+
for row in transcript_rows[first:]:
|
|
1789
|
+
row_starts.append(offset)
|
|
1790
|
+
text = _overlap_text(row)
|
|
1791
|
+
parts.append(text)
|
|
1792
|
+
offset += len(text)
|
|
1793
|
+
haystack = "".join(parts)
|
|
1794
|
+
screen_offset = 0
|
|
1795
|
+
starts: list[tuple[int, int]] = []
|
|
1796
|
+
for row in screen_rows:
|
|
1797
|
+
text = _overlap_text(row)
|
|
1798
|
+
if len(text) >= _OVERLAP_ANCHOR_CHARS and haystack.count(text) == 1:
|
|
1799
|
+
starts.append((haystack.index(text) - screen_offset, len(text)))
|
|
1800
|
+
if len(starts) == 2:
|
|
1801
|
+
break
|
|
1802
|
+
screen_offset += len(text)
|
|
1803
|
+
if not starts:
|
|
1804
|
+
return total
|
|
1805
|
+
if len(starts) == 1:
|
|
1806
|
+
if starts[0][1] < _OVERLAP_SINGLE_ANCHOR_CHARS:
|
|
1807
|
+
return total
|
|
1808
|
+
else:
|
|
1809
|
+
# Allow small rendering differences (list numbering, bullets).
|
|
1810
|
+
tolerance = 16 + abs(starts[0][0]) // 20
|
|
1811
|
+
if abs(starts[0][0] - starts[1][0]) > tolerance:
|
|
1812
|
+
return total
|
|
1813
|
+
start = max(0, starts[0][0])
|
|
1814
|
+
# Keep a row that begins before the screen: it may carry text the screen
|
|
1815
|
+
# no longer shows, and a partial duplicate is better than a loss.
|
|
1816
|
+
keep = len(row_starts)
|
|
1817
|
+
for index, row_start in enumerate(row_starts):
|
|
1818
|
+
if row_start >= start:
|
|
1819
|
+
keep = index
|
|
1820
|
+
break
|
|
1821
|
+
# Drop trailing blank rows so the screen is not preceded by a gap.
|
|
1822
|
+
while keep and not parts[keep - 1]:
|
|
1823
|
+
keep -= 1
|
|
1824
|
+
return first + keep
|
|
1825
|
+
|
|
1826
|
+
|
|
1750
1827
|
def _capture_pane_history(
|
|
1751
1828
|
pyte: object,
|
|
1752
1829
|
pane: _PaneGeometry,
|
|
@@ -1852,14 +1929,18 @@ def _capture_pane_history(
|
|
|
1852
1929
|
transcript_used = transcript_entry is not None and bool(transcript_entry.rows)
|
|
1853
1930
|
if transcript_used:
|
|
1854
1931
|
assert transcript_entry is not None
|
|
1855
|
-
|
|
1932
|
+
kept = _transcript_rows_before_screen(transcript_entry.rows, current_raw)
|
|
1933
|
+
trimmed = len(transcript_entry.rows) - kept
|
|
1934
|
+
transcript_lines = transcript_entry.rows[:kept]
|
|
1856
1935
|
history_count = max(0, max_lines - pane.height)
|
|
1857
1936
|
source_lines = (
|
|
1858
1937
|
transcript_lines[-history_count:] if history_count else ()
|
|
1859
1938
|
) + current_raw
|
|
1860
1939
|
timeline_end = max(
|
|
1861
1940
|
pane.height,
|
|
1862
|
-
(transcript_entry.total_rows or len(transcript_entry.rows))
|
|
1941
|
+
(transcript_entry.total_rows or len(transcript_entry.rows))
|
|
1942
|
+
- trimmed
|
|
1943
|
+
+ pane.height,
|
|
1863
1944
|
)
|
|
1864
1945
|
else:
|
|
1865
1946
|
source_lines = rendered_raw
|
|
@@ -1910,7 +1991,7 @@ def _capture_pane_history(
|
|
|
1910
1991
|
budget_truncated
|
|
1911
1992
|
or (
|
|
1912
1993
|
transcript_entry.more_available
|
|
1913
|
-
or len(
|
|
1994
|
+
or len(transcript_lines) + pane.height > len(lines)
|
|
1914
1995
|
if transcript_used and transcript_entry is not None
|
|
1915
1996
|
else pane.history_size + pane.height > len(lines)
|
|
1916
1997
|
)
|
|
@@ -22,6 +22,8 @@ _SESSION_ID_RE = re.compile(r"[A-Za-z0-9-]{1,256}\Z")
|
|
|
22
22
|
_HISTORY_SOURCE_SCHEMA = 1
|
|
23
23
|
_TRANSCRIPT_SOURCE_SCHEMA = 1
|
|
24
24
|
_MAX_TRANSCRIPT_SOURCE_BYTES = 8192
|
|
25
|
+
_CONTINUATION_TAIL_BYTES = 4096
|
|
26
|
+
_MAX_CONTINUATION_HOPS = 8
|
|
25
27
|
_DEFAULT_DISCOVERY_TIMEOUT = 2.0
|
|
26
28
|
_WINDOWS_DISCOVERY_TIMEOUT = 5.0
|
|
27
29
|
|
|
@@ -415,11 +417,8 @@ def decode_transcript_source(raw: str) -> TranscriptSource | None:
|
|
|
415
417
|
return TranscriptSource(provider, session_id, path)
|
|
416
418
|
|
|
417
419
|
|
|
418
|
-
def
|
|
419
|
-
"""Open
|
|
420
|
-
source = decode_transcript_source(raw)
|
|
421
|
-
if source is None:
|
|
422
|
-
return None
|
|
420
|
+
def _open_owned_regular_file(path: Path) -> int | None:
|
|
421
|
+
"""Open a same-user regular file without following the final symlink."""
|
|
423
422
|
flags = os.O_RDONLY
|
|
424
423
|
if hasattr(os, "O_CLOEXEC"):
|
|
425
424
|
flags |= os.O_CLOEXEC
|
|
@@ -427,7 +426,7 @@ def open_transcript_source(raw: str) -> tuple[TranscriptSource, int] | None:
|
|
|
427
426
|
flags |= os.O_NOFOLLOW
|
|
428
427
|
fd = -1
|
|
429
428
|
try:
|
|
430
|
-
fd = os.open(
|
|
429
|
+
fd = os.open(path, flags)
|
|
431
430
|
info = os.fstat(fd)
|
|
432
431
|
except OSError:
|
|
433
432
|
if fd >= 0:
|
|
@@ -443,6 +442,67 @@ def open_transcript_source(raw: str) -> tuple[TranscriptSource, int] | None:
|
|
|
443
442
|
):
|
|
444
443
|
os.close(fd)
|
|
445
444
|
return None
|
|
445
|
+
return fd
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def _claude_continuation_id(fd: int) -> str | None:
|
|
449
|
+
"""Return the successor session named by a final ``continued-in`` record.
|
|
450
|
+
|
|
451
|
+
Claude Code can move a live conversation to a new session file, copying
|
|
452
|
+
the full history and ending the old file with one ``continued-in``
|
|
453
|
+
record. Only that exact final record is trusted.
|
|
454
|
+
"""
|
|
455
|
+
try:
|
|
456
|
+
size = os.fstat(fd).st_size
|
|
457
|
+
tail = os.pread(
|
|
458
|
+
fd,
|
|
459
|
+
min(size, _CONTINUATION_TAIL_BYTES),
|
|
460
|
+
max(0, size - _CONTINUATION_TAIL_BYTES),
|
|
461
|
+
)
|
|
462
|
+
except OSError:
|
|
463
|
+
return None
|
|
464
|
+
lines = tail.rstrip(b"\n").rsplit(b"\n", 1)
|
|
465
|
+
if b"continued-in" not in lines[-1]:
|
|
466
|
+
return None
|
|
467
|
+
try:
|
|
468
|
+
record = json.loads(lines[-1])
|
|
469
|
+
except (UnicodeDecodeError, ValueError):
|
|
470
|
+
return None
|
|
471
|
+
if not isinstance(record, dict) or record.get("type") != "continued-in":
|
|
472
|
+
return None
|
|
473
|
+
successor = record.get("continuedInSessionId")
|
|
474
|
+
if not isinstance(successor, str) or not _SESSION_ID_RE.fullmatch(successor):
|
|
475
|
+
return None
|
|
476
|
+
return successor
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def open_transcript_source(raw: str) -> tuple[TranscriptSource, int] | None:
|
|
480
|
+
"""Open an exact same-user transcript without following the final symlink.
|
|
481
|
+
|
|
482
|
+
A Claude transcript that was continued in another session resolves to the
|
|
483
|
+
newest same-directory successor, so history keeps following the live pane.
|
|
484
|
+
"""
|
|
485
|
+
source = decode_transcript_source(raw)
|
|
486
|
+
if source is None:
|
|
487
|
+
return None
|
|
488
|
+
fd = _open_owned_regular_file(source.path)
|
|
489
|
+
if fd is None:
|
|
490
|
+
return None
|
|
491
|
+
if source.provider != "claude":
|
|
492
|
+
return source, fd
|
|
493
|
+
seen = {source.session_id}
|
|
494
|
+
for _ in range(_MAX_CONTINUATION_HOPS):
|
|
495
|
+
successor = _claude_continuation_id(fd)
|
|
496
|
+
if successor is None or successor in seen:
|
|
497
|
+
break
|
|
498
|
+
path = source.path.with_name(f"{successor}.jsonl")
|
|
499
|
+
next_fd = _open_owned_regular_file(path)
|
|
500
|
+
if next_fd is None:
|
|
501
|
+
break
|
|
502
|
+
os.close(fd)
|
|
503
|
+
fd = next_fd
|
|
504
|
+
source = TranscriptSource(source.provider, successor, path)
|
|
505
|
+
seen.add(successor)
|
|
446
506
|
return source, fd
|
|
447
507
|
|
|
448
508
|
|
|
@@ -1593,6 +1593,85 @@ def test_server_claude_history_uses_stable_transcript_suffix(monkeypatch):
|
|
|
1593
1593
|
assert hot.lines[-2:] == (b"live-a", b"live-b")
|
|
1594
1594
|
|
|
1595
1595
|
|
|
1596
|
+
def test_server_claude_history_drops_transcript_tail_shown_on_screen(monkeypatch):
|
|
1597
|
+
pane = fast_display_server._PaneGeometry(
|
|
1598
|
+
"%8",
|
|
1599
|
+
31,
|
|
1600
|
+
0,
|
|
1601
|
+
24,
|
|
1602
|
+
4,
|
|
1603
|
+
mouse_forwardable=True,
|
|
1604
|
+
alternate_on=True,
|
|
1605
|
+
transcript_source="exact-marker",
|
|
1606
|
+
transcript_backed=True,
|
|
1607
|
+
claude_history_policy="local",
|
|
1608
|
+
)
|
|
1609
|
+
# The transcript wraps the newest answer at the pane edge while the live
|
|
1610
|
+
# Claude screen uses a hanging indent and styling for the same text.
|
|
1611
|
+
transcript_rows = (
|
|
1612
|
+
b"\x1b[0mold question here\x1b[0m",
|
|
1613
|
+
b"\x1b[0m\x1b[0m",
|
|
1614
|
+
b"\x1b[0m\xe2\x97\x8f first answer line alph",
|
|
1615
|
+
b"a beta gamma delta\x1b[0m",
|
|
1616
|
+
b"\x1b[0m second answer line kept\x1b[0m",
|
|
1617
|
+
)
|
|
1618
|
+
live = (
|
|
1619
|
+
b"\xe2\x97\x8f first answer line",
|
|
1620
|
+
b" \x1b[1malpha beta gamma delta\x1b[0m",
|
|
1621
|
+
b" second answer line kept",
|
|
1622
|
+
b"\xe2\x9d\xaf",
|
|
1623
|
+
)
|
|
1624
|
+
monkeypatch.setattr(
|
|
1625
|
+
subprocess,
|
|
1626
|
+
"check_output",
|
|
1627
|
+
lambda *_args, **_kwargs: b"\n".join(live) + b"\n",
|
|
1628
|
+
)
|
|
1629
|
+
monkeypatch.setattr(
|
|
1630
|
+
fast_display_server,
|
|
1631
|
+
"_transcript_rows",
|
|
1632
|
+
lambda *_args, **_kwargs: fast_display_server._TranscriptCacheEntry(
|
|
1633
|
+
(1, 2, 3, 4), transcript_rows, False
|
|
1634
|
+
),
|
|
1635
|
+
)
|
|
1636
|
+
monkeypatch.setattr(
|
|
1637
|
+
fast_display_server,
|
|
1638
|
+
"_render_history_lines",
|
|
1639
|
+
lambda _pyte, lines, _width: tuple(lines),
|
|
1640
|
+
)
|
|
1641
|
+
|
|
1642
|
+
snapshot = fast_display_server._capture_pane_history(object(), pane, 1, 300)
|
|
1643
|
+
|
|
1644
|
+
assert snapshot is not None
|
|
1645
|
+
assert snapshot.lines == (transcript_rows[0],) + live
|
|
1646
|
+
assert snapshot.timeline_end == 1 + pane.height
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
def test_transcript_overlap_keeps_rows_without_credible_screen_match():
|
|
1650
|
+
rows = tuple(
|
|
1651
|
+
f"repeated status line number {index % 2}".encode() for index in range(8)
|
|
1652
|
+
)
|
|
1653
|
+
unrelated = (b"nothing in common with the transcript at all", b"")
|
|
1654
|
+
repeated = (b"repeated status line number 0", b"repeated status line number 1")
|
|
1655
|
+
short = (b"tiny", b"")
|
|
1656
|
+
|
|
1657
|
+
keep = fast_display_server._transcript_rows_before_screen
|
|
1658
|
+
assert keep(rows, unrelated) == len(rows)
|
|
1659
|
+
assert keep(rows, repeated) == len(rows)
|
|
1660
|
+
assert keep(rows, short) == len(rows)
|
|
1661
|
+
assert keep((), unrelated) == 0
|
|
1662
|
+
|
|
1663
|
+
|
|
1664
|
+
def test_transcript_overlap_rejects_disagreeing_anchors():
|
|
1665
|
+
rows = (
|
|
1666
|
+
b"first distinctive anchor row",
|
|
1667
|
+
b"filler " * 20,
|
|
1668
|
+
b"second distinctive anchor row",
|
|
1669
|
+
)
|
|
1670
|
+
screen = (b"second distinctive anchor row", b"first distinctive anchor row")
|
|
1671
|
+
|
|
1672
|
+
assert fast_display_server._transcript_rows_before_screen(rows, screen) == 3
|
|
1673
|
+
|
|
1674
|
+
|
|
1596
1675
|
@pytest.mark.parametrize(
|
|
1597
1676
|
("policy", "choice_required"),
|
|
1598
1677
|
[("ask", True), ("native", False)],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
import os
|
|
4
5
|
import subprocess
|
|
5
6
|
from types import SimpleNamespace
|
|
@@ -519,6 +520,65 @@ def test_transcript_source_round_trip_opens_only_exact_same_user_file(tmp_path):
|
|
|
519
520
|
os.close(opened[1])
|
|
520
521
|
|
|
521
522
|
|
|
523
|
+
def _continued_in(session_id: str) -> str:
|
|
524
|
+
return json.dumps({
|
|
525
|
+
"type": "continued-in",
|
|
526
|
+
"sessionId": "previous",
|
|
527
|
+
"continuedInSessionId": session_id,
|
|
528
|
+
}) + "\n"
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def test_claude_transcript_source_follows_continued_in_chain(tmp_path):
|
|
532
|
+
first, second, third = (
|
|
533
|
+
"47fca075-9cb8-44fb-a314-d57ef2256ad9",
|
|
534
|
+
"96fd3642-6c17-4c9b-8129-08d3d9db3e8a",
|
|
535
|
+
"02b59000-6bb4-4ec5-bdca-24f7a96b0467",
|
|
536
|
+
)
|
|
537
|
+
(tmp_path / f"{first}.jsonl").write_text(
|
|
538
|
+
'{"type":"user"}\n' + _continued_in(second))
|
|
539
|
+
(tmp_path / f"{second}.jsonl").write_text(
|
|
540
|
+
'{"type":"user"}\n' + _continued_in(third))
|
|
541
|
+
(tmp_path / f"{third}.jsonl").write_text('{"type":"assistant"}\n')
|
|
542
|
+
marker = tmux_server.encode_transcript_source(
|
|
543
|
+
"claude", first, tmp_path / f"{first}.jsonl")
|
|
544
|
+
|
|
545
|
+
opened = tmux_server.open_transcript_source(marker)
|
|
546
|
+
|
|
547
|
+
assert opened is not None
|
|
548
|
+
source, fd = opened
|
|
549
|
+
try:
|
|
550
|
+
assert source.session_id == third
|
|
551
|
+
assert source.path == tmp_path / f"{third}.jsonl"
|
|
552
|
+
assert os.read(fd, 100) == b'{"type":"assistant"}\n'
|
|
553
|
+
finally:
|
|
554
|
+
os.close(fd)
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
@pytest.mark.parametrize(
|
|
558
|
+
"tail",
|
|
559
|
+
[
|
|
560
|
+
_continued_in("missing-successor"),
|
|
561
|
+
_continued_in("../escape"),
|
|
562
|
+
_continued_in("47fca075-9cb8-44fb-a314-d57ef2256ad9"),
|
|
563
|
+
_continued_in("96fd3642-6c17-4c9b-8129-08d3d9db3e8a") + '{"type":"user"}\n',
|
|
564
|
+
],
|
|
565
|
+
)
|
|
566
|
+
def test_claude_transcript_source_keeps_file_without_valid_successor(
|
|
567
|
+
tmp_path, tail,
|
|
568
|
+
):
|
|
569
|
+
session_id = "47fca075-9cb8-44fb-a314-d57ef2256ad9"
|
|
570
|
+
path = tmp_path / f"{session_id}.jsonl"
|
|
571
|
+
path.write_text('{"type":"user"}\n' + tail)
|
|
572
|
+
(tmp_path / "96fd3642-6c17-4c9b-8129-08d3d9db3e8a.jsonl").write_text("{}\n")
|
|
573
|
+
marker = tmux_server.encode_transcript_source("claude", session_id, path)
|
|
574
|
+
|
|
575
|
+
opened = tmux_server.open_transcript_source(marker)
|
|
576
|
+
|
|
577
|
+
assert opened is not None
|
|
578
|
+
os.close(opened[1])
|
|
579
|
+
assert opened[0].session_id == session_id and opened[0].path == path
|
|
580
|
+
|
|
581
|
+
|
|
522
582
|
def test_codex_transcript_source_requires_matching_rollout_file(tmp_path):
|
|
523
583
|
session_id = "019fcaad-27a1-70c0-8029-8a9c7803fa6b"
|
|
524
584
|
path = tmp_path / f"rollout-2026-08-04T02-49-33-{session_id}.jsonl"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.2.dev3"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|