feat(v1.8.1): Windows 兼容性修复 + SKILL.md 铁律区块
Windows 兼容性修复(基于真实使用痛点):
- force_utf8_stdout(): 强制 stdout/stderr 为 UTF-8,修复 Windows GBK 崩溃(print('\\xa0') 不再炸)
- resolve_instances/load_config 新增 %APPDATA%/searxng-cli/ 路径,覆盖 Windows 配置约定
- fetch.py 失败诊断增强:输出 status_code=/cause=/url= 字段,AI Agent 可程序化区分 404/403/DNS 失败
SKILL.md 铁律区块(5 条,置顶):
- stdout=数据/stderr=日志 永不混淆
- 禁用 2>/dev/null(丢弃 stderr = 失败时零诊断)
- 排错去 --quiet 加 --verbose
- 配置查找覆盖 WSL + Windows 双路径
- 实例 URL 必填,公共实例发现已移除
测试: 352 -> 362(新增 10 个:force_utf8_stdout 幂等性/GBK 替换/非 ASCII 打印/APPDATA 路径发现/txt 回退/空 APPDATA)
This commit is contained in:
+35
-2
@@ -34,6 +34,7 @@ from common import (
|
||||
build_auth_headers,
|
||||
classify_error,
|
||||
emit_progress,
|
||||
force_utf8_stdout,
|
||||
resolve_auth_basic,
|
||||
resolve_auth_bearer,
|
||||
set_progress_enabled,
|
||||
@@ -329,13 +330,39 @@ def _read_instance_file(path: Path) -> list:
|
||||
return []
|
||||
|
||||
|
||||
def _windows_appdata_config_dir() -> Path:
|
||||
"""Return the Windows APPDATA config directory, or a sentinel Path if unset.
|
||||
|
||||
On Windows, the conventional per-user app config directory is
|
||||
``%APPDATA%`` (typically ``C:\\Users\\<user>\\AppData\\Roaming``).
|
||||
On POSIX, this env var is unset and we return a sentinel
|
||||
``Path("/__no_appdata__")`` which never exists on disk, so the caller
|
||||
can unconditionally append it to the candidate list without polluting
|
||||
Linux/macOS lookups.
|
||||
|
||||
Note: ``Path("")`` resolves to ``.`` (current directory) on Windows,
|
||||
which DOES exist — so we must use an absolute sentinel path instead.
|
||||
"""
|
||||
appdata = os.environ.get("APPDATA", "")
|
||||
if appdata:
|
||||
return Path(appdata) / "searxng-cli"
|
||||
# Sentinel: absolute path that never exists. Using "/" + unlikely name
|
||||
# keeps it false on both POSIX and Windows (where "/" is the drive root).
|
||||
return Path("/__no_appdata__")
|
||||
|
||||
|
||||
def resolve_instances(cli_arg: str = None) -> list:
|
||||
"""Resolve instance URLs from (in priority order):
|
||||
|
||||
1. ``--instance`` CLI flag (comma-separated list)
|
||||
2. ``SEARXNG_INSTANCE`` environment variable (comma-separated list)
|
||||
3. config file: ``./searxng.toml`` → ``~/.config/searxng-cli/searxng.toml``
|
||||
→ ``./instances.txt`` → ``~/.config/searxng-cli/instances.txt``
|
||||
3. config file search order:
|
||||
a. ``./searxng.toml``
|
||||
b. ``~/.config/searxng-cli/searxng.toml``
|
||||
c. ``%APPDATA%/searxng-cli/searxng.toml`` (Windows only)
|
||||
d. ``./instances.txt``
|
||||
e. ``~/.config/searxng-cli/instances.txt``
|
||||
f. ``%APPDATA%/searxng-cli/instances.txt`` (Windows only)
|
||||
|
||||
Returns an empty list if no instance can be resolved.
|
||||
"""
|
||||
@@ -346,11 +373,14 @@ def resolve_instances(cli_arg: str = None) -> list:
|
||||
if env:
|
||||
return parse_instances(env)
|
||||
|
||||
win_dir = _windows_appdata_config_dir()
|
||||
candidates = [
|
||||
Path.cwd() / "searxng.toml",
|
||||
Path.home() / ".config" / "searxng-cli" / "searxng.toml",
|
||||
win_dir / "searxng.toml",
|
||||
Path.cwd() / "instances.txt",
|
||||
Path.home() / ".config" / "searxng-cli" / "instances.txt",
|
||||
win_dir / "instances.txt",
|
||||
]
|
||||
for p in candidates:
|
||||
if p.exists():
|
||||
@@ -395,9 +425,11 @@ def load_config(config_path: str = None) -> dict:
|
||||
except Exception as e:
|
||||
logger.warning(f"Warning: cannot read config '{p}': {e}")
|
||||
return {}
|
||||
win_dir = _windows_appdata_config_dir()
|
||||
candidates = [
|
||||
Path.cwd() / "searxng.toml",
|
||||
Path.home() / ".config" / "searxng-cli" / "searxng.toml",
|
||||
win_dir / "searxng.toml",
|
||||
]
|
||||
for p in candidates:
|
||||
if p.exists():
|
||||
@@ -1379,6 +1411,7 @@ def main():
|
||||
pre_args, _ = pre.parse_known_args()
|
||||
|
||||
setup_logging(verbose=pre_args.verbose, quiet=pre_args.quiet)
|
||||
force_utf8_stdout() # Windows: prevent GBK crash on non-ASCII chars
|
||||
|
||||
# Load config defaults from --config file, else ./searxng.toml or
|
||||
# ~/.config/searxng-cli/searxng.toml. Every CLI flag below can be
|
||||
|
||||
Reference in New Issue
Block a user