Skip to content

fix: Windows runtime — GBK encoding & cross-platform tool detection - #5

Open
minzorty wants to merge 2 commits into
taxueseek:mainfrom
minzorty:fix/windows-runtime
Open

fix: Windows runtime — GBK encoding & cross-platform tool detection#5
minzorty wants to merge 2 commits into
taxueseek:mainfrom
minzorty:fix/windows-runtime

Conversation

@minzorty

Copy link
Copy Markdown

What

Make argo actually run on Windows (win11 + Python 3.12, npm-installed package).

  • bin/argo.js: spawn env 注入 PYTHONUTF8=1(PEP 540 UTF-8 模式),官方入口下所有子进程文件读写/解码统一 UTF-8
  • scripts/mcp_server.py: 入口 re-exec 守卫 —— 直接 python mcp_server.py 且非 UTF-8 模式时 execv 自身加 -X utf8(stdio 句柄继承,管道语义不变)
  • tfidf_router.py / quota.py / argo_engine_registry.py: 6 处含中文 JSON 读取 read_text()read_bytes()(JSON 规范自检编码,还能吃 BOM)
  • sub-skills/local-seek/scripts/seek.py:
    • tool_exists 由 Unix shell 内建 command -v 改为 shutil.which(Windows 下 command 不存在,导致永远误判 rg 缺失而落到 macOS 专属的 mdfind)
    • /dev/nullos.devnull
    • 无 rg 时的兜底由 mdfind 改为 GNU grep 递归:PATH 优先,Windows 下自动探测 Git for Windows 自带的 usr/bin/grep.exe;输出与 rg --no-heading 同构复用解析;正则失败回退 -F
    • 入口重配 stdout/stderr 为 UTF-8;中央 run() 显式 encoding="utf-8", errors="replace"(库导入 / CLI 直跑形态的独立防线)
  • health_probe.py: which 命令探测改为 shutil.which

Why

npm 安装后在 Windows 上 argo_search 直接崩溃:

UnicodeDecodeError: 'gbk' codec can't decode byte 0xa2 in position 37

根因是 Windows 默认 locale 编码 GBK:read_text() 读含中文的 backends/*.json 即崩,且 UnicodeDecodeError 不在原有 except (JSONDecodeError, OSError) 捕获范围,异常穿透到顶层。argo_local_search 则因 command -v / mdfind 双失效完全不可用。

设计取舍:入口级 UTF-8 模式(2 个入口)+ 字节流读取(6 处)+ 中央 helper 显式 encoding(2 处),而非 16 处散点 hardcode——新增代码自动免疫,diff 最小,且 Python 3.15 起 UTF-8 模式成为默认(PEP 686),届时守卫自然变 no-op。macOS/Linux 行为不变(grep 兜底仅在 rg 与 mdfind 均缺失时触达)。

Complements #2(os 元数据)——#2 解决装得上,本 PR 解决跑得动。

Tested

  • 7 个 py 文件 py_compile + node --check 通过
  • MCP 直跑(re-exec 生效,双启动 banner):argo_search 中文查询返回真实结果(L3 引擎恢复生效),无 GBK 错误;argo_local_search 114ms 命中且行号精确
  • node bin/argo.js 入口:env 传播生效(单 banner,守卫 no-op),initialize 正常
  • seek 引擎矩阵:正常 PATH 走 rg;剥除 rg 后经 Git 推导 grep(3 处命中行号精确);中文 17 字查询 JSON snippet 端到端无损;rg/grep/git 全无时优雅报错

Created from DSH session; branch fix/windows-runtime, single commit 52cb7e8.

目的:argo 在 Windows 上 npm 安装后 argo_search 直接 GBK 崩溃、
argo_local_search 因 command -v/mdfind 失效不可用,需在不侵入
上游风格的前提下修复(无新增注释/docstring)。

核心改动:
- bin/argo.js:spawn env 注入 PYTHONUTF8=1(PEP 540 UTF-8 模式)
- scripts/mcp_server.py:入口 re-exec 守卫,非 UTF-8 模式启动时
  execv 自身加 -X utf8(直接 python 运行场景;stdio 句柄继承)
- tfidf_router/quota/argo_engine_registry:6 处含中文 JSON 读取
  read_text() 改 read_bytes()(JSON 规范自检编码,except 元组不变)
- seek.py:tool_exists 由 command -v 改 shutil.which;/dev/null 改
  os.devnull;无 rg 时兜底由 macOS 专属 mdfind 改为 GNU grep 递归
  (PATH 优先,Windows 下探测 Git for Windows 自带 usr/bin/grep.exe;
  输出与 rg --no-heading 同构复用解析;rc=2 回退 -F 固定串);入口
  重配 stdout/stderr 为 UTF-8;中央 run() 显式 encoding="utf-8",
  errors="replace"(库导入/CLI 直跑形态的独立防线)
- health_probe.py:which 命令探测改 shutil.which

验证结果:
- 7 个 py 文件 py_compile + node --check 全过;diff 新增注释行为 0
- MCP 直跑(re-exec 生效,双 banner):argo_search 中文查询 count=2
  无 GBK 错误;argo_local_search 114ms 行号精确
- node bin/argo.js 入口:env 传播生效(单 banner),initialize 正常
- seek 引擎矩阵:正常 PATH 走 rg;剥 rg 后经 Git 推导 grep(3 处命中
  行号精确);中文 17 字查询 JSON snippet 无损;全无工具时优雅报错
目的:控制台 Ctrl+C 时(Windows 下 CTRL_C_EVENT 广播到同控制台的
python 子进程),readline() 被打断抛 KeyboardInterrupt,而既有
except Exception 接不住(KeyboardInterrupt 继承 BaseException),
裸 traceback 直接打印到控制台。

核心改动:mcp_transport.run_stdio 循环增加 except KeyboardInterrupt:
break,Ctrl+C 视同 EOF 干净退出(stdio server 标准惯例)。

验证结果:
- 单元模拟 readline 抛 KeyboardInterrupt:干净返回,无 traceback
- 正常 EOF 路径回归无损(initialize + EOF 退出均正常)
@minzorty

Copy link
Copy Markdown
Author

Added 4d5117b — fix Ctrl+C (Windows broadcasts CTRL_C_EVENT to python child on the same console): KeyboardInterrupt inherits BaseException, so the existing except Exception in run_stdio can't catch it and a bare traceback leaks to the console.

except KeyboardInterrupt:
    break

Treated as EOF, clean exit (standard stdio-server convention). Verified: simulated KeyboardInterrupt during readline() returns cleanly with no traceback; normal EOF path regression intact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant