diff --git a/docs/design/system-proxy-runtime-control-spec.md b/docs/design/system-proxy-runtime-control-spec.md deleted file mode 100644 index b21b54de..00000000 --- a/docs/design/system-proxy-runtime-control-spec.md +++ /dev/null @@ -1,131 +0,0 @@ -## Problem Statement - -系统代理开关开启时,网络接口的代理配置可能被系统设置或其他应用修改。当前首页没有列出仍存在差异的接口,最后一次应用成功也不能证明当前配置仍符合预期。网络位置、服务或路径变化后的自动应用可能覆盖用户在其他应用中的选择。 - -用户需要在首页识别当前差异并明确修复,同时避免后台代理失效后系统仍指向不可用的本地入口。操作失败时,助手等待批准的解决入口必须可见,不能被失败提示的优先级隐藏。 - -## Solution - -首页运行控制卡保留后台代理与系统代理两个意图开关,分别呈现运行事实与系统代理配置事实。在系统代理开关下展示当前有差异的网络接口名称和“修复”按钮。外部修改与被动网络变化只检查、提示,不自动修复;保存本 App 的相关设置、后台失效与健康恢复属于已确认的自动操作例外。 - -后台失效时清除全部系统代理配置,保留开启意图;恢复健康时自动应用。提示区分别表达操作结果与可解决的阻塞原因,始终保留需要的助手批准入口。设计已确认,已在提交 `4a0a72c` 实现;本 Issue 不授权直接改动真实主机的系统代理设置来验证。 - -## User Stories - -1. 作为应用用户,我希望后台代理开关表达保存的开启意图,以便运行失败时仍知道我希望后台继续运行。 -2. 作为应用用户,我希望系统代理开关表达保存的开启意图,以便暂停、外部修改或写入失败不会悄悄关闭它。 -3. 作为应用用户,我希望开启系统代理后等待本地入口就绪再应用,以便不把系统指向尚不可用的入口。 -4. 作为应用用户,我希望规则与全局模式没有可用活动目标时不应用,以便不使用没有出口的代理。 -5. 作为直连模式用户,我希望系统代理不依赖活动服务器,以便通过本地入口直接连接。 -6. 作为应用用户,我希望看到当前真实配置是否一致,以便不会被最后一次写入成功的状态误导。 -7. 作为应用用户,我希望外部修改只产生提示,以便 App 不自动覆盖其他应用的选择。 -8. 作为应用用户,我希望提示列出所有仍有差异的接口,以便知道哪些网络配置需要处理。 -9. 作为应用用户,我希望接口使用系统设置中的名称,以便辨认并定位对应网络服务。 -10. 作为应用用户,我希望未连接的服务也参与检查,以便以后切换到它时已有一致配置。 -11. 作为应用用户,我希望名单仅包含当前网络位置的服务,以便看到与当前环境有关的问题。 -12. 作为应用用户,我希望长名称完整换行,以便不会因省略号遗漏受影响接口。 -13. 作为应用用户,我希望等价写入不产生提示,以便不会把未改变的设置当作问题。 -14. 作为应用用户,我希望不受本 App 管理的字段变化不产生提示,以便避免无关告警。 -15. 作为应用用户,我希望文案不猜测修改者,以便不会收到无法证实的归因。 -16. 作为应用用户,我希望重复事件只刷新当前差异,以便提示不会累积成历史日志。 -17. 作为应用用户,我希望外部恢复一致后移除对应名称,以便名单始终反映现状。 -18. 作为应用用户,我希望全部一致后自动撤下提示,以便无需手动关闭已经解决的告警。 -19. 作为切换网络的用户,我希望切换网络位置只检查,以便新的环境不会被自动覆盖。 -20. 作为新增网络服务的用户,我希望看到“尚未应用”的提示,以便不会被误告知发生外部修改。 -21. 作为应用用户,我希望两类差异分段列出并共用修复入口,以便一次处理当前问题。 -22. 作为应用用户,我希望点击修复直接执行,以便不必经过额外确认弹窗。 -23. 作为应用用户,我希望修复前重新读取位置与差异,以便只处理当时真实需要修复的服务。 -24. 作为应用用户,我希望修复跳过已经一致的服务,以便不产生不必要写入。 -25. 作为应用用户,我希望修复保留 App 不管理的字段,以便不丢失无关网络配置。 -26. 作为应用用户,我希望修复中保留名单并显示进度,以便知道正在处理哪些接口。 -27. 作为应用用户,我希望修复中不能重复点击,以便避免并发重复操作。 -28. 作为应用用户,我希望修复后重新读取确认,以便“已应用”有当前配置事实支持。 -29. 作为应用用户,我希望修复失败保留差异与原因,以便知道下一步仍需处理什么。 -30. 作为应用用户,我希望外部再次修改后提示重新出现,以便不会遗漏后续变化。 -31. 作为设置用户,我希望保存端口或系统代理例外后自动应用,以便保存后的设置及时生效。 -32. 作为设置用户,我希望未保存编辑不触发系统代理操作,以便草稿不影响现有配置。 -33. 作为设置用户,我希望自动应用失败提供修复入口,以便能显式重试而不依赖后台循环。 -34. 作为应用用户,我希望后台失效时清除全部系统代理配置,以便不继续使用不可用的本地入口。 -35. 作为应用用户,我希望普通断网本身不被当作后台失效,以便避免不必要的配置清除。 -36. 作为应用用户,我希望清除成功后显示“已暂停”并保留开启意图,以便理解它会随后台恢复。 -37. 作为应用用户,我希望清除失败明确显示原因,以便不会误以为不可用的设置已经移除。 -38. 作为应用用户,我希望清除失败提供“重试清除”,以便主动解决残留配置。 -39. 作为应用用户,我希望后台恢复健康时自动应用,以便恢复可用代理而无需再次开启开关。 -40. 作为应用用户,我希望暂停期间关闭系统代理后不再自动应用,以便关闭意图优先于恢复事件。 -41. 作为应用用户,我希望健康启动只检查,以便启动 App 不自动覆盖其他应用的配置。 -42. 作为应用用户,我希望不健康且意图开启的启动自动清除,以便避免遗留的不可用入口。 -43. 作为应用用户,我希望意图关闭的启动不应用也不清除,以便启动不产生无关系统操作。 -44. 作为应用用户,我希望关闭后台代理仍级联关闭开启中的系统代理并先清除,以便停止监听前处理系统设置。 -45. 作为应用用户,我希望关闭系统代理不停止后台监听,以便保留其他本地代理使用方式。 -46. 作为应用用户,我希望操作失败不自动无限重试,以便 App 不持续竞争系统配置。 -47. 作为应用用户,我希望任何失败同时存在助手待批准时仍显示批准入口,以便有可执行的解决路径。 -48. 作为应用用户,我希望未批准时隐藏无法执行的修复与重试按钮,以便不会反复触发同一失败。 -49. 作为应用用户,我希望未批准原因只说明一次,以便提示清楚而不重复。 -50. 作为应用用户,我希望批准后已失败操作恢复对应按钮但不自动重试,以便重新写入仍由我决定。 -51. 作为首次开启的用户,我希望尚未执行的待批准请求在批准后继续,以便不必重复原开启操作。 -52. 作为应用用户,我希望配置读取失败显示“无法检查”,以便不会把未知状态当作已应用。 -53. 作为应用用户,我希望“重新检查”仅执行读取,以便排查本身不修改配置。 -54. 作为应用用户,我希望关闭工作区窗口但保留菜单栏进程时仍监控,以便菜单栏使用方式有相同状态保障。 -55. 作为应用用户,我希望退出 GUI 后不新增后台监控职责,以便后台代理与系统代理管理边界明确。 -56. 作为应用用户,我希望差异提示留在开关下而不额外弹通知,以便在相关操作处处理问题。 -57. 作为应用用户,我希望关闭操作清除失败时仍保留失败结果,以便关闭的开关不会掩盖残留设置。 - -## Implementation Decisions - -- 遵循领域词汇:Agent switch 与 System proxy switch 是持久化意图;Network service 是具备独立代理设置的 macOS 网络服务;Desired system proxy configuration、System proxy configuration difference、System proxy repair 与 System proxy suspension 是不同事实。用户文案仍称“网络接口”,不将其缩减为物理接口或终端命令地址候选。 -- ADR-0022 是本次已确认生命周期决策,替代 ADR-0019/0020 的被动事件自动应用、健康启动应用、健康失效保留配置等条款;保留 ADR-0020 的特权助手、注册、强类型配置与全位置无条件清除边界。 -- 复用 ProxyControlWorkflow 作为 UI 命令与快照入口。增加显式修复、重试清除和只读重新检查能力;快照承载当前差异、操作进度/结果、暂停、读取可用性及批准阻塞事实,不让 SwiftUI 自行判断系统配置是否一致。 -- 操作结果与批准阻塞独立建模。助手待批准可与清除/应用/修复失败共存,也可在系统代理意图关闭但清除失败时出现;不能继续以“意图开启”作为批准入口唯一条件。 -- 系统代理观察器复用现有网络事件来源;代理配置、服务、位置与路径事件触发读取,不直接触发应用或清除。事件只说明需要检查,不证明外部修改来源。 -- 在现有 SystemProxyControlling 适配缝补充可注入的服务配置读取事实与修复能力,包含网络位置/服务稳定身份、系统设置名称和代理值。保持真实系统读取与写入在适配边界,领域比较只消费纯值;特权写入仍由助手执行。 -- 比较 SOCKS、HTTP、HTTPS 的启用、地址与端口,以及 PAC、自动发现、简单主机名排除和完整例外等 App 管理值。等价写入、无关字段变化以及自身写入后已一致的事实不产生误报。 -- 复用 SystemProxyPlanner/SystemProxyPropertyList 的值投影和字段保留语义。初次开启、相关设置保存与健康恢复应用到当前位置全部服务;修复以重新读取的当前位置及当前差异为准,只写仍有差异的服务;一致服务跳过。不恢复历史配置,也不保存独占所有权标记。 -- 修复前重新读取,修复后再读取验证。不能仅凭助手成功响应消除提示;读取失败不能声称一致。位置或配置在提示与点击之间发生变化时,以最新事实为准。 -- 外部恢复一致后移除对应名称,全部一致后撤下提示;提示不是历史日志。新增服务或切换位置后未应用使用独立的“尚未应用”类别,不将其冒充为已知外部修改。 -- 清除仍移除全部网络位置、全部服务的完整代理字典,不检查来源,可清除其他应用设置。开启意图下的后台健康/出口失效及不健康启动是新增清除触发,清除成功才称“已暂停”。失败保留开启意图与失败结果。 -- 可应用条件沿用本地入口健康及模式出口门禁;规则/全局要求可用活动目标,直连不要求服务器。普通断网本身不算后台失效,不将“有可用目标”升级为新的远端可达性保证。 -- 健康恢复与用户保存影响预期系统代理值的设置可自动应用并覆盖外部值。意图关闭则不自动应用;未保存编辑不写系统配置。后台不可用时不强行应用。 -- 首次开启等待入口就绪是原用户操作的延续。GUI 健康启动只检查;不健康且意图开启的启动清除;意图关闭的启动不写。原有 Agent 主动关闭的级联与清除先于停止监听顺序保留。 -- 观察及健康驱动操作限于 GUI 进程运行期间,包括工作区窗口关闭但菜单栏仍运行。退出 GUI 后不把职责转移给 Agent 或助手,再次启动按启动规则处理。 -- 不因被动事件自动重试失败操作。批准后已失败操作恢复对应按钮但不自动执行;尚未执行的首次开启待批准请求可继续,仍需当前意图与健康门禁允许。新健康恢复事件仍是独立自动应用触发。 -- 状态文案包括“未应用”“待应用”“已应用”“配置已改变”“应用中”“修复中”“应用失败”“修复失败”“已暂停”“清除失败”“无法检查”“待批准”。清除失败优先于暂停;后台不可用时隐藏差异修复,恢复后重新检查;批准入口始终与失败结果并存。 -- 差异提示在开关下使用橙色警告图标与文字,服务名完整换行,名单下提供小尺寸原生“修复”按钮。无确认弹窗、无提示关闭按钮、无额外通知。执行中保留名单、显示“修复中…”和进度并阻止重复点击。 -- 已确认中文文案:外部修改为“以下网络接口的代理配置已被改变:{名称列表}”;新服务/位置为“以下网络接口尚未应用当前系统代理配置:{名称列表}”;修复后仍有差异为“以下网络接口的代理配置仍有差异:{名称列表}”。两类差异并存时分段列出,共用修复按钮。 -- 已确认中文文案:暂停为“后台代理不可用,已清除系统代理配置。恢复后将自动应用。”;后台失效清除失败为“后台代理不可用,系统代理配置未能清除。”;修复失败为“无法修复系统代理配置:{原因}”;读取失败为“无法读取网络接口的代理配置:{原因}”。 -- 助手批准说明为“系统代理助手等待批准。请在系统设置 → 登录项与扩展中允许。”,按钮为“在登录项中批准…”。失败原因仅为未批准时不重复展示相同错误。其余按钮为“重试清除”“重新检查”。 -- 本次不新增用户偏好或迁移要求;差异、进度和阻塞是当前观察与操作事实,现有开关意图和设置持久化契约保留。 - -## Testing Decisions - -- 主要行为验收缝采用现有 ProxyControlWorkflow 集成组合:生产 workflow、adapter 与真实控制器,注入系统代理、网络事件、健康探测和助手状态替身,通过公共命令、发布快照及可观察副作用验证。测试不直接调用私有收敛方法或依赖内部调度次数。 -- 复用 ProxyControlWorkflowIntegrationTests 的命令/快照先例,以及 ProxyRuntimeControllerTests 中的批准门禁、显式关闭清除顺序、网络事件与启动先例。为集成组合注入现有可编程网络事件替身;在现有系统代理适配缝扩展读取与修复替身,不新增独立的顶层测试入口。 -- 测试外部修改、位置/服务/路径变化只读取而不写;等价值与不管理字段无告警;当前差异恢复时撤下对应名称;新增服务与新位置分类不同于已知修改;包含未连接服务,名称事实保持完整。 -- 测试点击前位置/配置变化、部分服务已恢复、修复中的重复命令、修复后的再读取及外部再次修改。观察当前 snapshot 和写入的服务范围,而不是复刻比较实现。 -- 测试相关设置保存自动应用、未保存编辑不写;应用失败由显式修复重试;意图关闭时保存设置不应用。 -- 测试后台失效/出口不可用清除全位置、清除成功暂停、失败保留结果及意图、普通断网不单独触发清除、直连不依赖目标、恢复自动应用及暂停期间显式关闭阻止恢复应用。 -- 测试健康启动仅检查、不健康且意图开启启动清除、意图关闭启动零写入;保留后台主动关闭级联与清除先于停止监听的既有契约。 -- 测试批准阻塞与三类失败结果并存,包括意图已关闭但清除失败;批准入口可执行且不被状态优先级隐藏;批准后已失败操作不自动重试;未执行首次开启请求可继续;新健康恢复仍可自动应用。 -- 测试读取失败不声称“已应用”、重新检查零写入、读取恢复后真实状态重新出现。允许缓存用于诊断,但不能冒充当前已确认事实。 -- 对 SystemProxyPlanner/SystemProxyPropertyList 仅补充集成层无法清楚覆盖的纯值边界:语义等价、字段保留、定向服务范围及无条件全位置清除。复用 SystemProxyTests 的字段保留、PAC 移除、幂等应用和清除先例,不重复整套业务矩阵。 -- 对 UI 使用的状态/动作投影验证失败与批准共存、按钮互斥、修复进度、暂停说明与读取未知状态;后续实现还需检查实际卡片的长名称换行、按钮可见性与进度反馈。投影测试不声称已验证视觉布局。 -- 遵循 hostless 测试约定,使用临时数据和替身,不启动生产 GUI、不注册真实 Agent/助手、不写真实 SystemConfiguration。替身与纯值测试不证明真实主机写入、权限批准或观察通知已经成功;有需要时另行明确真实主机验收范围。 - -## Out of Scope - -- 本规格发布阶段的代码实现、测试执行或真实主机代理写入。 -- Legacy 的修改、旧版本迁移或兼容清理。 -- GUI 退出后的 Agent/LaunchDaemon 持续观察或自主修复。 -- 历史配置恢复、所有权声明、修改者识别或历史事件日志。 -- 新增健康探测系统、远端服务器可达性保证或把普通断网当作后台失效。 -- 终端代理命令地址选择器的候选与监听策略调整。 -- 额外通知、每次修复确认弹窗、可关闭差异提示或新的代理偏好开关。 -- 改变助手注册/签名/审批安全边界及无条件全位置清除机制。 -- 独立的侧栏或状态菜单视觉重设计;共享事实不得继续把未知或差异状态表述为已确认应用。 - -## Further Notes - -- 本设计与测试缝均已获用户确认,规格已发布为 [Issue #73](https://github.com/qiuyuzhou/ShadowsocksX-NG/issues/73),标签为 `ready-for-agent`。 -- 现有 Issue #71 已关闭;本次是其已实现生命周期基础上的后续变更,不重开或改写该 Issue。 -- ADR-0022 与配套首页设计文档已记录接受决策,并同步实现状态。本规格完整承载规则与文案。提交 `4a0a72c` 的 717 项 hostless 单测通过,并完成替身卡片渲染检查;真实主机写入、权限批准与观察通知未验收。 -- 自动清除会删除其他应用的设置,健康恢复与相关设置保存会覆盖外部值。这是用户已明确接受的行为例外,不能扩大为被动网络事件自动修复。 -- 关闭 GUI 指退出进程,不是仅关闭工作区窗口。健康启动观察与真实健康恢复必须区别,不能把初始未知到健康当作自动恢复应用。 diff --git a/docs/design/terminal-command-address-spec.md b/docs/design/terminal-command-address-spec.md deleted file mode 100644 index 38e9616a..00000000 --- a/docs/design/terminal-command-address-spec.md +++ /dev/null @@ -1,83 +0,0 @@ -## 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,不创建拆分实施票据。 diff --git a/docs/design/user-plugin-catalog-spec.md b/docs/design/user-plugin-catalog.md similarity index 100% rename from docs/design/user-plugin-catalog-spec.md rename to docs/design/user-plugin-catalog.md diff --git a/docs/design/user-plugin-form-spec.md b/docs/design/user-plugin-form.md similarity index 100% rename from docs/design/user-plugin-form-spec.md rename to docs/design/user-plugin-form.md diff --git a/docs/design/user-plugin-management-ui-spec.md b/docs/design/user-plugin-management-ui.md similarity index 100% rename from docs/design/user-plugin-management-ui-spec.md rename to docs/design/user-plugin-management-ui.md diff --git a/docs/design/user-plugin-mapping-commit-spec.md b/docs/design/user-plugin-mapping-commit.md similarity index 100% rename from docs/design/user-plugin-mapping-commit-spec.md rename to docs/design/user-plugin-mapping-commit.md