docs(design): publish terminal command address design for #72

grill-with-docs 会话产物:交互设计与测试边界定稿,spec 已发布为
issue #72;CONTEXT.md 增加 Terminal command address 词条。
This commit is contained in:
Qiu Yuzhou
2026-10-01 09:33:08 +08:00
parent 020d7a62d9
commit 82411d92ea
3 changed files with 129 additions and 0 deletions
+1
View File
@@ -32,6 +32,7 @@
- **Listener mode**: The user-facing choice that determines which address families the local proxy listeners accept: this Mac only (IPv4 loopback), all IPv4 interfaces, all IPv4 and IPv6 interfaces, or all IPv6 interfaces only. One mode applies to both the local SOCKS and HTTP proxy inbounds. _Avoid_: Listen scope.
- **HTTP proxy environment command**: An HTTP-only terminal command that sets lowercase `http_proxy` and `https_proxy` for this Mac's local HTTP proxy inbound. It always targets a loopback address for the selected listener mode.
- **Terminal proxy environment commands**: Shell-specific commands for zsh/bash and fish that set lowercase `http_proxy` and `https_proxy` through the local HTTP inbound, `all_proxy` through the local SOCKS inbound, and `no_proxy` for `localhost`, `127.0.0.1`, `::1`, and `.local` hostnames. The proxy endpoints use loopback addresses selected by listener mode, and the commands affect child processes that honor these variables.
- **Terminal command address**: The user-selected IP address used by both HTTP and SOCKS endpoints in copied terminal proxy environment commands. It defaults to a compatible loopback address; non-local listener modes also offer addresses of enabled Wi-Fi and Ethernet interfaces in the accepted address families, and the selection lasts only for the current app session without changing listener or system-proxy settings.
- **Proxy runtime**: The per-user background host process, independent of the GUI's lifetime, that runs the external tunnel service and loads the optional generated ACL sidecar.
- **Legacy configuration**: The server list and preferences persisted by the frozen implementation in `Legacy/`.
- **Legacy import**: The user-confirmed, read-only translation of a Legacy configuration's server records into a separate manual group in 2.0. It migrates no preferences, activates no target, and neither starts proxying nor alters the Legacy source.
@@ -0,0 +1,83 @@
## Problem Statement
首页“复制代理环境变量设置命令”目前只能生成指向回环地址的命令。用户已经选择允许其他设备访问的监听方式时,仍需手动修改命令中的 HTTP、HTTPS 和 SOCKS 地址,也无法从首页辨认本机可用的 Wi-Fi 或 Ethernet 地址。
## Solution
在非“仅本机”监听方式下,为首页命令卡片增加一个单选 IP 下拉框,默认选中兼容的回环地址。候选仅来自 loopback 和当前启用的 Wi-Fi、Ethernet 接口,并按监听地址族过滤。候选显示为 `{IP} - {name}`,名称采用系统接口本地化名称,缺失时使用 BSD 名称。两种 shell 的所有代理端点共用该选择,选择失效时自动回退到回环地址。
## User Stories
1. 作为应用用户,我希望非本机监听时能在首页选择命令地址,以便直接复制包含所需 IP 的命令。
2. 作为应用用户,我希望仅本机监听时隐藏地址下拉框,以便只看到适用于当前监听方式的操作。
3. 作为应用用户,我希望默认使用回环地址,以便继续使用现有本机终端操作习惯。
4. 作为 IPv4 用户,我希望候选仅包含 IPv4 地址,以便避免复制监听器不接受的端点。
5. 作为双栈用户,我希望同时选择 IPv4 和 IPv6 地址,以便适应目标设备使用的地址族。
6. 作为双栈用户,我希望两个回环地址都可选且默认使用 127.0.0.1,以便保留熟悉的默认值。
7. 作为仅 IPv6 用户,我希望默认地址为 ::1 且候选只有 IPv6,以便得到兼容的命令。
8. 作为 Wi-Fi 用户,我希望候选包含当前启用 Wi-Fi 接口的单播地址,以便通过无线网络使用代理。
9. 作为 Ethernet 用户,我希望候选包含当前启用 Ethernet 接口的单播地址,以便通过有线网络使用代理。
10. 作为应用用户,我希望排除 VPN 和其他接口类型,以便候选只包含明确支持的三类接口。
11. 作为应用用户,我希望每项同时显示 IP 和接口名称,以便辨认地址属于哪个网络接口。
12. 作为应用用户,我希望接口名称采用系统本地化名称,以便与系统中的接口称呼对应。
13. 作为应用用户,我希望名称缺失时显示 BSD 接口名,以便仍能辨认候选。
14. 作为应用用户,我希望回环项置顶、其他项稳定排序并合并同一接口的重复地址,以便快速查找候选。
15. 作为应用用户,我希望不出现 IPv6 链路本地地址和通配绑定地址,以便避免复制需要额外接口作用域或不能用作目标的地址。
16. 作为 zsh/bash 用户,我希望复制的 HTTP、HTTPS 和 SOCKS 端点都使用选中地址,以便一次设置全部代理变量。
17. 作为 fish 用户,我希望复制命令使用同一地址并保持 fish 语法,以便直接在 fish 中执行。
18. 作为 IPv6 用户,我希望生成的 URL 正确包含地址方括号和端口,以便应用能解析代理端点。
19. 作为应用用户,我希望选择命令地址不改变监听方式或系统代理,以便该操作仅用于生成命令。
20. 作为应用用户,我希望离开首页再返回时保留本次选择,以便减少重复操作。
21. 作为应用用户,我希望应用重启后恢复默认回环地址,以便不沿用先前网络环境的选择。
22. 作为切换网络的用户,我希望候选随网络变化刷新,以便选择当前接口地址。
23. 作为切换监听方式的用户,我希望不兼容的选择自动回退,以便界面始终符合已保存的监听配置。
24. 作为应用用户,我希望复制前重新检查地址并在失效时复制回环命令,以便不复制已消失的地址。
25. 作为应用用户,我希望无法枚举接口时仍能选择回环并复制,以便基础本机功能保持可用。
26. 作为应用用户,我希望代理未运行时仍能复制命令,以便预先准备终端配置。
27. 作为应用用户,我希望复制按钮的提示命令与实际剪贴板内容采用相同选择,以便理解即将复制的内容。
## Implementation Decisions
- 扩展 ProxyControlWorkflow 的 UI-facing 投影与用户操作:提供候选地址、选中地址、选择器可见性,以及基于同一选择生成的两种 shell 命令。呈现层负责下拉框和现有剪贴板副作用,不自行访问底层控制器或拼接命令。
- 应用会话持有选择,生命周期长于首页视图;不写入持久化设置。地址身份包含 BSD 接口身份与规范化 IP,不以本地化名称作为身份。
- 一个下拉框放在两个复制按钮上方,仅“仅本机”监听方式隐藏。监听方式与端口取已保存的设置;命令选择不改变代理运行状态、监听设置或系统代理。
- 默认地址前三种监听方式为 127.0.0.1,仅所有 IPv6 接口为 ::1。双栈提供两个回环地址。IPv4-only、双栈和 IPv6-only 分别过滤对应地址族。
- 候选仅包含 loopback,以及当前启用 Wi-Fi、Ethernet 接口的单播地址。排除 VPN、其他虚拟接口和其他接口类型,不以接口名前缀或通用链路类型代替严格类型判断。
- 系统适配器以 SCNetworkInterfaceGetInterfaceType 的 IEEE80211、Ethernet 类型识别非回环接口,以 IFF_LOOPBACK 识别回环。无法确认属于允许类型的非回环接口排除。
- 本地化接口名称使用 SCNetworkInterfaceGetLocalizedDisplayName,通过 BSD 接口名关联地址事实。缺失时回退 BSD 名;回环默认显示 lo0。名称缺失不会放宽类型过滤。
- 标签统一采用 `{IP} - {name}`。回环项置顶,双栈时 IPv4 回环先于 IPv6 回环;其他项按接口名称排序,同一接口先 IPv4 后 IPv6,然后按地址稳定排序。同一接口重复 IP 合并,不同接口同 IP 保留接口身份。
- 不提供手动地址输入,排除 IPv6 链路本地地址和通配地址。允许已通过接口类型过滤的 IPv4 链路本地单播地址。列出地址不代表已验证其他设备到该端点的连通性。
- 进入首页、网络变化以及复制前刷新;监听方式变化时重新过滤。仍有效的选择保留,否则回退到当前监听方式的默认回环地址。复制前发现失效时,本次复制采用回退后的命令,并更新界面选择。
- 枚举失败时仅提供兼容回环候选。即使代理未运行也允许复制。提示命令与实际复制内容使用相同的地址选择和生成逻辑;复制前刷新产生的变化同步至提示投影。
- HTTP、HTTPS 使用已保存的 HTTP 端口,SOCKS 使用已保存的 SOCKS 端口。保持现有变量集合、小写变量名、shell 转义、socks5 协议和 no_proxy 内容;IPv6 URL 使用方括号。
- 复用现有运行时适配缝提供已保存监听事实。仅新增一个工作流层可注入的本机接口事实来源,统一提供接口地址、类型、名称及变化通知;系统 API 查询细节封装于生产适配器,不再为每个底层 API 增加独立 mock 协议。
- 无配置迁移或持久化 schema 变更。同步修订现有四种监听方式 ADR 和领域文档中“终端命令始终面向回环”的旧约定;健康检查、系统代理目标继续依据监听方式,不受复制地址影响。
## Testing Decisions
- 主测试入口为 ProxyControlWorkflow 的可观察投影和用户操作。复用现有 FakeProxyRuntime、确定性变化通知与工作流 contract 测试方式,新增一个可编程接口事实替身。替身提供原始接口事实,让生产策略实际完成过滤、排序、名称回退与地址选择;不直接注入已经过滤好的候选。
- 好的测试断言用户可见候选、选中值、选择器可见性和最终 shell 命令,不断言底层系统 API 调用顺序、内部容器或私有辅助方法。
- 用四种监听方式验证地址族过滤、默认值、双栈回环项及监听方式切换后的回退。提供 Wi-Fi、Ethernet、loopback、VPN、其他虚拟接口及未知类型事实,验证严格白名单。
- 验证本地化名称、名称缺失的 BSD 回退、同一接口重复 IP 合并、不同接口同 IP 保留、稳定排序、IPv6 链路本地排除与 IPv4 链路本地允许。
- 通过选址后执行两种 shell 的命令准备操作,断言 HTTP、HTTPS、SOCKS 共用地址、端口来自已保存值、IPv6 URL 正确且 no_proxy 保持不变。
- 以同一会话离开再进入首页验证保留;以新会话验证默认值。通过可编程网络变化和复制前刷新覆盖地址消失、地址族不兼容及枚举失败的回环回退。
- 复用已有运行时命令记录,断言选择和刷新不会启动代理、修改监听设置或修改系统代理;代理未运行时命令仍可准备。
- 延续现有 workflow 不直接访问剪贴板的边界。工作流测试验证“刷新后准备的复制内容”,以及提示命令与命令准备结果在刷新后的投影一致性。不为纯视图布局引入额外领域测试缝,不进行视觉验收。
- 在真实 macOS 上通过非视觉验证核实系统接口名称与类型映射、Wi-Fi/Ethernet 候选以及 IPv6 地址事实。替身测试证明策略行为,真实主机的非视觉验证证明系统适配器整合;候选枚举本身不证明跨设备网络可达。
## Out of Scope
- 运行时监听绑定修改、系统代理地址修改或自动启用代理。
- VPN、其他虚拟接口和其他接口类型的候选支持。
- IPv6 链路本地地址作用域、手动地址输入、域名或外部公网 IP 发现。
- 跨应用重启记忆选择、设置迁移、恢复旧的手动 advertised address 配置。
- 网络可达性检测、认证机制、防火墙配置和复制命令后在目标终端的执行。
- 额外 shell、代理协议或环境变量语义变更。
- 视觉验收、截图检查与人工界面布局验收。
## Further Notes
- 设计来自 2026-10-01 的 grill-with-docs 会话。用户已确定交互与边界,最终将候选限制为 Wi-Fi、Ethernet、loopback,覆盖第一轮包含 VPN/虚拟接口的建议。
- 系统接口名称 API 可返回空值;loopback 无对应的 SystemConfiguration 类型常量,必须单独识别。严格类型白名单与名称回退分别处理。
- 用户已明确不做视觉验收。测试边界采用工作流外部行为测试和一个接口事实注入缝,系统适配器采用非视觉验证。
- 作为单一 feature spec issue 发布,标记 ready-for-agent,不创建拆分实施票据。
+45
View File
@@ -0,0 +1,45 @@
# 首页代理环境变量命令地址选择
日期:2026-10-01。
状态:交互设计与测试边界已确定,spec 已发布为 [Issue #72](https://github.com/qiuyuzhou/ShadowsocksX-NG/issues/72),标记 ready-for-agent;尚未实现。
## 功能范围
首页“复制代理环境变量设置命令”卡片在非“仅本机”监听方式下,在 zsh / bash 和 fish 两个复制按钮上方显示一个单选下拉框。仅本机模式隐藏下拉框并使用 IPv4 回环地址。
所选地址同时用于两种 shell 命令的 HTTP、HTTPS 和 SOCKS 端点。端口取已保存的监听设置,现有 shell 语法、变量集合和 no_proxy 内容保持不变。IPv6 在 URL 中使用方括号。选择只改变生成的命令,不改变监听配置或系统代理。
## 候选地址
仅包含 loopback,以及本机当前启用的 Wi-Fi、Ethernet 接口的单播 IP。VPN、其他虚拟接口和其他接口类型排除;不能仅依据 BSD 接口前缀或通用 Ethernet 链路类型来接受虚拟接口。无法确认是允许类型的非回环接口不纳入列表。
不提供手动输入,不提供通配绑定地址,IPv6 链路本地地址排除。IPv4 链路本地地址属于允许接口的单播地址时可以列出。候选列表不表示网络连通性已验证。
| 已保存的监听方式 | 地址族 | 默认地址 |
| --- | --- | --- |
| 仅本机 | IPv4 回环;隐藏下拉框 | 127.0.0.1 |
| 所有 IPv4 接口 | IPv4 | 127.0.0.1 |
| 所有 IPv4 与 IPv6 接口 | IPv4、IPv6,包含两个回环地址 | 127.0.0.1 |
| 仅所有 IPv6 接口 | IPv6 | ::1 |
每项显示 `{IP} - {name}`。接口名称优先取 `SCNetworkInterfaceGetLocalizedDisplayName(interface)`;名称缺失或无法映射到 SystemConfiguration 接口时,回退到 BSD 接口名,但不会因此放宽接口类型过滤。回环项回退名称为 lo0。
回环项置顶,双栈时 127.0.0.1 在 ::1 前。其余按接口名称排序,同一接口先 IPv4 后 IPv6,再按地址稳定排序。同一接口的重复 IP 合并;不同接口即使 IP 相同也保留接口身份。
## 选择生命周期与刷新
选择在本次应用运行期间保留,包括离开首页后返回;不跨应用重启持久化。进入首页、网络变化以及复制前刷新候选地址。监听方式变化时立即重新过滤候选。
所选地址消失,或监听方式不再支持该地址时,回退到对应监听方式的默认回环地址。复制前刷新发现地址失效时,本次复制使用回退后的地址,界面与命令一致。
地址枚举失败时仅保留兼容的回环项,继续允许复制。代理未运行时也允许复制;生成命令不承诺端点当前可连接。
## 实现与验证边界
地址枚举、接口名称及类型识别通过可注入的事实来源提供,UI 不自行访问底层控制器拼接命令。应用会话状态持有选中地址的接口身份和地址值,不使用界面显示名称作为身份。
需要验证四种监听方式的候选过滤和默认地址、Wi-Fi/Ethernet/loopback 类型过滤、VPN/虚拟接口排除、名称回退、IPv6 URL、两种 shell 的共享选中地址、离开首页后保留、应用重启后重置、网络变化和复制前失效回退,以及枚举失败时的回环退化行为。用户明确不做视觉验收;系统接口映射通过非视觉验证核实。
## 现有决策调整
此设计扩展 ADR-0015 中“命令始终面向本机回环”的旧约定。实现时同步更新该 ADR 的命令地址段落以及 CONTEXT.md 中对应定义和约束;健康检查和系统代理目标仍由监听方式确定,不受命令地址选择影响。此项是可逆的首页交互调整,不新增 ADR。