首页
/ last30days-skill 首次配置向导中 Digg CLI 的安装路径对齐与 Agent 子进程 PATH 实践

last30days-skill 首次配置向导中 Digg CLI 的安装路径对齐与 Agent 子进程 PATH 实践

2026-09-06 12:03:34作者:郁楠烈Hubert

本篇指南基于仓库内的集成问题解决方案文档 digg-cli-agent-path-setup-wizard.md,讲解 last30days-skill 首次运行(NUX)自动安装 digg-pp-cli 时遇到的一个典型集成缺陷:安装器报告"成功"、引擎却因 Agent 子进程 PATH 缺失而静默丢弃 Digg 源。读完本篇,你能理解"已安装"与"引擎可激活"两个概念的差异、shutil.which 作为唯一激活门控的机制,以及配置向导如何通过对齐 printing-press-library 的默认安装目录、细分安装结果分类和 OpenClaw 服务端对等支持,实现诚实、可验证的 CLI 源引导流程。

问题背景:为什么"安装成功"不等于"数据源激活"

last30days-skill 的引擎通过外部 shell out 到 digg-pp-cli 二进制(只读、无需鉴权)来接入 Digg AI 1000 聚类源。该源是否可用,取决于一个非常朴素的判定:引擎子进程能否在 PATH 上按名字解析到这个二进制。

问题出在首次运行的自动安装环节(setup_wizard.pyrun_auto_setup()):

  • 在 Hermes / OpenClaw 这类 Agent 网关中,引擎子进程的 PATH 往往不包含 $HOME/.local/bin,而 printing-press-library npm 0.1.16 起正是把二进制默认装到该目录;
  • 早期实现使用了已弃用的 @mvanhorn/printing-press 包,并且探测的是遗留的 ~/go/bin 回退目录,而非当前的默认安装目录;
  • OpenClaw 的 setup --openclaw 路径完全没有尝试安装 Digg(只覆盖桌面 NUX 场景)。

由此产生的用户可见症状(见 解决方案文档 的 Symptoms 一节):

  • --diagnose 输出的 available_sources 中没有 digg,即使 pp-digg 或 setup 已经"安装"了 CLI;
  • 之前跑过 npx @mvanhorn/printing-press-library install digg --cli-only 的 Hermes/OpenClaw 用户,会因为探测逻辑不一致而收到虚假的失败或虚假的"now active"提示;
  • OpenClaw 服务端 setup 从不安装 Digg。

引擎侧的激活门控:shutil.which 是唯一标准

理解修复方案之前,先确认引擎侧的判定逻辑。在 digg.py 中:

CLI_BIN = "digg-pp-cli"

def _is_available() -> bool:
    """True when the digg-pp-cli binary is on PATH."""
    return shutil.which(CLI_BIN) is not None

pipeline.pyavailable_sources() 中,Digg 的可用性判定同样是:

if which("digg-pp-cli"):
    available.append("digg")

也就是说,引擎从不读取"pp-digg skill 是否已安装"这类状态,每一次研究运行都是按名字在 PATH 上 shell out 到 digg-pp-cli。这就是解决方案文档中"Why This Works"一节的核心结论:setup 向导必须镜像引擎自身的判定谓词,而不是发明另一套成功定义。如果 setup 用"某处存在二进制文件"当作成功,而引擎用 shutil.which 判定,两者就会漂移——用户在向导里看到"已激活",--diagnose 却显示源缺席。

修复要点一:固定(Pin)目录安装器与安装命令

setup_wizard.py 中固化了安装器版本与命令:

# Generous timeout: the install shells out to `npx`, which may download the
# Printing Press package and build the Go binary over the network.
DIGG_INSTALL_TIMEOUT = 300
DIGG_CLI_BIN = "digg-pp-cli"
# Pin the catalog installer; matches printing-press-library npm 0.1.16 default
# ($HOME/.local/bin on macOS/Linux).
PRINTING_PRESS_NPM = "@mvanhorn/printing-press-library@0.1.16"
DIGG_INSTALL_CMD = f"npx -y {PRINTING_PRESS_NPM} install digg --cli-only"

三个设计决策值得注意:

  1. npm 包名固定到 semver 0.1.16:该版本的目录安装器默认安装目录从 $GOPATH/bin 迁移到了 $HOME/.local/bin。固定版本号保证 setup 向导与 CONFIGURATION.md 中给用户的命令、以及引擎的 PATH 门控三者始终指向同一安装位置;
  2. 只装 CLI(--cli-only:last30days 把 Digg 内嵌为引擎数据源,而不是引入 pp-digg skill,所以不需要 skill 接线;Hermes/OpenClaw 上差异的只是 focused skill 的接线方式,二进制位置两者完全相同(都是 $HOME/.local/bin);
  3. 300 秒超时:安装过程可能涉及 npm 下载与 Go 二进制构建,超时预算按最坏网络条件给足。

CONFIGURATION.md 的数据源表格中对此有明确约定:Digg 的激活条件是"digg-pp-cli on PATH(首次运行 setup 时通过 npx -y @mvanhorn/printing-press-library@0.1.16 install digg --cli-only 自动安装;二进制默认落在 $HOME/.local/bin;Hermes/OpenClaw 的 Agent 子进程必须继承该目录的 PATH,Digg 才能激活)"。

修复要点二:安装结果五分类,杜绝虚假成功

修复后的 _install_digg_cli()setup_wizard.py)返回四元组 (engine_active, action, stderr, off_path_binary),其中 action 是一个五值分类:

action 触发条件 引擎是否激活 状态文案行为
already_installed shutil.which("digg-pp-cli") 一开始就解析成功 "Digg CLI already installed (AI-news clusters active)"
installed npx 安装后 shutil.which 解析成功 "Installed Digg CLI (... now active)"
installed_off_path 二进制在已知安装目录存在且可执行,但不在 PATH 上 给出具体路径与可复制粘贴的 PATH 目录,提示重启 Agent 会话/网关
install_failed npx 退出码非零或安装后两处探测均未找到 digg_stderr,提示手动执行 DIGG_INSTALL_CMD
no_npx 系统上找不到 npx 提示先安装 Node/npx 再执行安装命令

关键约束是:already_installed / installed 只在 shutil.which 解析成功时才允许出现——与 pipeline.available_sources() 的门控完全同谓词。而 installed_off_path 是专门为"磁盘上存在但 PATH 不可见"这种 Hermes/OpenClaw 常见失败模式准备的诚实出口。

候选目录探测:与安装器共享单一来源

探测 off-path 二进制的目录列表没有另起炉灶,而是从 health 模块的共享清单派生(setup_wizard.py):

def _digg_bin_candidate_paths() -> list[Path]:
    """Known install locations for digg-pp-cli (Printing Press library defaults).

    Order: current installer default (~/.local/bin), legacy Go bins, Windows
    managed dir. ...
    """
    from . import health

    win_dir = health.windows_printing_press_bin_dir()
    candidates: list[Path] = []
    for directory in health.installer_bin_dirs():
        if win_dir is not None and directory == win_dir:
            candidates.append(directory / f"{DIGG_CLI_BIN}.exe")
        else:
            candidates.append(directory / DIGG_CLI_BIN)
    return candidates

health.py 中这个清单的定义是:

  • ~/.local/bin(当前安装器默认,macOS/Linux);
  • $GOPATH/bin(若设置了 GOPATH,遗留 Go 目录);
  • ~/go/bin(遗留 Go 目录);
  • Windows:%LOCALAPPDATA%/Programs/PrintingPress/bin,且该目录下的候选名带 .exe 后缀(windows_printing_press_bin_dir() 在非 Windows 上返回 None)。

两个探测函数的分工在源码中写得很清楚:

def _digg_on_path() -> Optional[str]:
    """Return digg-pp-cli when the engine would activate Digg (PATH-resolvable)."""
    return shutil.which(DIGG_CLI_BIN)

def _digg_off_path_binary() -> Optional[str]:
    """Return digg-pp-cli path from known install dirs when not on PATH."""
    for candidate in _digg_bin_candidate_paths():
        if candidate.is_file() and os.access(candidate, os.X_OK):
            return str(candidate)
    return None

注意注释里的一句话:"探测这些目录只用于 setup 验证与诚实的 off-PATH 消息,不用于引擎激活"。这正是"What Didn't Work"第一条的教训——旧逻辑把"某处存在二进制"当作已安装,探测 ~/go/bin 但没有 PATH 可见性,造成假阳性;引擎门控与 setup 验证必须各守其位。

安装流程的状态机

_install_digg_cli() 的完整判定顺序(setup_wizard.py):

  1. _digg_on_path() 命中 → already_installed,直接返回;
  2. 未命中则查 _digg_off_path_binary():命中 → installed_off_path(复用之前 pp-digg 的安装,不重复装、也不谎称已激活);
  3. 都未命中才调用 _run_npx_install("digg") 执行 npx -y @mvanhorn/printing-press-library@0.1.16 install digg --cli-only;该子过程(setup_wizard.py)用 shutil.which("npx") 解析出 npx 的绝对路径再作为 argv[0] 传入——这是为了修复 Windows 上 PATHEXT 不匹配的问题(裸字符串 "npx" 不会触发 .CMD 解析,会以 WinError 2 失败);
  4. npx 返回非零或异常 → install_failed 并携带 stderr;
  5. npx 返回 0 后重新执行双探测:PATH 上出现 → installed;只出现在候选目录 → installed_off_path(把 npx 的非致命 stderr 一并记录);两处都没有 → install_failed("install completed but digg-pp-cli was not found")。

第 5 步的"安装后复验"是整个修复的关键:安装器进程退出码为 0 不代表二进制对当前进程可见,必须以引擎自己的门控再做一次判定。

状态文案:off-path 时给出可操作的 PATH 提示

get_setup_status_text()setup_wizard.py)把五分类渲染成用户可读的文案。installed_off_path 分支会调用 _digg_bin_dir_hint() 把二进制路径折算成可复制粘贴的 PATH 目录($HOME/.local/bin 形式,Windows 用绝对路径),并明确提示"add ... to PATH and restart your agent session/gateway for Digg to activate"——重启 Agent 会话是必要步骤,因为子进程 PATH 在会话启动时继承。

修复要点三:OpenClaw 服务端对等支持

旧实现中 setup --openclaw 完全跳过 Digg 安装,只覆盖桌面 NUX。修复后的 run_openclaw_setup()setup_wizard.py)在服务端 JSON 探针中执行同一套 _install_digg_cli()

digg_installed, digg_action, digg_stderr, digg_path = _install_digg_cli()
...
payload: Dict[str, Any] = {
    "yt_dlp": yt_dlp,
    "node": node,
    "python3": python3,
    "digg_cli": digg_installed,
    "digg_action": digg_action,
    "keys": keys,
    "x_method": x_method,
}
if digg_path:
    payload["digg_path"] = digg_path
if digg_action == "install_failed" and digg_stderr:
    payload["digg_stderr"] = digg_stderr

JSON 输出字段 digg_cli(引擎是否激活)、digg_action(五分类之一)、可选的 digg_path(off-path 二进制路径)与可选的 digg_stderr(安装失败详情),让 SKILL.md 驱动的模型在服务器场景下也能呈现与桌面 NUX 一致的、诚实的 Digg 状态。

这套模式如何推广到其他 Printing Press 源

同一套"固定安装器 + 双探测 + 五分类"模式在 setup_wizard.py 中被参数化复用到了其他默认开启的 Printing Press 源上:PP_DEFAULT_SOURCES = [("arxiv", "arxiv", "arxiv-pp-cli"), ("techmeme", "techmeme", "techmeme-pp-cli")],由 _install_pp_cli() / install_default_pp_sources() 执行,返回结构与 Digg 完全一致。Trustpilot 则被有意排除在自动安装之外(它默认关闭,属于 INCLUDE_SOURCES opt-in 源,且使用无头 Chrome 收割 cookie,为默认关闭的源预装二进制是浪费);Bright Data 同样是"只报告、不安装"(它消耗用户自己的计费额度,获取与否由用户决定)。这些例外与 Digg 的主路径共同构成 setup_wizard.py 中统一的 action 分类学。

测试覆盖与验证

修复的关键行为都有对应测试用例,集中在 tests/test_setup_wizard.py

  • off-path 检测路径:digg-pp-cli 位于 ~/.local/bin 但不在 PATH 上 → 期望 digg_action == "installed_off_path" 且不触发 npx(约 L384-L398);npx 安装 rc=0 但二进制落在 $HOME/.local/bin 且不可见 → 同样判定 installed_off_path(约 L405-L424);
  • 状态文案路径:installed_off_path 的各种情形(含遗留 ~/go/bin 位置、digg_path 缺失或为空)在 get_setup_status_text() 下均生成带 PATH 修复指引的文案(约 L771-L805);
  • Bright Data 的三态报告(already_installed / installed_off_path / not_installed)也验证了"引擎门控原样透传、从不夸大 active"的同一原则(约 L892、L931)。

这与解决方案文档 Prevention 一节的测试要求一致:Hermes/OpenClaw 场景要用重定向的 HOME 与 mock 的 PATH 覆盖,OpenClaw 服务端镜像桌面 NUX 时要在 JSON 中加入对应字段。

可复用的预防规则

解决方案文档最后沉淀了四条预防规则,适用于任何新增"CLI 门控数据源"的引导逻辑:

  1. 对齐上游安装器的默认 bin 目录,并固定 npm semver——安装位置是契约,不是假设;
  2. 成功消息必须使用与 available_sources() 相同的探测谓词(shutil.which,磁盘上存在但 PATH 不可见的情况走独立的 off-PATH 结果分支;
  3. 测试用重定向 HOME + mock PATH 覆盖 Agent 网关场景;服务端 setup 镜像桌面 NUX 时同步扩展 JSON 字段;
  4. 改动可选源引导前,先在 docs/solutions/ 下检索 diggsetup-wizardagent-path 等关键词——本方案文档(docs/solutions/integration-issues/digg-cli-agent-path-setup-wizard.md)即为此类集成问题的登记入口。

关键文件索引

文件 作用
setup_wizard.py 首次运行向导:Digg 安装器常量、候选目录探测、五分类安装流程、OpenClaw JSON 探针
digg.py Digg 源适配器:shutil.which 可用性门控、search/posts CLI 调用
pipeline.py available_sources():引擎侧按 which("digg-pp-cli") 激活 Digg
health.py installer_bin_dirs() / windows_printing_press_bin_dir():安装器目录单一来源
test_setup_wizard.py off-path 检测、状态文案与 OpenClaw 输出的测试覆盖
CONFIGURATION.md 数据源表格:Digg/arXiv 的 PATH 激活条件与安装命令
SKILL.mdAGENTS.mdHERMES_SETUP.md Step 0 引导与 CLI 门控源的文档约束
登录后查看全文
热门项目推荐
相关项目推荐