feat(windows): icon, windowed exe, no-admin installer

- PyInstaller exe built windowed (console=False) with package/testium.ico
  as the embedded icon (BMP entries for shell compatibility).
- Suppress stray subprocess console windows in the frozen Windows build via
  paths.no_window_kwargs() (CREATE_NO_WINDOW); wheel/source unchanged.
  Applied to py_process, lua_process, bins probes, sys_app_path_win.
- New per-user Inno Setup installer (package/innosetup/): no admin,
  version-scoped AppId/dir so versions install side-by-side, one Start
  Menu entry per version, .ico shipped for shortcut/uninstall icons.
- DESIGN.md + release_note.txt updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 13:57:48 +02:00
parent e0802a9a72
commit 8c4e1b56b5
10 changed files with 191 additions and 6 deletions

View File

@@ -25,7 +25,7 @@ import subprocess
import tempfile
import api.testium as tm
from interpreter.utils.paths import sys_app_path_lin, sys_app_path_win
from interpreter.utils.paths import sys_app_path_lin, sys_app_path_win, no_window_kwargs
from runtime.tum_except import ETUMRuntimeError
@@ -272,6 +272,7 @@ def _run_probe(cmd):
r = subprocess.run(
cmd, capture_output=True, text=True,
encoding=tm.sys_encoding(), timeout=10, env=_probe_env(),
**no_window_kwargs(),
)
except (FileNotFoundError, PermissionError, subprocess.TimeoutExpired):
return None

View File

@@ -4,7 +4,7 @@ import subprocess
import api.testium as tm
from runtime.jrpc import JsonRpcClient
from interpreter.utils.paths import subproc_path
from interpreter.utils.paths import subproc_path, no_window_kwargs
from runtime.tum_except import ETUMRuntimeError
from interpreter.utils import bins
from interpreter.utils.proc_drain import drain_and_read_port, wait_for_port
@@ -114,6 +114,7 @@ class LuaProcessBase:
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
restore_signals=False,
**no_window_kwargs(),
**popen_kwargs,
)
# Forward subprocess output to the log and read the startup port sentinel.

View File

@@ -8,6 +8,14 @@ import subprocess
import api.testium as tm
def no_window_kwargs():
# Hide stray child consoles in the frozen Windows GUI exe (console=False has
# no console to inherit). The wheel/source keeps its console, so leave it.
if sys.platform == "win32" and getattr(sys, "frozen", False):
return {"creationflags": subprocess.CREATE_NO_WINDOW}
return {}
def testium_path():
if getattr(sys, 'frozen', False):
@@ -54,6 +62,7 @@ def sys_app_path_win(app_name):
text=True,
encoding="oem",
timeout=10,
**no_window_kwargs(),
)
data = result.stdout
except (FileNotFoundError, PermissionError, subprocess.TimeoutExpired):

View File

@@ -4,7 +4,7 @@ import subprocess
from runtime.jrpc import JsonRpcClient
import api.testium as tm
from runtime.tum_except import ETUMRuntimeError
from interpreter.utils.paths import testium_path, subproc_path
from interpreter.utils.paths import testium_path, subproc_path, no_window_kwargs
from interpreter.utils import bins
from interpreter.utils.proc_drain import drain_and_read_port, wait_for_port
@@ -97,6 +97,7 @@ class PyProcessBase:
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
restore_signals=False,
**no_window_kwargs(),
**popen_kwargs,
)
# Forward subprocess output to the log and read the startup port sentinel.