fix(gui_2): use str sentinel not bytes in _capture_workspace_profile
This commit is contained in:
+133
@@ -0,0 +1,133 @@
|
||||
"""Manually start sloppy.py, then run the test against the same GUI process."""
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import socket
|
||||
from pathlib import Path
|
||||
|
||||
# Start sloppy.py
|
||||
project_root = Path("C:/projects/manual_slop").absolute()
|
||||
gui_script = project_root / "sloppy.py"
|
||||
test_workspace = project_root / "tests" / "artifacts" / "live_gui_workspace"
|
||||
|
||||
# Clean up old workspace
|
||||
if test_workspace.exists():
|
||||
import shutil
|
||||
for _ in range(5):
|
||||
try:
|
||||
shutil.rmtree(test_workspace)
|
||||
break
|
||||
except PermissionError:
|
||||
time.sleep(0.5)
|
||||
|
||||
test_workspace.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create minimal files
|
||||
(test_workspace / "manual_slop.toml").write_text("[project]\nname = 'TestProject'\n\n[conductor]\ndir = 'conductor'\n", encoding="utf-8")
|
||||
(test_workspace / "conductor" / "tracks").mkdir(parents=True, exist_ok=True)
|
||||
|
||||
config_content = {
|
||||
'ai': {'provider': 'gemini', 'model': 'gemini-2.5-flash-lite'},
|
||||
'projects': {
|
||||
'paths': [str((test_workspace / 'manual_slop.toml').absolute())],
|
||||
'active': str((test_workspace / 'manual_slop.toml').absolute())
|
||||
},
|
||||
'paths': {
|
||||
'logs_dir': str((test_workspace / "logs").absolute()),
|
||||
'scripts_dir': str((test_workspace / "scripts" / "generated").absolute())
|
||||
},
|
||||
}
|
||||
import tomli_w
|
||||
with open(test_workspace / 'config.toml', 'wb') as f:
|
||||
tomli_w.dump(config_content, f)
|
||||
|
||||
# Start sloppy.py
|
||||
os.makedirs("logs", exist_ok=True)
|
||||
log_file = open("logs/sloppy_py_test_2.log", "w", encoding="utf-8")
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = str(project_root.absolute())
|
||||
env["SLOP_CONFIG"] = str((test_workspace / "config.toml").absolute())
|
||||
env["SLOP_GLOBAL_PRESETS"] = str((test_workspace / "presets.toml").absolute())
|
||||
env["SLOP_GLOBAL_TOOL_PRESETS"] = str((test_workspace / "tool_presets.toml").absolute())
|
||||
|
||||
print("Starting sloppy.py...")
|
||||
proc = subprocess.Popen(
|
||||
["uv", "run", "python", "-u", str(gui_script), "--enable-test-hooks"],
|
||||
stdout=log_file,
|
||||
stderr=log_file,
|
||||
text=True,
|
||||
cwd=str(test_workspace.absolute()),
|
||||
env=env,
|
||||
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
|
||||
)
|
||||
print(f"Started PID: {proc.pid}")
|
||||
|
||||
# Wait for hook server
|
||||
import requests
|
||||
for i in range(30):
|
||||
try:
|
||||
resp = requests.get("http://127.0.0.1:8999/status", timeout=0.5)
|
||||
if resp.status_code == 200:
|
||||
print(f"Hook server ready after {i*0.5}s")
|
||||
break
|
||||
except Exception:
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
print("Hook server didn't start!")
|
||||
proc.kill()
|
||||
sys.exit(1)
|
||||
|
||||
# Wait extra for imgui to fully initialize
|
||||
print("Waiting 3s for imgui to stabilize...")
|
||||
time.sleep(3.0)
|
||||
|
||||
# Now run the actual test flow
|
||||
from src.api_hook_client import ApiHookClient
|
||||
client = ApiHookClient()
|
||||
|
||||
print("\n[1] set_value show_windows {Diagnostics: True}")
|
||||
client.set_value('show_windows', {'Diagnostics': True})
|
||||
time.sleep(1.0)
|
||||
|
||||
print("\n[2] push_event save_workspace_profile")
|
||||
client.push_event('custom_callback', {'callback': 'save_workspace_profile', 'args': ['Tier3Profile', 'project']})
|
||||
time.sleep(1.0)
|
||||
|
||||
print("\n[3] set_value show_windows {Diagnostics: False}")
|
||||
client.set_value('show_windows', {'Diagnostics': False})
|
||||
|
||||
print("\n[4] set_value ui_auto_switch_layout")
|
||||
client.set_value('ui_auto_switch_layout', True)
|
||||
|
||||
print("\n[5] set_value ui_tier_layout_bindings")
|
||||
client.set_value('ui_tier_layout_bindings', {'Tier 1': '', 'Tier 2': '', 'Tier 3': 'Tier3Profile', 'Tier 4': ''})
|
||||
|
||||
def trigger_tier(tier):
|
||||
client.push_event("mma_state_update", {"status": "running", "active_tier": tier})
|
||||
|
||||
print("\n[6] trigger Tier 2")
|
||||
trigger_tier('Tier 2 (Tech Lead)')
|
||||
time.sleep(1.0)
|
||||
val = client.get_value('show_windows')
|
||||
print(f"[after Tier 2] show_windows: {val!r}")
|
||||
assert val is not None, "show_windows is None"
|
||||
assert val.get('Diagnostics', False) == False, f"Expected False, got {val}"
|
||||
|
||||
print("\n[7] trigger Tier 3")
|
||||
trigger_tier('Tier 3 (Worker): task-1')
|
||||
time.sleep(1.0)
|
||||
val = client.get_value('show_windows')
|
||||
print(f"[after Tier 3] show_windows: {val!r}")
|
||||
assert val.get('Diagnostics', False) == True, f"Expected True, got {val}"
|
||||
|
||||
print("\nALL ASSERTIONS PASSED!")
|
||||
|
||||
# Cleanup
|
||||
print("Killing sloppy.py...")
|
||||
proc.kill()
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except:
|
||||
pass
|
||||
log_file.close()
|
||||
@@ -0,0 +1,29 @@
|
||||
"""Minimal reproducer for the auto_switch_sim GUI crash."""
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
sys.path.insert(0, 'C:/projects/manual_slop')
|
||||
sys.path.insert(0, 'C:/projects/manual_slop/src')
|
||||
|
||||
from src.api_hook_client import ApiHookClient
|
||||
client = ApiHookClient()
|
||||
if not client.wait_for_server(timeout=15):
|
||||
print('FAIL: server not up')
|
||||
sys.exit(1)
|
||||
print('OK: server up')
|
||||
|
||||
print('Step 1: click btn_reset')
|
||||
client.click('btn_reset')
|
||||
time.sleep(1.0)
|
||||
print('Step 1 done, status=', client.get_value('ai_status'))
|
||||
|
||||
print('Step 2: set_value current_provider gemini_cli')
|
||||
client.set_value('current_provider', 'gemini_cli')
|
||||
time.sleep(1.0)
|
||||
print('Step 2 done')
|
||||
|
||||
print('Step 3: set_value gcli_path')
|
||||
mock_path = os.path.abspath('tests/mock_concurrent_mma.py')
|
||||
client.set_value('gcli_path', '"' + sys.executable + '" "' + mock_path + '"')
|
||||
time.sleep(1.0)
|
||||
print('Step 3 done')
|
||||
+5
-5
@@ -69,6 +69,11 @@ scale = 1.0199999809265137
|
||||
transparency = 1.0
|
||||
child_transparency = 1.0
|
||||
|
||||
[theme.tone_mapping.solarized_light]
|
||||
brightness = 0.6899999976158142
|
||||
contrast = 0.8600000143051147
|
||||
gamma = 0.7699999809265137
|
||||
|
||||
[theme.tone_mapping.moss]
|
||||
brightness = 1.059999942779541
|
||||
contrast = 0.5799999833106995
|
||||
@@ -84,11 +89,6 @@ brightness = 0.7699999809265137
|
||||
contrast = 0.7200000286102295
|
||||
gamma = 0.6899999976158142
|
||||
|
||||
[theme.tone_mapping.solarized_light]
|
||||
brightness = 0.6899999976158142
|
||||
contrast = 0.8600000143051147
|
||||
gamma = 0.7699999809265137
|
||||
|
||||
[mma]
|
||||
max_workers = 4
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@ active = "main"
|
||||
|
||||
[discussions.main]
|
||||
git_commit = ""
|
||||
last_updated = "2026-06-04T20:08:39"
|
||||
last_updated = "2026-06-05T18:41:59"
|
||||
history = []
|
||||
|
||||
+9
-9
@@ -598,15 +598,15 @@ class App:
|
||||
finally:
|
||||
self._is_applying_snapshot = False
|
||||
|
||||
def _capture_workspace_profile(self, name: str) -> models.WorkspaceProfile:
|
||||
if not getattr(self, "_ini_capture_ready", False):
|
||||
self._ini_capture_ready = True
|
||||
ini = b""
|
||||
else:
|
||||
try:
|
||||
ini = imgui.save_ini_settings_to_memory()
|
||||
except Exception:
|
||||
ini = b""
|
||||
def _capture_workspace_profile(self, name: str) -> models.WorkspaceProfile:
|
||||
if not getattr(self, "_ini_capture_ready", False):
|
||||
self._ini_capture_ready = True
|
||||
ini = ""
|
||||
else:
|
||||
try:
|
||||
ini = str(imgui.save_ini_settings_to_memory() or "")
|
||||
except Exception:
|
||||
ini = ""
|
||||
panel_states = {
|
||||
"ui_separate_context_preview": getattr(self, "ui_separate_context_preview", False),
|
||||
"ui_separate_message_panel": getattr(self, "ui_separate_message_panel", False),
|
||||
|
||||
Reference in New Issue
Block a user