Private
Public Access
Merge remote-tracking branch 'tier2-clone/tier2/default_layout_install_20260629' into tier2/default_layout_install_20260629
This commit is contained in:
+46
-45
@@ -4,22 +4,19 @@
|
|||||||
;;; missing/empty/small).
|
;;; missing/empty/small).
|
||||||
;;;
|
;;;
|
||||||
;;; Mechanism: HelloImGui reads this INI at app startup via the
|
;;; Mechanism: HelloImGui reads this INI at app startup via the
|
||||||
;;; ini_folder_type/ini_filename on the RunnerParams. The DockSpace ID,
|
;;; ini_folder_type/ini_filename on the RunnerParams. The DockSpace ID
|
||||||
;;; DockNode IDs, and per-window DockId lines below tell HelloImgui where
|
;;; 0xAFC85805 (= decimal 2949142533) is the runtime-generated MainDockSpace
|
||||||
;;; to place each panel. The literal IDs (0xAFC85805, 0x00000001,
|
;;; ID. The nested DockNode tree creates a 2-column layout:
|
||||||
;;; 0x00000002) match the runtime-generated MainDockSpace ID (decimal
|
;;; - LEFT column (DockNode 0x10, CentralNode=1): tabs for Theme, Project
|
||||||
;;; 2949142533) that HelloImGui computes deterministically per session.
|
;;; Settings, AI Settings, Files & Media, Operations Hub
|
||||||
|
;;; - RIGHT column (DockNode 0x01): tabs for Discussion Hub, Log
|
||||||
|
;;; Management, Diagnostics
|
||||||
;;;
|
;;;
|
||||||
;;; Window list matches the post-config-merge effective visibility set
|
;;; The nested structure (DockSpace -> DockNode 0x03 -> DockNode 0x0B ->
|
||||||
;;; (8 default-true windows excluding Response (stale) and the four
|
;;; DockNode 0x05 -> DockNode 0x10) is REQUIRED for HelloImGui to honor
|
||||||
;;; Tier panels (disabled in config.toml)):
|
;;; the docking. A simpler "DockSpace + 2 direct children" structure is
|
||||||
;;; Project Settings, Files & Media, AI Settings, AI operations,
|
;;; silently ignored by HelloImGui (verified empirically — runtime INI
|
||||||
;;; Discussion Hub, Operations Hub, Theme, Log Management, Diagnostics.
|
;;; shows DockSpace with no DockNodes, all windows float).
|
||||||
;;; Per-window DockId:
|
|
||||||
;;; 0x00000001,0..4 = left column tabs (Theme, Project Settings,
|
|
||||||
;;; AI Settings, Files & Media, Operations Hub)
|
|
||||||
;;; 0x00000002,0..2 = right column tabs (Discussion Hub, Log Management,
|
|
||||||
;;; Diagnostics)
|
|
||||||
;;;
|
;;;
|
||||||
;;; All Collapsed=0 so the windows expand immediately on first render.
|
;;; All Collapsed=0 so the windows expand immediately on first render.
|
||||||
;;;
|
;;;
|
||||||
@@ -30,65 +27,70 @@
|
|||||||
;;;
|
;;;
|
||||||
;;; To iterate on this layout: open sloppy.py, arrange windows as
|
;;; To iterate on this layout: open sloppy.py, arrange windows as
|
||||||
;;; desired, quit (HelloImGui auto-saves), then copy the resulting
|
;;; desired, quit (HelloImGui auto-saves), then copy the resulting
|
||||||
;;; cwd/manualslop_layout.ini over this one. (HelloImGui adds SplitsIds,
|
;;; cwd/manualslop_layout.ini over this one.
|
||||||
;;; Tables, and other internal sections on save; the bundled default
|
|
||||||
;;; version is the minimal scaffold needed for first-run visibility.)
|
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
[Window][Project Settings]
|
[Window][Project Settings]
|
||||||
Pos=0,28
|
Pos=0,28
|
||||||
Size=481,1172
|
Size=881,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,1
|
DockId=0x00000010,1
|
||||||
|
|
||||||
[Window][Files & Media]
|
[Window][Files & Media]
|
||||||
Pos=0,28
|
Pos=0,28
|
||||||
Size=481,1172
|
Size=881,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,3
|
DockId=0x00000010,2
|
||||||
|
|
||||||
[Window][AI Settings]
|
[Window][AI Settings]
|
||||||
Pos=0,28
|
Pos=0,28
|
||||||
Size=481,1172
|
Size=881,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,2
|
DockId=0x00000010,3
|
||||||
|
|
||||||
[Window][Operations Hub]
|
[Window][Operations Hub]
|
||||||
Pos=0,28
|
Pos=0,28
|
||||||
Size=481,1172
|
Size=881,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,4
|
DockId=0x00000010,4
|
||||||
|
|
||||||
[Window][Theme]
|
[Window][Theme]
|
||||||
Pos=0,28
|
Pos=0,28
|
||||||
Size=481,1172
|
Size=881,1697
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000010,0
|
||||||
|
|
||||||
|
[Window][Discussion Hub]
|
||||||
|
Pos=883,28
|
||||||
|
Size=1183,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,0
|
DockId=0x00000001,0
|
||||||
|
|
||||||
[Window][Discussion Hub]
|
|
||||||
Pos=483,28
|
|
||||||
Size=1197,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000002,0
|
|
||||||
|
|
||||||
[Window][Log Management]
|
[Window][Log Management]
|
||||||
Pos=483,28
|
Pos=883,28
|
||||||
Size=1197,1172
|
Size=1183,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,1
|
DockId=0x00000001,1
|
||||||
|
|
||||||
[Window][Diagnostics]
|
[Window][Diagnostics]
|
||||||
Pos=483,28
|
Pos=883,28
|
||||||
Size=1197,1172
|
Size=1183,1697
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,2
|
DockId=0x00000001,2
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=1680,1172 Split=X
|
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=1680,1172 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0xAFC85805 SizeRef=481,1172 CentralNode=1 Selected=0x3F1379AF
|
DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2357,1183 Split=X
|
||||||
DockNode ID=0x00000002 Parent=0xAFC85805 SizeRef=1197,1172 Selected=0xB4CBF21A
|
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2
|
||||||
|
DockNode ID=0x00000005 Parent=0x0000000B SizeRef=820,1681 Split=Y Selected=0x3F1379AF
|
||||||
|
DockNode ID=0x00000010 Parent=0x00000005 SizeRef=983,1140 CentralNode=1 Selected=0x3F1379AF
|
||||||
|
DockNode ID=0x00000011 Parent=0x00000005 SizeRef=983,184 Selected=0x432BAE4E
|
||||||
|
DockNode ID=0x00000006 Parent=0x0000000B SizeRef=1754,1681 Split=X Selected=0x6F2B5B04
|
||||||
|
DockNode ID=0x00000001 Parent=0x00000006 SizeRef=1183,1924 Selected=0xB4CBF21A
|
||||||
|
DockNode ID=0x00000002 Parent=0x00000006 SizeRef=569,1924 Selected=0x0D5A5273
|
||||||
|
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
|
||||||
|
DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=488,1183 Selected=0x3AEC3498
|
||||||
|
|
||||||
;;;<<<HelloImGui_Misc>>>;;;
|
|
||||||
[Layout]
|
[Layout]
|
||||||
Name=Default
|
Name=Default
|
||||||
[StatusBar]
|
[StatusBar]
|
||||||
@@ -97,5 +99,4 @@ ShowFps=true
|
|||||||
[Theme]
|
[Theme]
|
||||||
Name=ImGuiColorsDark
|
Name=ImGuiColorsDark
|
||||||
|
|
||||||
;;;<<<SplitIds>>>;;;
|
{"gImGuiSplitIDs":{"MainDockSpace":2949142533}}
|
||||||
{"gImGuiSplitIDs":{"MainDockSpace":2949142533}}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
;;;
|
|
||||||
;;; Manual Slop default docking layout for live_gui test sessions AND
|
|
||||||
;;; first-run production launches (when cwd/manualslop_layout.ini is
|
|
||||||
;;; missing/empty/small).
|
|
||||||
;;;
|
|
||||||
;;; Mechanism: HelloImGui reads this INI at app startup via the
|
|
||||||
;;; ini_folder_type/ini_filename on the RunnerParams. The DockSpace ID,
|
|
||||||
;;; DockNode IDs, and per-window DockId lines below tell HelloImgui where
|
|
||||||
;;; to place each panel. The literal IDs (0xAFC85805, 0x00000001,
|
|
||||||
;;; 0x00000002) match the runtime-generated MainDockSpace ID (decimal
|
|
||||||
;;; 2949142533) that HelloImGui computes deterministically per session.
|
|
||||||
;;;
|
|
||||||
;;; Window list matches the post-config-merge effective visibility set
|
|
||||||
;;; (8 default-true windows excluding Response (stale) and the four
|
|
||||||
;;; Tier panels (disabled in config.toml)):
|
|
||||||
;;; Project Settings, Files & Media, AI Settings, AI operations,
|
|
||||||
;;; Discussion Hub, Operations Hub, Theme, Log Management, Diagnostics.
|
|
||||||
;;; Per-window DockId:
|
|
||||||
;;; 0x00000001,0..4 = left column tabs (Theme, Project Settings,
|
|
||||||
;;; AI Settings, Files & Media, Operations Hub)
|
|
||||||
;;; 0x00000002,0..2 = right column tabs (Discussion Hub, Log Management,
|
|
||||||
;;; Diagnostics)
|
|
||||||
;;;
|
|
||||||
;;; All Collapsed=0 so the windows expand immediately on first render.
|
|
||||||
;;;
|
|
||||||
;;; This INI does NOT include any of the _STALE_WINDOW_NAMES from
|
|
||||||
;;; src/gui_2.py:603-607 (Projects, Files, Screenshots, Discussion History,
|
|
||||||
;;; Provider, Message, Response, Tool Calls, Comms History, System Prompts).
|
|
||||||
;;; _diag_layout_state will not emit a "stale window name" warning.
|
|
||||||
;;;
|
|
||||||
;;; To iterate on this layout: open sloppy.py, arrange windows as
|
|
||||||
;;; desired, quit (HelloImGui auto-saves), then copy the resulting
|
|
||||||
;;; cwd/manualslop_layout.ini over this one. (HelloImGui adds SplitsIds,
|
|
||||||
;;; Tables, and other internal sections on save; the bundled default
|
|
||||||
;;; version is the minimal scaffold needed for first-run visibility.)
|
|
||||||
;;;
|
|
||||||
|
|
||||||
[Window][Project Settings]
|
|
||||||
Pos=0,28
|
|
||||||
Size=481,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,1
|
|
||||||
|
|
||||||
[Window][Files & Media]
|
|
||||||
Pos=0,28
|
|
||||||
Size=481,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,3
|
|
||||||
|
|
||||||
[Window][AI Settings]
|
|
||||||
Pos=0,28
|
|
||||||
Size=481,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,2
|
|
||||||
|
|
||||||
[Window][Operations Hub]
|
|
||||||
Pos=0,28
|
|
||||||
Size=481,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,4
|
|
||||||
|
|
||||||
[Window][Theme]
|
|
||||||
Pos=0,28
|
|
||||||
Size=481,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,0
|
|
||||||
|
|
||||||
[Window][Discussion Hub]
|
|
||||||
Pos=483,28
|
|
||||||
Size=1197,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000002,0
|
|
||||||
|
|
||||||
[Window][Log Management]
|
|
||||||
Pos=483,28
|
|
||||||
Size=1197,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000002,1
|
|
||||||
|
|
||||||
[Window][Diagnostics]
|
|
||||||
Pos=483,28
|
|
||||||
Size=1197,1172
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000002,2
|
|
||||||
|
|
||||||
[Docking][Data]
|
|
||||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=1680,1172 Split=X
|
|
||||||
DockNode ID=0x00000001 Parent=0xAFC85805 SizeRef=481,1172 CentralNode=1 Selected=0x3F1379AF
|
|
||||||
DockNode ID=0x00000002 Parent=0xAFC85805 SizeRef=1197,1172 Selected=0xB4CBF21A
|
|
||||||
|
|
||||||
;;;<<<HelloImGui_Misc>>>;;;
|
|
||||||
[Layout]
|
|
||||||
Name=Default
|
|
||||||
[StatusBar]
|
|
||||||
Show=false
|
|
||||||
ShowFps=true
|
|
||||||
[Theme]
|
|
||||||
Name=ImGuiColorsDark
|
|
||||||
|
|
||||||
;;;<<<SplitIds>>>;;;
|
|
||||||
{"gImGuiSplitIDs":{"MainDockSpace":2949142533}}
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
"""Find the orphan by disabling each default-visible window in turn via API hook."""
|
||||||
|
import sys, time, subprocess, json, urllib.request, shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PROJ = Path("C:/projects/manual_slop_tier2")
|
||||||
|
|
||||||
|
VISIBLE = [
|
||||||
|
"AI Settings",
|
||||||
|
"Diagnostics",
|
||||||
|
"Discussion Hub",
|
||||||
|
"Files & Media",
|
||||||
|
"Log Management",
|
||||||
|
"Operations Hub",
|
||||||
|
"Project Settings",
|
||||||
|
"Response",
|
||||||
|
"Theme",
|
||||||
|
]
|
||||||
|
|
||||||
|
def make_wrapper(visible):
|
||||||
|
return '''
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, "C:/projects/manual_slop_tier2")
|
||||||
|
sys.argv = ["sloppy.py", "--enable-test-hooks"]
|
||||||
|
from src.gui_2 import App as _App
|
||||||
|
_orig_init = _App.__init__
|
||||||
|
def _patched_init(self, *a, **kw):
|
||||||
|
_orig_init(self, *a, **kw)
|
||||||
|
for k in list(self.show_windows.keys()):
|
||||||
|
self.show_windows[k] = False
|
||||||
|
for k in %r:
|
||||||
|
if k in self.show_windows:
|
||||||
|
self.show_windows[k] = True
|
||||||
|
_App.__init__ = _patched_init
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
from src.paths import initialize_paths
|
||||||
|
initialize_paths(None)
|
||||||
|
from src.gui_2 import main as _sloppy_main
|
||||||
|
_sloppy_main()
|
||||||
|
''' % visible
|
||||||
|
|
||||||
|
def run_test(visible_subset, label, wait_after_health=6):
|
||||||
|
WORK = PROJ / "tests" / "artifacts" / f"diag4_{label}"
|
||||||
|
LOG = PROJ / "tests" / "artifacts" / f"diag4_{label}.log"
|
||||||
|
if WORK.exists():
|
||||||
|
shutil.rmtree(WORK)
|
||||||
|
WORK.mkdir(parents=True, exist_ok=True)
|
||||||
|
if LOG.exists():
|
||||||
|
LOG.unlink()
|
||||||
|
WRAP = PROJ / "tests" / "artifacts" / f"diag4_wrap_{label}.py"
|
||||||
|
WRAP.write_text(make_wrapper(visible_subset), encoding='utf-8')
|
||||||
|
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["uv", "run", "python", "-u", str(WRAP.absolute())],
|
||||||
|
stdout=open(LOG, "w"),
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=str(WORK),
|
||||||
|
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if sys.platform == "win32" else 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
ready = False
|
||||||
|
for i in range(30):
|
||||||
|
time.sleep(0.5)
|
||||||
|
try:
|
||||||
|
urllib.request.urlopen("http://127.0.0.1:8999/status", timeout=1)
|
||||||
|
ready = True
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not ready:
|
||||||
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False)
|
||||||
|
time.sleep(1)
|
||||||
|
return "NO_HOOK"
|
||||||
|
|
||||||
|
# Wait for first frame to render
|
||||||
|
time.sleep(wait_after_health)
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/gui_health", timeout=2)
|
||||||
|
body = json.loads(r.read().decode())
|
||||||
|
except Exception:
|
||||||
|
body = {"healthy": None}
|
||||||
|
|
||||||
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False)
|
||||||
|
time.sleep(1)
|
||||||
|
return "HEALTHY" if body.get("healthy") else f"DEGRADED: {body.get('degraded_reason', '')[:80]}"
|
||||||
|
|
||||||
|
|
||||||
|
print("BASELINE (all 9 visible):", flush=True)
|
||||||
|
print(f" -> {run_test(VISIBLE, 'all')}", flush=True)
|
||||||
|
|
||||||
|
for skip in VISIBLE:
|
||||||
|
visible_subset = [w for w in VISIBLE if w != skip]
|
||||||
|
print(f"DISABLE {skip}:", flush=True)
|
||||||
|
print(f" -> {run_test(visible_subset, f'skip_{skip.replace(chr(32), chr(95)).replace(chr(58), chr(95))}')}", flush=True)
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
"""Quick diagnostic: start sloppy.py as subprocess, hit /api/gui_health, print everything."""
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PROJ = Path("C:/projects/manual_slop_tier2")
|
||||||
|
WORK = PROJ / "tests" / "artifacts" / "diag_workspace"
|
||||||
|
LOG = PROJ / "tests" / "artifacts" / "diag_sloppy.log"
|
||||||
|
|
||||||
|
# Clean workspace
|
||||||
|
import shutil
|
||||||
|
if WORK.exists():
|
||||||
|
shutil.rmtree(WORK)
|
||||||
|
WORK.mkdir(parents=True, exist_ok=True)
|
||||||
|
if LOG.exists():
|
||||||
|
LOG.unlink()
|
||||||
|
|
||||||
|
# Spawn
|
||||||
|
print(f"Starting sloppy.py in {WORK}...", flush=True)
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["uv", "run", "python", "-u", str(PROJ / "sloppy.py"), "--enable-test-hooks"],
|
||||||
|
stdout=open(LOG, "w"),
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=str(WORK),
|
||||||
|
)
|
||||||
|
print(f"PID: {proc.pid}", flush=True)
|
||||||
|
|
||||||
|
# Wait for hook server
|
||||||
|
ready = False
|
||||||
|
for i in range(30):
|
||||||
|
time.sleep(1.0)
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/status", timeout=2)
|
||||||
|
ready = True
|
||||||
|
print(f"Hook server ready after {i+1}s", flush=True)
|
||||||
|
print(f" /status: {r.read().decode()}", flush=True)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
if i % 5 == 0:
|
||||||
|
print(f" waiting ({i+1}s)... {e.__class__.__name__}", flush=True)
|
||||||
|
|
||||||
|
if not ready:
|
||||||
|
print("Hook server never came up!", flush=True)
|
||||||
|
|
||||||
|
# Get health
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/gui_health", timeout=2)
|
||||||
|
body = r.read().decode()
|
||||||
|
print(f"\n/api/gui_health: {body}", flush=True)
|
||||||
|
data = json.loads(body)
|
||||||
|
print(f" healthy: {data.get('healthy')}", flush=True)
|
||||||
|
print(f" degraded_reason: {data.get('degraded_reason')!r}", flush=True)
|
||||||
|
print(f" last_assert: {data.get('last_assert')!r}", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"health check failed: {e}", flush=True)
|
||||||
|
|
||||||
|
# Get startup timeline
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/startup_timeline", timeout=2)
|
||||||
|
print(f"\n/api/startup_timeline: {r.read().decode()}", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"startup_timeline failed: {e}", flush=True)
|
||||||
|
|
||||||
|
# Get warmup status
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/warmup_status", timeout=2)
|
||||||
|
print(f"\n/api/warmup_status: {r.read().decode()}", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"warmup_status failed: {e}", flush=True)
|
||||||
|
|
||||||
|
# Give it another 5 seconds to render
|
||||||
|
print("\nWaiting 5s for first frame...", flush=True)
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# Re-check health
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/gui_health", timeout=2)
|
||||||
|
body = r.read().decode()
|
||||||
|
print(f"\n/api/gui_health (after 5s): {body}", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"re-check health failed: {e}", flush=True)
|
||||||
|
|
||||||
|
# Kill
|
||||||
|
print(f"\nKilling PID {proc.pid}...", flush=True)
|
||||||
|
try:
|
||||||
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], check=False)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"taskkill failed: {e}", flush=True)
|
||||||
|
|
||||||
|
# Print log
|
||||||
|
print("\n=== STDOUT/STDERR LOG ===", flush=True)
|
||||||
|
print(LOG.read_text(encoding="utf-8", errors="replace"))
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
"""Diagnostic: disable each default-visible window one at a time, find which fixes the error."""
|
||||||
|
import sys, time, subprocess, json, urllib.request, shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PROJ = Path("C:/projects/manual_slop_tier2")
|
||||||
|
|
||||||
|
# Default-visible windows per the diag log
|
||||||
|
VISIBLE = [
|
||||||
|
"AI Settings",
|
||||||
|
"Diagnostics",
|
||||||
|
"Discussion Hub",
|
||||||
|
"Files & Media",
|
||||||
|
"Log Management",
|
||||||
|
"Operations Hub",
|
||||||
|
"Project Settings",
|
||||||
|
"Response",
|
||||||
|
"Theme",
|
||||||
|
]
|
||||||
|
|
||||||
|
def make_wrapper(visible):
|
||||||
|
"""Build a wrapper that monkey-patches show_windows before App() is constructed."""
|
||||||
|
visible_set = set(visible)
|
||||||
|
return '''
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, "C:/projects/manual_slop_tier2")
|
||||||
|
sys.argv = ["sloppy.py", "--enable-test-hooks"]
|
||||||
|
from src.gui_2 import App as _App
|
||||||
|
_orig_init = _App.__init__
|
||||||
|
def _patched_init(self, *a, **kw):
|
||||||
|
_orig_init(self, *a, **kw)
|
||||||
|
for k in list(self.show_windows.keys()):
|
||||||
|
self.show_windows[k] = False
|
||||||
|
for k in %r:
|
||||||
|
if k in self.show_windows:
|
||||||
|
self.show_windows[k] = True
|
||||||
|
_App.__init__ = _patched_init
|
||||||
|
|
||||||
|
# Replicate sloppy.py main path
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
from src.paths import initialize_paths
|
||||||
|
initialize_paths(None)
|
||||||
|
from src.gui_2 import main as _sloppy_main
|
||||||
|
_sloppy_main()
|
||||||
|
''' % visible
|
||||||
|
|
||||||
|
def run_diag(visible_subset, label):
|
||||||
|
WORK = PROJ / "tests" / "artifacts" / f"diag3_{label}"
|
||||||
|
LOG = PROJ / "tests" / "artifacts" / f"diag3_{label}.log"
|
||||||
|
if WORK.exists():
|
||||||
|
shutil.rmtree(WORK)
|
||||||
|
WORK.mkdir(parents=True, exist_ok=True)
|
||||||
|
if LOG.exists():
|
||||||
|
LOG.unlink()
|
||||||
|
WRAP = PROJ / "tests" / "artifacts" / f"diag3_wrap_{label}.py"
|
||||||
|
WRAP.write_text(make_wrapper(visible_subset), encoding='utf-8')
|
||||||
|
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["uv", "run", "python", "-u", str(WRAP.absolute())],
|
||||||
|
stdout=open(LOG, "w"),
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=str(WORK),
|
||||||
|
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if sys.platform == "win32" else 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
ready = False
|
||||||
|
for i in range(15):
|
||||||
|
time.sleep(0.5)
|
||||||
|
try:
|
||||||
|
urllib.request.urlopen("http://127.0.0.1:8999/status", timeout=1)
|
||||||
|
ready = True
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not ready:
|
||||||
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False)
|
||||||
|
time.sleep(1)
|
||||||
|
return "NO_HOOK"
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/gui_health", timeout=2)
|
||||||
|
body = json.loads(r.read().decode())
|
||||||
|
except Exception:
|
||||||
|
body = {"healthy": None}
|
||||||
|
|
||||||
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False)
|
||||||
|
time.sleep(1)
|
||||||
|
return "HEALTHY" if body.get("healthy") else f"DEGRADED: {body.get('degraded_reason', '')[:60]}"
|
||||||
|
|
||||||
|
# Baseline: all 9 visible
|
||||||
|
print("BASELINE (all 9 visible):")
|
||||||
|
result = run_diag(VISIBLE, "all")
|
||||||
|
print(f" -> {result}")
|
||||||
|
|
||||||
|
# Disable each one
|
||||||
|
for skip in VISIBLE:
|
||||||
|
visible_subset = [w for w in VISIBLE if w != skip]
|
||||||
|
print(f"DISABLE {skip}:")
|
||||||
|
result = run_diag(visible_subset, f"skip_{skip.replace(' ', '_').replace(':', '')}")
|
||||||
|
print(f" -> {result}")
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
"""Find the exact unbalanced begin/end by monkey-patching imgui."""
|
||||||
|
import sys, json, time, subprocess, urllib.request, traceback
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PROJ = Path("C:/projects/manual_slop_tier2")
|
||||||
|
WORK = PROJ / "tests" / "artifacts" / "diag2_workspace"
|
||||||
|
LOG = PROJ / "tests" / "artifacts" / "diag2_sloppy.log"
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
if WORK.exists():
|
||||||
|
shutil.rmtree(WORK)
|
||||||
|
WORK.mkdir(parents=True, exist_ok=True)
|
||||||
|
if LOG.exists():
|
||||||
|
LOG.unlink()
|
||||||
|
|
||||||
|
WRAPPER = PROJ / "tests" / "artifacts" / "diag2_wrapper.py"
|
||||||
|
# Wrapper content is pre-written; this script just runs it.
|
||||||
|
|
||||||
|
# Spawn the wrapper
|
||||||
|
print(f"Starting wrapper in {WORK}...", flush=True)
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["uv", "run", "python", "-u", str(WRAPPER.absolute())],
|
||||||
|
stdout=open(LOG, "w"),
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=str(WORK),
|
||||||
|
)
|
||||||
|
print(f"PID: {proc.pid}", flush=True)
|
||||||
|
|
||||||
|
# Wait for hook server
|
||||||
|
ready = False
|
||||||
|
for i in range(30):
|
||||||
|
time.sleep(1.0)
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/status", timeout=2)
|
||||||
|
ready = True
|
||||||
|
print(f"Hook server ready after {i+1}s", flush=True)
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not ready:
|
||||||
|
print("Hook server never came up!", flush=True)
|
||||||
|
else:
|
||||||
|
# Get health
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen("http://127.0.0.1:8999/api/gui_health", timeout=2)
|
||||||
|
body = r.read().decode()
|
||||||
|
print(f"health: {body}", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"health failed: {e}", flush=True)
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
# Kill
|
||||||
|
print(f"\nKilling PID {proc.pid}...", flush=True)
|
||||||
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], check=False)
|
||||||
|
|
||||||
|
# Print log (only the IMGUI lines)
|
||||||
|
print("\n=== IMGUI TRACE ===", flush=True)
|
||||||
|
content = LOG.read_text(encoding="utf-8", errors="replace")
|
||||||
|
for line in content.splitlines():
|
||||||
|
if "imgui-error" in line or "Missing End" in line or "MAIN_CALL" in line or "first frame" in line or "first _gui_func" in line:
|
||||||
|
print(line, flush=True)
|
||||||
|
|
||||||
|
# Also dump the FULL log
|
||||||
|
print("\n=== FULL LOG (last 50 lines) ===", flush=True)
|
||||||
|
for line in content.splitlines()[-50:]:
|
||||||
|
print(line, flush=True)
|
||||||
@@ -580,6 +580,19 @@ class App:
|
|||||||
if not install_result.ok:
|
if not install_result.ok:
|
||||||
if not hasattr(self, "_startup_timeline_errors"): self._startup_timeline_errors = []
|
if not hasattr(self, "_startup_timeline_errors"): self._startup_timeline_errors = []
|
||||||
self._startup_timeline_errors.append(("_install_default_layout", install_result.errors[0]))
|
self._startup_timeline_errors.append(("_install_default_layout", install_result.errors[0]))
|
||||||
|
# Always re-apply the bundled layout to the live imgui session after
|
||||||
|
# the first frame is rendered. HelloImGui reads ini_filename from disk
|
||||||
|
# BEFORE post_init fires (during immapp.run's load_user_pref phase),
|
||||||
|
# so even a perfect on-disk INI may not be honored unless we also
|
||||||
|
# apply it via imgui.load_ini_settings_from_memory here. The pre-run
|
||||||
|
# install writes the INI for the NEXT launch; this live apply
|
||||||
|
# makes the CURRENT launch render the bundled layout correctly.
|
||||||
|
try:
|
||||||
|
src_text = src_layout_path.read_text(encoding="utf-8", errors="replace")
|
||||||
|
imgui.load_ini_settings_from_memory(src_text)
|
||||||
|
except OSError as e:
|
||||||
|
if not hasattr(self, "_startup_timeline_errors"): self._startup_timeline_errors = []
|
||||||
|
self._startup_timeline_errors.append(("_post_init.live_apply", str(e)))
|
||||||
if hasattr(self.controller, "on_warmup_complete"):
|
if hasattr(self.controller, "on_warmup_complete"):
|
||||||
cb_result = _post_init_callback_result(self)
|
cb_result = _post_init_callback_result(self)
|
||||||
if not cb_result.ok:
|
if not cb_result.ok:
|
||||||
|
|||||||
Reference in New Issue
Block a user