Skip to content

feat: 一键/脚本启动的产物跨平台真正脱离启动器,统一为静默后台运行 + 统一停止(detach/PID/stop) #2

Description

@EpisodeYu

概述

生成产物的两条本地启动路径——wizard“一键启动”与产物自带的 <显示名>.{bat,sh}——在所有平台上都把产物 server 作为真正脱离启动器的静默后台进程运行,并提供统一、干净的停止手段(PID 文件 + <slug> stop)。

直接动因:当前 wizard 一键启动用 subprocess.Popen(..., start_new_session=True) 派生产物,而 start_new_sessionPOSIX-only;在 Windows 上它被忽略,产物继承 wizard 的控制台与进程组 → 关掉 wizard 的 bat 窗口(CTRL_CLOSE_EVENT)或对 wizard 按 Ctrl-C连带杀掉本应独立存活的产物

纯生成器侧 + 产物启动脚本的改动,不改 HarnessSpec、不给产物加运行期依赖;产物“生成即脱离”定位不变。

动机

  • Windows 脱离失效:wizard/app.py::_launch_product 仅用 start_new_session=True,Windows 无效 → 一键产物与 wizard 同生共死,违背“产物 outlive 临时配置工具”的预期。
  • 两条路径表现不一致:
    • 一键(wizard):语义上应是后台,但 Windows 下其实没脱离;
    • 产物 bat:前台占用双击出来的控制台窗口,关窗口 / Ctrl-C 即停。
  • 静默后台缺管理手段:真脱离后没有窗口,只能任务管理器 / taskkill,不够干净。

目标:两条路径统一为“静默后台 + 一个明确的停止入口”,跨平台一致。

方案概要

  • 跨平台 detach:把脱离所需的 Popen 参数按平台拆开成 _detach_kwargs(platform)
    • POSIX:start_new_session=True(setsid,脱离终端会话)。
    • Windows:creationflags = DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP(无控制台 → CTRL_CLOSE_EVENT 到不了;独立进程组 → Ctrl-C 不波及)。常量用 getattr(subprocess, ..., 0x8/0x200) 兜底,便于在 Linux 上单测。
    • 产物输出已重定向到 .serve.log,无控制台不影响日志。
  • 产物记录 PID:产物 serve 在自身进程内写 .serve.pid、退出删,供停止 / 查活。
  • 统一停止:新增 <slug> stop(读 PID → 终止 → 清理 stale,跨平台);产物 <显示名>.{bat,sh} 改为静默后台拉起 + 打印 URL 与停止提示(可选再渲染一个 Stop <显示名> 脚本)。
  • 结果:wizard 一键 与 产物脚本 两条路径都 = 静默后台 server,均可用 <slug> stop 收尸。
flowchart LR
  Wizard["wizard 一键<br/>_launch_product"] -->|"detach kwargs"| Serve
  Bat["产物启动脚本<br/>launch_name.bat / .sh"] -->|"静默后台"| Serve
  Serve["产物 serve<br/>后台 / 无窗口"] --> Pid[".serve.pid"]
  Serve --> Log[".serve.log"]
  Stop["slug stop / Stop 脚本"] -->|"读 PID 终止"| Serve
Loading

交付物

生成器侧(harnessmith/)

  • wizard/app.py:新增 _detach_kwargs(platform) helper;_launch_product**_detach_kwargs() 替换 start_new_session=True;更新相关 docstring / _LAUNCHED 注释为跨平台准确措辞。
  • templates/src/__project_slug__/interfaces/cli.py.j2:serve 启动写 / 退出删 .serve.pid;新增 stop 子命令。
  • templates/__launch_name__.bat.j2 / __launch_name__.sh.j2:改为静默后台启动 + 停止提示;(可选)新增 Stop 脚本模板。

生成产物侧(渲染后)

  • <pkg> serve.serve.pid;<pkg> stop 停止后台 server。
  • <显示名>.{bat,sh} 双击 = 后台起 server + 提示停止方式。
  • README.md / AGENTS.md:说明后台运行与停止方式。

任务拆解

  • wizard _detach_kwargs + _launch_product 接入(Windows detach 修复)。
  • 产物 serve.serve.pid 写入 / 清理(记录真正 server 进程的 PID)。
  • 产物 stop 命令(跨平台、处理 stale PID)。
  • 产物 __launch_name__.{bat,sh} 改静默后台 + 停止提示(可选 Stop 脚本)。
  • README / AGENTS + slice 7 文档同步。

验收标准(退出门禁)

  • 单测:_detach_kwargs("win32")DETACHED_PROCESS(0x8)+ CREATE_NEW_PROCESS_GROUP(0x200)、不含 start_new_session;_detach_kwargs("linux") == {"start_new_session": True};_launch_product 把 detach 参数透传给 Popen(monkeypatch 捕获)。
  • 产物黄金路径绿:示例 / preset 生成 → uv sync && pytest(含 PID / stop 单测)全绿;mock 跑通一轮 function-calling;pyproject.toml 不含 langchain / langgraph / adk
  • PID / stop 行为:serve 起后存在 .serve.pid、退出清理;stop 能终止、对 stale / 缺失 PID 不报错。
  • 启动脚本快照:bat / sh 渲染为静默后台 + 停止提示。
  • ReadLints clean。
  • 人审手验(Windows):双击 HarnessSmith.bat → 一键启动 → 产物 web 起来 → 关 wizard 黑窗 → 浏览器仍可用;双击产物 bat → 后台起 server → <slug> stop / Stop 脚本能停。

需人审决策(命中 CLAUDE.md §6)

  • 本方案刻意不命中 §6.1 / §6.2(不改 schema、不给产物加运行期依赖)。
  • §6.10:取舍影响 wizard 与产物启动脚本两处,设计已在讨论中定档为“统一静默后台 + PID/stop”。
  • 人审手验:Windows 上 detach 真效(CI 无法 headless 验证 Windows 控制台事件)。

非目标 / 后续

  • Windows 系统托盘(tray):讨论过用托盘图标作为后台 server 的可见 / 可控入口。本片不做——要覆盖产物 bat 路径,托盘代码必须进产物仓库 → 产物吃 Windows 桌面 GUI 依赖(pystray / Pillow,或 300+ 行 ctypes Win32),命中 §6.1(spec 开关)/ §6.2(产物运行期依赖)/ §6.8(体积),且 GUI 核心 CI 无法 headless 测,与“薄 + 产物独立 + 跨平台 + 黄金可测”定位冲突。若要,另立带 spec 开关、默认关、Windows-only 的独立 slice。
  • 不引入任何 agent 编排框架。
  • 不改默认薄产物形态(除新增 .serve.pid + stop 命令的轻量管理)。

风险

  • Windows 不可 headless 自测:DETACHED_PROCESS / 控制台事件行为只能靠 Windows 手验;CI 仅覆盖参数映射与透传。
  • uv run 派生层级:产物经 uv run <slug> serve 派生,真正 server 是其孙进程;PID 文件应记录真正 server 进程的 PID(在产物进程内写),stop 才能准确终止,而非误杀 uv 包装层。
  • 静默后台的可发现性:无窗口 → 必须靠 .serve.log + stop / Stop 脚本提供可见与可控;中英文案要清楚。

参考

  • 相关代码:harnessmith/wizard/app.py(_launch_product)、harnessmith/templates/src/__project_slug__/interfaces/cli.py.j2(serve)、harnessmith/templates/__launch_name__.{bat,sh}.j2、根 HarnessSmith.{bat,sh}
  • slice 7 向导:docs/02-development/08-slice-7-wizard.md(§跨平台启动健壮性)。
  • 开发总览与切片门禁:docs/02-development/00-overview.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature新功能 / feature work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions