Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Agent.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,7 +118,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design:
pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.token; python -m emrg
```

Python: `uv run pytest tests/ -v` (1051) — import check: `uv run python -c "from emrg.client.app import run_client"`
Python: `uv run pytest tests/ -v` (1052) — import check: `uv run python -c "from emrg.client.app import run_client"`
GUI: `cd emrg/gui && npm test` (259: 45 daemon_client + 20 conn-manager + 22 app-commands + 129 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js`
CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文)
Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响)
Expand Down
10 changes: 10 additions & 0 deletions emrg/server/prompts/upgrade_prompt.j2
Original file line numberDiff line numberDiff line change
Expand Up@@ -51,6 +51,16 @@ release installer" means for this version.
`previous-version.txt`.
- `{{ install_dir }}/bin/` launcher scripts (emrg/emrgd/emrg.cmd/emrgd.cmd
etc.) — sync if the target tag changed them.
- `{{ install_dir }}/bin/pyvenv.cfg` — Windows layout requirement (rant
2026-08-24T21:46:53, follow-up to #966): `bin\python.exe` / `bin\python3.exe`
are copies of the standalone interpreter and need a same-directory
`pyvenv.cfg` to locate the stdlib inside `bin\python-dist\`. Write it
idempotently with the **native absolute path** (backslashes on Windows),
i.e. one line: `home = {{ install_dir }}\bin\python-dist` — expand
{{ install_dir }} to the real path at runtime. A relative `home` fails with
"Fatal Python error: Failed to import encodings" — never use a relative
path. On POSIX layouts skip this file (the `bin/python` wrapper already
handles stdlib discovery).
- GUI **must be synced too** (rant 2026-08-24T17:50: GUI packages had been
stuck at 0.2.72 while the daemon moved on — the old "no node/npm, skip"
reasoning was a false premise: node/npm exist on the host (asdf), they are
Expand Down
21 changes: 21 additions & 0 deletions packaging/make-installer.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -376,10 +376,31 @@ begin
BroadcastEnvironmentChange;
end;

// R131: 安装后写 {app}\bin\pyvenv.cfg(rant 2026-08-24T21:46:53,#966 的
// Windows 后续)。bin\python.exe / python3.exe 是 python-dist 解释器的复制品,
// 需要同目录 pyvenv.cfg 才能定位标准库(CPython 在 exe 所在目录查找
// pyvenv.cfg,home 指向 python-dist)。home 必须为绝对路径——相对路径实测
// Fatal Python error: Failed to import encodings(venv 内 python 无法定位
// 标准库,任务无法安装科研依赖)。pyvenv.cfg 不在 payload 里(build-runtime
// 不生成),由安装器 ssPostInstall 写入;升级安装覆盖同内容,幂等;
// 卸载由 [UninstallDelete] 连同 {app} 一起删除。
procedure WritePyvenvCfg;
var
CfgPath: string;
CfgContent: AnsiString;
begin
CfgPath := ExpandConstant('{app}\bin\pyvenv.cfg');
CfgContent := 'home = ' + ExpandConstant('{app}\bin\python-dist') + #13#10;
SaveStringToFile(CfgPath, CfgContent, False);
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
WritePyvenvCfg;
AddBinDirToPath;
end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
Expand Down
19 changes: 16 additions & 3 deletions packaging/smoke-test.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -185,11 +185,24 @@ else
fi

# 14. bundled python venv(rant 2026-08-24T21:46:53:bin/python 软链 → wrapper,
# pyvenv.cfg home 修复)。回归用例:install python 创建 venv 后必须能导入标准库
# + pip 可用。Windows 用 python-dist 根 exe(bin/python.exe 复制品缺 DLL,R100)。
# pyvenv.cfg home 修复;Windows 后续:bin\python.exe 复制品依赖同目录
# bin\pyvenv.cfg 定位标准库)。回归用例:install python 创建 venv 后必须能
# 导入标准库 + pip 可用。POSIX 走 bin/python wrapper(#966);Windows 走
# bin\python.exe 本体——先复刻安装器 [Code] ssPostInstall 写的 bin\pyvenv.cfg
# (home = 绝对路径;相对路径实测 "Failed to import encodings"),再验证。
say "14. bundled python venv (pyvenv.cfg home fix)"
PY_BIN="$HOME/.emrg/install/bin/python"
if [ -e "$HOME/.emrg/install/bin/python-dist/python.exe" ]; then
if [ -n "${WINDIR:-}" ]; then
# R131:dist/runtime 未经安装器(pyvenv.cfg 由 make-installer.sh [Code] 在
# ssPostInstall 写入),smoke 在此复刻同款内容。有了 cfg 后 bin\python.exe
# 本体即可用(R100 "缺 DLL" 结论修正:DLL 同在 bin\,真正缺的是 cfg)。
INSTALL_BIN_WIN="$(cygpath -w "$HOME/.emrg/install/bin")"
printf 'home = %s\\python-dist\n' "$INSTALL_BIN_WIN" > "$HOME/.emrg/install/bin/pyvenv.cfg"
PY_BIN="$HOME/.emrg/install/bin/python.exe"
if [ ! -e "$PY_BIN" ]; then
PY_BIN="$HOME/.emrg/install/bin/python-dist/python.exe"
fi
elif [ -e "$HOME/.emrg/install/bin/python-dist/python.exe" ]; then
PY_BIN="$HOME/.emrg/install/bin/python-dist/python.exe"
elif [ -e "$HOME/.emrg/install/bin/python-dist/python3.13.exe" ]; then
PY_BIN="$HOME/.emrg/install/bin/python-dist/python3.13.exe"
Expand Down
34 changes: 34 additions & 0 deletions tests/test_installer_stop.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,40 @@ def test_make_installer_iss_has_prepare_to_install():
assert "restart the computer" in content


def test_make_installer_iss_writes_pyvenv_cfg():
"""rant 2026-08-24T21:46:53 — #966 的 Windows 后续:bin\\python.exe / python3.exe
是 python-dist 解释器的复制品,缺同目录 bin\\pyvenv.cfg → venv 内 python 无法
定位标准库(Could not find platform independent libraries + No module named
'encodings')。修复 = 安装器 [Code] ssPostInstall 写 bin\\pyvenv.cfg
(home 指向 {app}\\bin\\python-dist 绝对路径;相对路径实测 "Failed to import
encodings")。纯文本断言钉死接线(不执行 iscc/cmd —— macOS/CI 无 Windows)。
"""
content = _read("packaging/make-installer.sh")
# WritePyvenvCfg 过程:SaveStringToFile 的 S 参数是 AnsiString(与 LogText 同规,
# 6.7.1 → 7.x 全版本一致);UnicodeString 不匹配 → 声明 AnsiString 变量
assert "procedure WritePyvenvCfg;" in content
assert "CfgContent: AnsiString;" in content
assert "CfgContent: string;" not in content
assert "SaveStringToFile(CfgPath, CfgContent, False)" in content
# 写 {app}\\bin\\pyvenv.cfg,home = 绝对路径(ExpandConstant 展开 {app})
assert "ExpandConstant('{app}\\bin\\pyvenv.cfg')" in content
assert "CfgContent := 'home = ' + ExpandConstant('{app}\\bin\\python-dist')" in content
# ssPostInstall 钩子:先写 cfg 再补 PATH(同一个 CurStepChanged)
step_src = content.split("procedure CurStepChanged")[1].split("procedure CurUninstallStepChanged")[0]
assert "WritePyvenvCfg;" in step_src
assert "AddBinDirToPath;" in step_src
assert step_src.index("WritePyvenvCfg;") < step_src.index("AddBinDirToPath;")
# smoke-test.sh:Windows 分支复刻同款 cfg(home 绝对路径)再验证 venv
smoke = _read("packaging/smoke-test.sh")
assert 'if [ -n "${WINDIR:-}" ]; then' in smoke
assert "printf 'home = %s\\\\python-dist\\n'" in smoke
assert 'PY_BIN="$HOME/.emrg/install/bin/python.exe"' in smoke
# upgrade_prompt.j2:本地等价安装也要写 bin\\pyvenv.cfg(绝对 home)
prompt = _read("emrg/server/prompts/upgrade_prompt.j2")
assert "bin/pyvenv.cfg" in prompt
assert "home = {{ install_dir }}\\bin\\python-dist" in prompt


def test_make_installer_iss_old_python_health_check():
"""rant 2026-08-19T00:44:52 — 安装器韧性:旧版 python-dist 损坏(encodings 崩,
v0.2.49/v0.2.50 -I 事故遗留)时,升级安装不得因坏 python 硬中止。
Expand Down
Loading