wangjia
a392d18a6a
feat(web): iOS/iPad 下载卡合一 + 双按钮 + 正式版「?」气泡提示
...
- 三张 iOS/iPad 卡合成一张:测试版(TestFlight,实心可点)+ 正式版(App Store,描边禁用)双按钮。
- 「?」移入正式版按钮内,自定义 tooltip 气泡(走设计 token,上浮淡入+小箭头)替代原生 title,
悬浮/聚焦显示「美区即将上线 · 需美区 Apple ID」;光标不再变问号。
- 新增 i18n 文案 dl.us_soon(6 语)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-09-11 16:33:16 +08:00
wangjia
a913fe56fb
feat(web): 下载区补 iPad + iOS 分测试版/正式版 + 需美区ID提示
...
按需求调整官网下载卡片:
- 补 iPad 卡片(tablet 图标,universal app→同 TestFlight 公测链接)。
- iOS/iPad 明确分「测试版」(TestFlight,可点)与「正式版」(App Store,
敬请期待占位)——加 badge 标注(dl.beta/dl.stable i18n,6 语言)。
- 测试版卡加「?」悬浮提示「需美区 Apple ID」(dl.us_id i18n)。
- badge/「?」样式全走设计 token(--accent-subtle/--accent/--bg-subtle/
--fg3),不硬编码颜色。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-09-11 09:02:43 +08:00
wangjia
18fb5177be
feat(web/client): iOS 下载/更新指向 TestFlight 公测链接
...
公测公开链接 https://testflight.apple.com/join/6HFfw8Jc 。
- 官网 Download:site.ts 加 downloads.ios + Download.astro iOS 按钮启用
(原为禁用占位),点击直跳 TestFlight;ver 顺带改 iOS 15+(对齐最低版本)。
- 客户端自更新:清单模板 deploy/single-node/version.yaml 的
download_urls.ios 从空填成 TF 链接 → 客户端「有更新」按钮直跳 TestFlight。
- pangolin1 现行 /etc/pangolin/version.yaml 已同步改(/version 已反映),
现有用户即时生效。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-09-11 08:55:49 +08:00
wangjia
cd1ef98b27
fix(ci): checkout 浅克隆 + sing-box clone 重试(外网走 frps 稳定性 A)
...
外网 runner 的 git fetch 经 ali frps 隧道偶发超时(run#289/290 的 Checkout
卡死即此)。A 层加固:
- deploy-client.yml 全部 actions/checkout 加 fetch-depth:1 —— 从拉全历史
降到一层,数据骤减,直接打掉 Checkout 步超时根因(外网/在家都受益)。
- build-libbox.sh sing-box clone(已 --depth 1)加 3 次重试 —— 另一大 fetch
抖了自动重来。
checkout 步显式重试(需替换 actions/checkout)暂缓,先看浅克隆后失败率;
仍高再上 checkout 重试 + frps 隧道调优(B)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-08 12:33:17 +08:00
wangjia
6a3cb48a02
fix(ios): 最低部署目标 14.0→15.0(消除 ASC 警告 90068)
...
TestFlight 上传报 ITMS-90068 MinimumOSVersion too low:app 最低 iOS 14.0,
Apple 要求 2027 春起 ≥15.0 才能上传/分发。改 IPHONEOS_DEPLOYMENT_TARGET
(pbxproj 6 处:Runner+PacketTunnel 扩展 × debug/release/profile)+ Podfile
platform :ios 14.0→15.0。iOS15(2021)覆盖面足够,放弃 iOS14 无影响。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-08 11:18:42 +08:00
wangjia
6c6d9636bb
fix(ci): 串行化 mac 三 job(android→macos→ios) 消除单 runner 争用
...
run#286 暴露:三个 runs-on:mac 并行,家里只一个 mac runner(capacity=1),
android 占住后 macos/ios 抢不到 runner 被整体 cancelled(全步骤含 Checkout
都 cancelled)→ iOS 没跑起来、没上 TestFlight。用 needs 把 mac 三 job 串成
链(build-macos needs android、build-ios needs macos)+ if:!cancelled() 保证
上游失败也照跑,一个跑完再跑下一个,不再争用。windows/deploy-web 在各自
runner 上仍并行。对齐 jiu 的 needs 链。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-08 06:59:33 +08:00
wangjia
8f0c2ef81b
ci(client): web 并入 deploy-client(一个 client-v* 发全平台) + iOS 加密合规键
...
1) deploy-client.yml 加 deploy-web job(usercenter+website→CF Pages,与
deploy-site.yml 同源共用 scripts/ci/*.sh),release-deploy needs 带上它:
一个 client-v* tag 即发 web + iOS/mac/Android/Windows(对齐 jiu)。
site-v*/deploy-site.yml 保留供 web-only 单发。清理过时 runner TODO 注释
(mac/windows 用户级 runner 今日已就绪)。
2) iOS Info.plist 加 ITSAppUsesNonExemptEncryption=false(仅标准加密,免
ASC 每次上传加密合规问答;法务判定需申报再改 true)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-08 06:13:08 +08:00
wangjia
d094a53d7e
docs(ci): W3/W4 落地记录——git 局域网直达 24ms + 华为防私接 DHCP 偏差
...
W3/W4 标记完成。W4 按计划(DSM 443 反代改 HTTPS+导入 ali LE 证书)。
W3 改方案:原定 NAS 接管 DHCP 被华为 Q2S 防私接 DHCP 挡死→放弃,改成
NAS 装 Synology DNS Server(git/nas/win 单主机主区+转发其余)+仅 runner mac
家里 Wi-Fi 手动 DNS=.200。§8 记完整过程/偏差/坑(mDNSResponder 负缓存需 flush)。
真相源 baize domains.yaml 家内分光 note;NAS 運維归 ~/code/nas。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-07 22:19:19 +08:00
wangjia
c152c2aadf
docs(ci): 标记 W5 已完成(runner 收敛为单一用户级+relay 退役)
...
W5 执行记录:mac-pangolin-2(id=7)本就用户级+已指向域名,唯一 bug 是
label 错成 nas(根因 Shadowrocket 掐连接致 Declare 从没上报成)。换
pangolin 后改 config labels nas:host→mac:host + kickstart 重启,
Declare 成功、label 变 mac,立即接走队列 task 2299。退役 jiu id=3
(删+launchd .disabled)+relay(.retired)。工作表 W5 改已完成。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-07 18:11:40 +08:00
wangjia
cf3b806311
docs(ci): 补 NAS 可行性判定(DS925+ 支持 W3/W4)
...
read-only 实测:NAS=DS925+ x86/DSM7.3.2,本身就是 LAN DHCP 服务器
(DhcpServer 已装,引擎 dnsmasq,段 .10-.230)→DNS 下发自控、无需碰路由器;
ContainerManager 已装(可跑 AdGuard/dnsmasq 容器);DSM Reverse Proxy 已在用
→加 SNI vhost git→localhost:3000 即可;gitea 为 3000 native 进程非容器。
唯一 caveat:证书 DSM 内置 LE 仅 HTTP-01 家里签不了→走 acme.sh DNS-01(阿里云)
或同步 ali 已有 LE。判定:W3+W4 均可行,不属于「一般 nas 不支持」。
新增 §6 可行性判定表,W3/W4 状态改可行·待建,W3 修正为 NAS 自身 DHCP。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-07 16:47:57 +08:00
wangjia
f1e527918f
docs(ci): runner 走域名注册 + 局域网/外网无感切换实现方案
...
daily 代理换成 pangolin 全局 TUN(对 Go 二进制透明,不再掐 act_runner
直连)→ relay 淘汰,runner 统一注册到域名 https://git.51yanmei.com 。
git 已在 PANGOLIN_PRIVATE_SPLIT_DOMAINS,靠 dns-system 解析:在家局域网
DNS 覆盖→LAN 直连规则先命中直达 NAS;在外公网锚点→私有域名走隧道→
pangolin1 出口→ali frp→NAS。含 SVG 架构图、机制(clientconfig 三处
注入)、六 workstream、迁移顺序、验证清单、需确认的机器改动。登记进
docs/index.html 实现计划分类。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-07 16:35:11 +08:00
wangjia
fea6f82299
feat(ci): 多账号签名 Phase 1——SIGNING_ACCOUNT 开关 + 账号密钥集切换
...
按 docs/ci-multi-account-signing-design.html 落地:
- signing.env 加 SIGNING_ACCOUNT=us|cn(CI 多账号切换的唯一开关)。
- deploy-client.yml 的 macOS/iOS job 各加 "Resolve signing account" 步(从 signing.env
读),证书/ASC 的 env 映射改为按账号三元选:us→SIGN_US_*(用户级)、cn→现有旧通用名
(用户级,不动,供其他 app 继续用)。描述文件是 app 级(绑 bundle id)→ 仓库级,与账号无关,不变。
效果:pangolin(SIGNING_ACCOUNT=us)CI 用美国证书/ASC;其他 app 的独立 workflow 不受影响;
切账号只改 signing.env 一行。注:若 SIGNING_ACCOUNT=us 但 SIGN_US_* 未配,三元会回退到
旧(中国)名 → compile 脚本按 signing.env 的美国 Team 校验会失败(fail-safe,不会误签),
故 US 账号发版前须先配齐 SIGN_US_* 用户级 secret + 仓库级美国描述文件。
YAML 校验通过;codegen 无 drift(SIGNING_ACCOUNT 不参与 gen-signing)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-07 00:17:42 +08:00
wangjia
5513377221
docs: CI/CD 多账号签名设计(Apple 多账号 × 多 App,配置切换)
...
方案:CI 签名拆成正交两维——account(用哪个 Apple 账号,Developer ID/Apple
Distribution 证书 + ASC Key 跨该账号所有 App 共享)× app(bundle 专属描述文件)。
App 在自己仓 scripts/signing.env 声明 SIGNING_ACCOUNT=us|cn 一行完成切换;工作流
读它、三元映射从 gitea 用户级取对应账号 SIGN_<ACCT>_* 密钥集,描述文件走仓库级 per-app。
证书按账号存一次共享 + 描述文件按 App 存本仓 → 避免多账号×多App 的密钥爆炸。
含三层配置模型、gitea 命名规范、workflow 切换机制(基于现有 secret→env 映射层)、
composite action 多 App 复用、新增账号/App/切换的操作手册、Phase 0(pangolin 仓库级
快速解锁)/Phase 1(完整多账号模型)分期、待核实的 gitea 能力。已登记 docs/index.html。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-07 00:08:30 +08:00
wangjia
acb9d8052b
docs: runbook 修正 App ID 能力(主 app 需 System Extension)+ 收敛为 2 个 App ID
...
实操验证补正:§1.2 原写 4 个 App ID 各勾 App Groups+Network Extensions,漏了主 app
的 System Extension 能力——缺它 macOS 主 app 的 Developer ID profile 不含
com.apple.developer.system-extension.install,构建报「profile doesn't include the
System Extension capability」。改为 2 个唯一 App ID(iOS/macOS 共用同串):主 app 需
App Groups+Network Extensions+System Extension,扩展需 App Groups+Network Extensions;
并说明改能力后 profile 变 Invalid 须重新生成。
背景:macOS Developer ID 签名链已本地端到端验证通过(build→重签→codesign 核验:
Yanmei AI LLC / 44WULXM6SV / com.yanmeiai.pangolin,零中国痕迹)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 23:17:47 +08:00
wangjia
7be0eb4c08
docs: 迁移 Runbook 更新——代码侧已完成(signing.env 单源 + codegen)
...
Team ID 已知(44WULXM6SV),§3 代码替换已落地并收敛为单一真相源:改写 §3 为
「signing.env + gen-signing.mjs codegen + drift 闸」,占位 <NEW_TEAM> 全替为真值,
顶部进度卡与 §6 责任表标注代码侧完成。剩余为 Apple 后台建资产/本机公证/gitea/验证。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 22:06:36 +08:00
wangjia
3fb645ed40
refactor(signing): 原生侧签名标识符改由 signing.env codegen 生成(单一真相源)
...
承接 scripts/signing.env(shell 单源):Xcode/Swift 侧的 Team ID/Bundle ID/App Group
等无法 source 变量、只能字面量,故用 codegen 保持单源。
- 新增 scripts/gen-signing.mjs:从 signing.env 读 3 基值,用**结构化正则**(匹配
`DEVELOPMENT_TEAM = X`/app group 形状等,不含任何旧字面值)回填 16 个原生文件的
标识符;--check 为 drift 模式。因不含旧值,codegen 自身无痕、未来再迁账号仍生效。
- ci/check-codegen-drift.sh 追加签名 drift 闸(gen-signing.mjs --check)。
- 全量迁到美国身份:Team 44WULXM6SV / 实体 Yanmei AI LLC / Bundle com.yanmeiai.pangolin
(+.PacketTunnel)/ App Group macOS 原生 44WULXM6SV.com.yanmeiai.pangolin、iOS
group.com.yanmeiai.pangolin。清理注释/ORGANIZATIONNAME 等 Apple 侧残留痕迹。
- CLAUDE.md 同步新身份 + 指向 signing.env 单源。
验证:plutil lint 6 份 entitlements/plist 全 OK;macOS/iOS pbxproj `xcodebuild -list`
可解析、Runner build settings 解析为新 Team/Bundle;gen-signing.mjs --check 幂等 0 drift;
完整 codegen drift 闸(token/l10n/proto-i18n/signing)全绿。
注:未动 Android 包名 com.pangolin.pangolin_vpn(Play 身份、自签、非 Apple 账号痕迹,
改动影响大另议)与 Windows/桌面少量元数据串。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 20:14:30 +08:00
wangjia
6618929092
fix(l10n): 断开确认三键补进 strings.json 单源(此前只手改了生成物)
...
断开确认功能(1cc5207 )当时直接手改了 strings_*.dart(生成文件),没补进真源
design/i18n/strings.json。codegen drift 闸重生成时会按 strings.json 把这三键冲掉,
且 app_text.dart 仍声明抽象 getter → 生成物缺实现会编译失败。
补 disconnectTitle/Body/Action(en/zh/es/ja/ko/ru 六语)进 strings.json;重生成后
strings_*.dart 内容与已发布逐字一致(仅改由手改改成走单源)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 20:13:46 +08:00
wangjia
baaf21df36
refactor(signing): shell 签名身份抽成单一真相源 scripts/signing.env
...
迁移美国账号引出的诉求:Team ID/实体名/Bundle ID/App Group 原本散在三个签名脚本里
硬编码,迁一次账号要改多处易漏。抽成 scripts/signing.env 单一真相源,三脚本
(local_test.sh / ci/compile-macos.sh / ci/compile-ios.sh)source 它并派生各自常量。
signing.env(非机密,入 git)含:SIGNING_TEAM_ID / SIGNING_ENTITY / SIGNING_APP_BUNDLE_ID
/ SIGNING_EXT_BUNDLE_ID / SIGNING_{MACOS,IOS}_APP_GROUP + 派生的 Developer ID /
Apple Distribution 签名主体串。当前值已是美国 Yanmei AI LLC(Team 44WULXM6SV,
Bundle com.yanmeiai.pangolin);今后迁账号/改 Bundle ID 只改这一个文件。
bash -n 三脚本语法通过;source 冒烟各派生值正确。Xcode 侧单源(Signing.xcconfig)
另提交,由一致性闸比对防两处漂移。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 20:03:43 +08:00
wangjia
47c1e3329f
docs: Apple 开发者账号迁移 Runbook(中国→美国 Yanmei AI LLC)
...
完整迁移流程:把 Pangolin 的 Apple 签名从中国「岩美北京技术」(Team BYL4KQHMTN)
整体迁到美国「Yanmei AI LLC」,目标产物+仓库无中国账号痕迹。干净切割方案(全新
Bundle ID com.yanmeiai.* + 全新 Team/证书/描述文件/公证凭据,零依赖旧账号)。
含:命名总表、Apple 后台建资产逐步(App ID/App Group/两证书/四描述文件/ASC Key)、
本机钥匙串+公证凭据配置、仓库 Team ID/Bundle ID/App Group/实体名全量替换点清单、
gitea 12 个 Apple secret 换新、无痕验收清单、责任顺序表。已登记 docs/index.html。
代码替换待用户提供新 Team ID + 证书全名后单独一批执行。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 19:42:46 +08:00
wangjia
4a76134ca9
feat(server/pay): 查单对账开通(reconcile-on-read)——付完不再干等 webhook
...
「付完刷新等十几秒」的服务端主因:GetOrder 的 activated 只认本地 row=paid,而 row
只有 webhook 到账才翻;webhook 投递+退避重投正是那十几秒。GetOrder 其实早已调 pay
网关查单(st),却只当 pay_status 展示、没用来开通。
改法(仅 pangolin,pay 无需改):GetOrder 拿到网关 st 后,若 st.Status=="paid" 但本地
row 未 paid → 用 st 拼 webhookEvent 就地调 settle(复用 webhook 同一段幂等开通逻辑),
把「等 webhook」压成「付完下一拍查单即开通」。webhook 保留作兜底。
- Handler 加可选 settler(orderSettler 接口,*WebhookHandler 已满足)+ SetSettler;
main.go 装配时 payHandler.SetSettler(payWebhook)。
- 幂等双保险:row.Status!="paid" 守卫 + settle 内锁行/已 paid 短路 → 重复轮询/并发查
不二次开通、不二次发奖。settle 失败仅记日志,退回旧展示由下一拍或 webhook 兜。
- channel 查单不返回 → 回退 row.Method(仅影响渠道显示)。成功状态词 "paid" 已对齐
pay 仓 model.OrderStatusV2,提为 payOrderPaid 常量并注释「改前对齐 pay 契约」。
- 信任模型一致:主动调 pay 自有接口(server→server,order_no 持有凭据),与现有把
st.Status 当 pay_status 透传同源,非接收外部推送,不需 webhook 那样验签。
测试:新增端到端 sqlite——网关 paid→就地开通(activated + 台账翻 paid + 真授予订阅)
且重复轮询幂等(仍 1 条订阅);网关 pending→不开通。go test ./... 全绿、vet 干净。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 09:37:54 +08:00
wangjia
55f6b1a19e
fix(client/pay): 优化付款流程两处体感——点击即时反馈 + 到账更快反映
...
复盘反馈:①点「立即购买」有一点卡顿 ②付完刷新不及时、等了十几秒。
① 卡顿:_buy 原本 await createOrder 网络往返、返回才导航,期间购买页零反馈 →
改为 start()(同步先置 creating)后立刻导航到支付页,用户点击即见页面切换+转圈
(支付页已有 creating/failed/succeeded 全相位渲染);加 _buying 防连点(避免下双单)。
② 刷新慢(客户端可控部分):
- _startPolling 首拍立即发(原 Timer.periodic 要干等一个周期才首查);
- 新增 AppLifecycleListener,付款后从微信/支付宝返回 app 即刻补查一拍
(等待付款期切后台,iOS 会挂起 Dart Timer,回前台首拍可能迟到十几秒——主因);
- 轮询间隔 3s→2s。
测试:payment_flow 新增「start 立即补一拍→已到账不等周期直接 succeeded」,
共 7 个单测 + 支付页 widget 全绿;flutter analyze 干净。
注:十几秒还有服务端一半——GetOrder 的 activated 只认本地 row=paid(仅 webhook 落),
即便主动查 pay 网关已 paid 也不即时开通。reconcile-on-read(查单时网关已成功即幂等 settle)
是更大且触及结算逻辑的改动,另议。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-05 19:52:43 +08:00
wangjia
721371d806
fix(server): 付费会话「活跃即续期」——根治 macOS 常驻隧道一天多掉线
...
根因:付费连接凭证硬编码 24h TTL(paidCredentialTTL),而客户端只在 _connect()
(用户/看门狗前台重连)才重签,服务端从不因流量续期。macOS sysext(root)隧道独立于
GUI app 常驻,用户关窗后 Dart 看门狗根本不运行 → 凭证 24h 到期、下次 agent 重注册
用「未过期」快照整表覆盖并重渲染 sing-box → REALITY 会话被剔除、永久黑洞。该逻辑
四端共用同一份 Dart,故为全端共性(macOS 最易现形)。
修法(方案 A,服务端、与客户端生命周期无关,一改修四端):
- ReportUsage 收到某 dp_uuid 有流量,若属付费套餐(!AdGate)即把其凭证 expires_at
顶到 now+PaidCredentialTTL。活跃会话永不过期;免费凭证 TTL 编码日额度、绝不续期
(否则击穿日限)。每报按 user 缓存一次 entitlement 查询。
- 新增 NodeStore.RenewCredential(纯 UPDATE,WHERE expires_at>now 不复活已过期会话)。
- 24h 提为 nodes.PaidCredentialTTL 单一真相源,httpapi 引用它消除漂移。
- 纯 DB 续期,无需再 push agent(现有 REALITY 用户仍在,只要 DB 行不过期,下次
重注册快照仍含它)。可移植 SQL(? 占位 + Go 端算时间,无 MySQL 专属构造)。
测试:handler 层付费续期/免费不续期(mock);store 层真 SQLite 续期/不复活已过期。
go test ./... 全绿、go vet 干净。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-05 19:34:58 +08:00
wangjia
1cc52075e9
feat(client): 断开连接前弹二次确认框(避免误触瞬断)
...
连接键在 on 态点击不再直接断开:先弹危险操作确认框(告知连接已加密,
确认才 toggle 断开);off/connecting 态行为不变直接 toggle。
新增 l10n disconnectTitle/Body/Action(en/zh/es/ja/ko/ru 六语)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-05 19:08:01 +08:00
wangjia
def3bb34b8
fix(server): 控制面 8080 收口——默认绑 loopback + 部署时幂等纠偏 ADDR/ufw
...
Deploy Server / deploy-server (push) Successful in 4m33s
Deploy Site / deploy-site (push) Successful in 2m19s
Deploy Client / build-windows (push) Successful in 1m39s
Deploy Client / build-android (push) Successful in 3m49s
Deploy Client / build-macos (push) Failing after 1m47s
Deploy Client / build-ios (push) Failing after 16m18s
Deploy Client / release-deploy (push) Successful in 1m39s
现网 server.env 漂移成 ADDR=:8080(全网卡),ufw 又放行 8080 → 控制面 API 明文
裸奔公网(http://<IP>:8080),绕过 cloudflared/CF 的 TLS 层。两处硬化:
- main.go:ADDR 未设时默认由 :8080 改 127.0.0.1:8080(防御纵深;跨主机监听须显式设 ADDR)
- deploy-server.sh:部署重启前幂等把 ADDR=:8080 纠回 127.0.0.1:8080(备份原文件)+
撤 ufw allow 8080/tcp。收口随 server-v* 发版自动落地,不再手改线上。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
server-v1.1.2
site-v1.1.2
client-v1.1.4
2026-08-09 10:02:10 +08:00
wangjia
bb031a04c1
fix(client/web): 语言跟随系统 + SSO 落地补 basePath + 移除账户页续费按钮
...
- 语言(#1 ):LocaleNotifier 首启无用户选择时读设备 locale(zh/ja/ko/ru/es 命中
对应语种,余回退英文),原来恒为固定默认 en、从不看系统语言。用户显式切换仍持久
化优先。
- 用户中心 SSO(#3 ):usercenter 运行在 basePath=/user,但 /sso 落地页用原生
window.location.replace('/') 跳转(Next 不补 basePath)→ 落到站点根=官网主页,
且换票已建立的会话看起来像未登录。改为 withBase() 统一补 /user 前缀,兑票成功
直达 /user/ 且保持登录态。(服务端 issue/exchange 流程实测均 200,非后端问题)
- 账户页(#4 ):移除"续费/升级"按钮(免费卡片 + PRO 横幅两处)及其未用组件;购买入口
仍由"购买套餐"行保留,不影响下单路径。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-08-09 09:42:25 +08:00
wangjia
e7e59a786d
fix(client): 默认 UI 品牌文案统一英文 Pangolin(窗口标题/托盘/安装包名/macOS 菜单栏)
...
默认 UI 语言是英文,但窗口标题(windowManager.setTitle)、MaterialApp title、
托盘 tooltip 与右键菜单、Windows 安装包显示名、macOS CFBundleName 硬编码中文,
中英混排。统一改英文品牌名;iOS 桌面图标名(CFBundleDisplayName=穿山甲)按
市场定位保留。托盘菜单文案后续可接 l10n(现契约无 tray 键)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-08-09 01:43:39 +08:00
wangjia
b59101abf1
chore(scripts): local_test 默认 API 改指生产域名(8080 公网收口后旧默认失效)
...
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-08-09 00:54:03 +08:00
wangjia
0ddcc5e935
fix(client/macos): CI 重签 sysext entitlements 补 network.client/server + 闸断言
...
Deploy Client / build-windows (push) Successful in 1m43s
Deploy Client / build-android (push) Successful in 5m13s
Deploy Client / build-macos (push) Successful in 6m53s
Deploy Client / build-ios (push) Failing after 12m28s
Deploy Client / release-deploy (push) Successful in 2m6s
v1.1.2 事故第二弹:inside-out 重签的 sysext heredoc 漏了
com.apple.security.network.client/server —— 沙箱扩展无权对外建连,
隧道起了也连不上节点(本地 Xcode 直签用仓库 PacketTunnel.entitlements
带这两键,故 local_test 流程正常,唯 CI 包不通)。
- compile-macos.sh / local_test.sh cmd_sign:sysext heredoc 补两键(与仓库源文件对齐)
- 公证前一致性闸扩展:断言 sysext 最终签名 network.client/server=true,重签丢键即 fail
- 已本地验证:对 v1.1.2 发布包用新 entitlements 重签,读回签名两键在位
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
client-v1.1.3
2026-08-09 00:49:05 +08:00
wangjia
0c6957fcb5
chore(todo): #28 App Group 修复已发版 client-v1.1.2,标 done 待验收
...
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-08-09 00:07:14 +08:00
wangjia
6a4da3e164
chore(todo): 记 #28 App Group 事故复盘 + #29 chenxin 凭据过期 + #30 四语支付文案缺口
...
Deploy Client / build-windows (push) Successful in 1m43s
Deploy Client / build-android (push) Successful in 6m57s
Deploy Client / build-macos (push) Successful in 8m43s
Deploy Client / build-ios (push) Successful in 4m53s
Deploy Client / release-deploy (push) Successful in 2m6s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
client-v1.1.2
2026-08-08 23:41:36 +08:00
wangjia
77302cfa7a
fix(client/macos): CI 重签 App Group 修回 macOS 原生格式 + 公证前一致性闸
...
compile-macos.sh 的 sysext entitlements 曾硬编码 iOS 风格 group. 前缀,且主 app
entitlements 缺 application-groups —— 与 NEMachServiceName 前缀对不上,
nesessionmanager 报 Code=6,sysextd 当场卸载新扩展,线上包永远建不出 VPN 配置
(本地 Xcode 直签流程正常,故长期未察觉;详见 todo #28 )。
- compile-macos.sh: 两处 entitlements 改用 ${APP_GROUP};公证前加一致性闸
(读最终签名核对 app/sysext App Group 与 NEMachServiceName 前缀,不一致即 fail)
- local_test.sh: 同款修复 + verify_app_group 闸 + cmd_bump_build 自动递增
sysext 构建号 + macos 一条龙子命令(bump→build→闸→公证→装→跑)
- pbxproj: CURRENT_PROJECT_VERSION 53→55(本地已构建两次,保持单调)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-08-08 23:41:36 +08:00
wangjia
79830cb43f
fix(ci): client release-deploy 加 if 守卫,mac/ios 抖失败不阻发布
...
Deploy Client / build-windows (push) Successful in 1m42s
Deploy Client / build-android (push) Successful in 5m8s
Deploy Client / build-macos (push) Successful in 8m3s
Deploy Client / build-ios (push) Successful in 4m59s
Deploy Client / release-deploy (push) Successful in 2m2s
run 239:android/windows/macos 全绿、ios 在 Checkout 阶段 git fetch
git.51yanmei.com 走 frps 超时挂掉(非 iOS 构建问题;run 238 同代码 fetch 碰巧
成功)。因上一版把 build-ios 加进 release-deploy 的 needs,而 gitea 里
continue-on-error 的 job 失败**仍会 skip 下游 needs** → release-deploy 被跳过。
修:needs 保留四平台(等全部完成、不抢跑 → 收齐已上传产物),但加
`if: always() && needs.build-android.result == 'success'` —— 只要 android
(稳定 floor)成功即发布,mac/ios/windows 的瞬断失败不再 skip release-deploy,
download-artifact 收当时存在的产物照发。
yaml 校验通过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
client-v1.1.1
2026-08-03 00:17:53 +08:00
wangjia
fdc13ea06c
fix(ci): client release-deploy 挪到 nas runner + 等全平台构建
...
Deploy Client / build-windows (push) Successful in 1m41s
Deploy Client / build-android (push) Successful in 4m40s
Deploy Client / build-macos (push) Successful in 7m30s
Deploy Client / build-ios (push) Failing after 11m51s
Deploy Client / release-deploy (push) Has been skipped
client-v1.1.1 首跑:4 平台 build 全绿,但 release-deploy 卡在「Release →
Forgejo」curl exit 28(超时,3m3s=release_ensure 60s×3 重试耗尽)。根因:
release-deploy `runs-on: mac`(mac-pangolin-2)访问 git.51yanmei.com 走 frps
隧道 → 抖断。deploy-server/deploy-site 同类 Forgejo release 步跑在
ubuntu-latest(nas act_runner,与 gitea 同机/同网)稳定通过(server 仅 13s)。
- runs-on: mac → ubuntu-latest:release-deploy 全为网络/SSH 步骤(下载产物/
传 Forgejo/SSH pangolin1/通知),无 mac 专属需求,挪到 nas runner 走本地。
- needs: [build-android] → [build-android, build-windows, build-macos, build-ios]:
等全部平台 build 完再发布,修旧竞态(只等 android → macos/ios 产物没传就发布
漏平台)。macos/ios 保留 continue-on-error,失败不阻断已成功平台。
- 更新过时注释(原称 Apple secret 未配 / needs 仅 android+windows)。
yaml 校验通过。build 四平台本身已在 run 639 全绿,本次只修发布环节。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-08-01 23:47:29 +08:00
wangjia
f0f845c6e5
fix(ci): site 流水线加 npm 国内镜像(GFW)+ npm ci 重试
...
Deploy Site / deploy-site (push) Successful in 2m6s
Deploy Client / build-windows (push) Successful in 1m43s
Deploy Client / build-android (push) Successful in 20m37s
Deploy Client / build-macos (push) Successful in 8m19s
Deploy Client / build-ios (push) Successful in 5m29s
Deploy Client / release-deploy (push) Failing after 24m14s
site pipeline(deploy-site.yml:Astro 官网 + Next.js 用户中心 + npx wrangler)
在墙内 nas runner 上 npm ci / npx wrangler@4 直连 registry.npmjs.org → 慢/抖断。
_env.sh 早有 Go(goproxy.cn)/Flutter(flutter-io.cn)镜像,唯独漏了 npm,且 3 个
site 脚本根本没 source _env.sh。上次「修外网发版 GFW 坑」只覆盖 android(gradle)/
windows(maven),site 这块遗漏。
- _env.sh:加 NPM_CONFIG_REGISTRY=registry.npmmirror.com(可 env 覆盖)+ npm_ci_retry
助手(照 flutter_pub_get_retry,5 次重试)。
- compile-site.sh / compile-usercenter.sh:source _env.sh,npm ci → npm_ci_retry。
- deploy-site.sh:source _env.sh,让 npx wrangler@4 也走镜像拉包。
本地实跑 compile-site.sh:镜像生效、Astro 构建成功、dist/ 产物齐全(index.html 48K
+ 多语言目录)。shellcheck -x 全 clean。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
site-v1.1.1
2026-08-01 20:32:37 +08:00
wangjia
b255fdfb4e
chore(ci): CI 校验迁本地(ci/check-local.sh),删 pipeline ci.yml
...
ci.yml 跑在自建 gitea 的 mac-pangolin-2 runner 上,该 runner 不稳:重 job
(go/flutter/golden/integration/e2e)频繁整体超时/失败(run 233、236 复现:所有
runs-on=mac 的 job 全挂、runs-on=ubuntu 的 nas 快扫描全过,证明是 mac runner
掉线而非代码)。既然开发就在 mac 上、原生工具齐全,把校验迁回本地。
- 新增 ci/check-local.sh:与 ci.yml 各 job 一一对应,dev mac 原生跑(仅 golden
因 Linux 权威基线走 docker)。分档:默认=静态闸+go build/test+flutter analyze/test
(各带覆盖率闸 Go30%/Flutter28%);--full 加 golden/go-integration/e2e;
--only <名> 单跑;--list 列项。缺工具标 SKIP 不算失败。shellcheck-clean。
- 删 .gitea/workflows/ci.yml(部署流水线 deploy-server/client/site 保留,发版
仍过 go test)。
- .githooks/pre-commit:秒级快闸不变,指引改指 ci/check-local.sh(原指 CI)。
- CLAUDE.md CI/CD 段重写 + ds-flow 闸表「CI」触发点改「check-local」。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-08-01 10:20:18 +08:00
wangjia
9aafb63461
chore(todo): 同步最新看板到 main(#24-#27 + #23→done)
...
Deploy Server / deploy-server (push) Successful in 4m7s
主 checkout 停在陈旧 feat/private-dest-acl,其工作区 todo 看板反而领先 main
4 条(#24 UI连接态脱钩 / #25 私有服务在家直连 / #26 MySQL Promo 并发防线 /
#27 分支审核 Minor 硬化)且 #23 已推进到 done。工作区是 main 的干净超集
(main 无任何独有条目),取工作区版覆盖回 main,零丢失。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
server-v1.1.1
2026-08-01 02:12:34 +08:00
wangjia
6f232d4043
fix(routing): 堵住 ip_cidr direct 旁路系统层 + 客户端保存失败可见提示
...
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (push) Successful in 19s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 18s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (push) Failing after 13m6s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 13m16s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Failing after 13m25s
ci-pangolin / Go — build + test (push) Failing after 13m35s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (push) Failing after 13m45s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Failing after 13m54s
ci-pangolin / Flutter — analyze + test (push) Failing after 14m5s
ci-pangolin / OpenAPI Sync Check (push) Failing after 14m16s
ci-pangolin / Lint — shellcheck (push) Failing after 14m27s
分支审核发现两处 Important,合并前修复。
① [安全] direct 的 ip_cidr 用户规则可自伤式旁路整条隧道:
Validate 原先只校 CIDR 语法。用户提交 ip_cidr=0.0.0.0/0 action=direct
(或 172.16.0.0/12,含隧道 DNS 172.19.0.2)会并入 TUN 入站
route_exclude_address(OS/auto_route 层,位于系统强制层之下),被排除的
流量根本不进 sing-box → hijack-dns 与整条隧道被静默旁路,违反「系统层
用户不可越」铁律。
- Validate: direct 的 ip_cidr 拒绝 catch-all(/0)及与保留段 172.16.0.0/12
重叠(写入闸)。
- clientconfig 渲染层:新增 routing.SafeToExclude 守卫,只有安全的 direct
ip_cidr 才并入 route_exclude_address(纵深防护,兜底写入闸之前的历史坏行)。
- 测试 TestValidateDirectIPCIDRReservedGuard 钉死:拒 catch-all/隧道段重叠、
放行 proxy catch-all 与不重叠 direct。
② [健壮性] 客户端保存失败静默回滚 + 抛未捕获异步异常 + 对话框无字段校验:
_persist 失败会 rethrow(约定调用方 catch),但屏幕层所有回调
(setMode/setBuiltin/addRule/removeRule/reorder/resetToDefault)均未 catch,
规则闪现即消失、无提示,且 rethrow 变 zone 未处理异常。
- 新增 _guardSave 守卫:await + 失败弹 SnackBar(AuthApiException 显服务端
双语文案含校验错,其余回退通用「保存失败」),包裹全部变更类回调。
- 添加规则对话框:_valueError 字段级预校验(ip_cidr 用 InternetAddress
校验、geo 白名单仅 cn),非法即禁用保存并内联红字提示;语义级(保留段)
仍由服务端权威判定经 SnackBar 呈现。
- l10n 单源新增 routingSaveFailed / routingRuleValueInvalid(6 语),regen。
go test ./... 全绿;flutter analyze 无 error;flutter test 265 全过无 golden 回归;
codegen 幂等、原型 i18n 无漂移。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-08-01 00:32:52 +08:00
wangjia
e157b16c11
fix(server): 走隧道/拒绝的域名规则也开 reverse_mapping
...
用户规则(可配置分流)里 action==proxy/reject 的域名规则,此前不触发
dns.reverse_mapping(只有 direct 域名规则触发)。而应用自行解析域名后按 IP
发起连接,路由层只剩 IP,无反向映射则 domain 规则永不命中——走隧道/拒绝的
域名规则会静默失效。
translateUserRules 把 hasDomainDirect 扩成 hasDomainRule:任意 action 的
域名类规则(domain/domain_suffix/domain_keyword)都置真、都开 reverse_mapping。
direct 专属的 ip_cidr→route_exclude_address(extraExclude)那条线不变。
这也是把私有服务分流(PANGOLIN_PRIVATE_SPLIT_DOMAINS)改用用户规则表达的
前置修复——否则一条"走隧道"用户规则替代 private-split 会连不上。
回归测试 TestBuildConfigProxyDomainEnablesReverseMapping:唯一一条走隧道/拒绝
域名规则(privateSplit 关、无 direct 域名规则)必须开 reverse_mapping。go test ./... 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-31 01:15:34 +08:00
wangjia
ce485a1b62
fix(ui): SegSwitch 用 FittedBox(scaleDown) 防窄容器截断文字
...
添加规则弹层的动作段选(Direct/Tunnel/Reject)在窄弹层里被 icon+文字挤到 ellipsis 截断
成「Dire…/Tun…/Reje…」。改:段内容包 FittedBox(scaleDown)——放得下原样(宽段选/goldens
不变),放不下整体等比缩放而非截断;padding 16→12 留余量。flutter test 265/265 无 golden 回归。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-29 08:42:27 +08:00
wangjia
49d0c5d2df
docs(claude): 记 iOS 真机装机(local_test.sh ipad,老忘)+ CI 发版(tag触发+私有依赖鉴权)+ 可配置分流功能
...
- 移动端段加真机装机:API_URL=... local_test.sh ipad <设备>(公司分发证书/签名核验/xcurl 装机);
iOS libbox gitignore 产物从主仓拷免重建;新设备 -allowProvisioningDeviceRegistration。
- CI/CD 段更新:tag 触发发版(server-v*/client-v*/site-v* → compile→test→release→deploy pangolin1
备份+migrate+回滚+healthz),取代过时的「仅校验无部署」;私有依赖 github.com/wangjia/codes→gitea
鉴权(GOPRIVATE+insteadOf,冷缓存 runner 必踩);发版排障(gitea actions API + rbw gitea 读写key)。
- server/ 加可配置分流小节:routing_profiles/GET-POST me/routing/BuildClientConfig 翻译(层级/三模式/
IP直连 route_exclude 在 tunIn/域名直连 reverse_mapping/nil 逐字节不变)/system_locked_domains。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-29 08:23:42 +08:00
wangjia
cd0ba919d1
fix(ci): deploy-server 编译前给私有依赖 github.com/wangjia/codes 配 gitea 鉴权
...
Deploy Server / deploy-server (push) Successful in 4m17s
冷缓存 runner 上 go build 拉私有 codes 依赖时,GOPROXY=goproxy.cn 对私有仓 404 →
回退 direct git 到 github.com → 无凭证失败(server-v1.1.0 首发在此挂,44s Compile 步红)。
加一步:GOPRIVATE + git insteadOf 把 github.com/wangjia/codes 重写到自建 gitea 并注入
FORGEJO_TOKEN(已验证 oauth2:<token> basic-auth 可 ls-remote 到 pin 的 commit)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
server-v1.1.0
2026-07-29 07:50:35 +08:00
wangjia
a307c6ca2c
fix(test): codes-lib 迁移往返测试改用 m.Migrate(21) 显式定位版本
...
Deploy Server / deploy-server (push) Failing after 41s
TestCodesLibMigrateRoundTrip 硬编码 6 次 Steps(-1),假设 000027 是迁移栈顶;本功能
加了 000028_routing_profiles 后 6 步落在版本 22、跳过了 000022 down,导致断言失败。
根因不是迁移 SQL(000022 up/down 正确、codes-lib 表无 FK——推翻了 FK 假设),而是
测试的脆弱步数计数被新增迁移打乱。改用 m.Migrate(21) 显式降到 000022 down 之后的
边界,不受栈顶新增迁移影响。全仓 go test ./... 恢复 0 FAIL。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-29 07:08:56 +08:00
wangjia
2930d76cf3
feat(routing): 域名级系统锁冲突提示 + 重置默认按钮 + 客户端 follow-up 清理
...
承接 FT-A(GET /v1/me/routing 含只读 system_locked_domains)。
- RoutingProfile 加只读 systemLockedDomains(fromJson 读/toJson 不输出);
routing_screen 冲突检测扩展到域名类规则(domain/domain_suffix/domain_keyword
命中锁定域名 → systemLocked),ip_cidr 私网启发式保留。
- RoutingProfile.defaults() + RoutingProfileNotifier.resetToDefault()(复用
_persist:乐观更新/失败回滚/存成功后自动重连,保留只读 systemLockedDomains
不丢)+ routing_screen 加「重置默认」按钮与二次确认弹层(新增 3 个 l10n 键)。
- RoutingRule.copyWith 用哨兵支持 note 显式清空为 null;RoutingRule/Builtin/
RoutingProfile 加值相等 operator==/hashCode。
- T8 smartRouteSub 清理:grep 全仓发现 design/prototype/i18n/alias.json →
gen_proto_i18n.mjs(CI 漂移闸)仍有活引用,按计划口径不删,详见
.superpowers/sdd/task-FTB-report.md。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-29 06:57:58 +08:00
wangjia
3159dd75c1
refactor(routing): 暴露 system_locked_domains + 服务端 follow-up 清理(FK/Validate/dedup/exclude单源/共用Store/Builtin保留)
2026-07-29 06:38:52 +08:00
wangjia
52912268d0
docs(routing): 可配置分流 spec 状态 → Phase 1 已实现
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-28 09:34:35 +08:00
wangjia
4c76c2a701
feat(routing): 存档案后连接态自动重连使新规则生效
...
Task 9: RoutingProfileNotifier._persist() 保存成功后,若 connectionProvider.phase
== on,触发 ConnectionController.reapplyRoutingProfile()(disconnect→connect,
不改选中节点)重连,让服务端按新档案渲染的规则生效;off 态不触发。
新增 l10n 键 routingRulesReconnecting(单源 design/i18n/strings.json → codegen),
「规则已更新,正在重连…」区别于既有 nodeReconnecting(弱网抖动语义)。
reapplyRoutingProfile 内先置 _userDisconnect=true 再 disconnect,避免其触发的
kernel off 事件被 _onKernelStatus 误判「意外掉线」、再抢跑一次 watchdog 自动重连。
2026-07-28 09:17:32 +08:00
wangjia
86e5b6d451
feat(routing): 设置入口改分流规则下钻行 + 双形态导航
...
- settings_page.dart: smartRoute 布尔开关行 → 分流规则下钻行(标题 + 当前模式 pill
+ chevron),点击 desktop/tablet 切 navViewProvider 内容区下钻,mobile 全屏 push
RoutingScreen(与 account_page.dart 的 open() 双形态导航同一范式)。
- navigation_provider.dart: 新增 NavView.routing + kSettingsSubViews 集合(登记
settings 的下钻子页,供 shell backTarget 判断返回 settings 而非 account)。
- desktop_shell.dart/tablet_shell.dart: 内容区 switch 挂 RoutingScreen(embedded:
true),backTarget 优先判 kSettingsSubViews → 回 settings。
- settings_ia_test.dart: 追加下钻行断言(标题+模式pill+点击导航到 RoutingScreen)。
- 重录 desktop_settings golden(唯一因本刀布局变化受影响的 golden)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-28 09:04:46 +08:00
wangjia
d73b6da110
feat(routing): 分流规则子屏 UI(模式/内置/我的规则/添加/冲突提示)
...
- 新增 RoutingScreen(ConsumerWidget):代理模式段选(全局/智能/直连)→setMode、
内置规则卡(国内直连开关 + LAN 强制锁定行)、我的规则 ReorderableListView
(拖动排序→reorder、删除→removeRule)、添加规则弹层(类型 chip + 目标输入 +
动作段选→addRule)、FINAL 兜底行。非智能分流模式「我的规则」区灰化+忽略提示。
- 冲突提示:①同 type+value 被更靠前规则遮蔽 →「已被上面规则覆盖」(纯本地计算);
②自定义 ip_cidr 规则落在私网/回环地址段 → 系统锁定提示(启发式,详见文件头注释
——真正的私有服务域名清单未经 API 下发给客户端,是已知缺口)。
- l10n 新增 9 个 key(routingTypeDomain/DomainKeyword/IpCidr/Geoip、
routingRuleShadowed、routingModeNote、routingRuleValueHint、routingNoRules),
经 design/i18n/strings.json 单源 + gen_l10n_dart.mjs 生成六语。
- 补生成 pangolin_icons.dart 的 plus 图标(design/prototype/icons.js 已有,
codegen 之前未跑过)。
- 新增 widget 测试 test/widget/routing_screen_test.dart:模式段选/规则行/添加
按钮可见、非智能模式灰化、重复规则遮蔽提示,共 3 例。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-28 08:51:40 +08:00
wangjia
057c11eee2
feat(routing): 客户端 model + AccountApi + AsyncNotifier provider
...
- RoutingProfile/RoutingRule/Builtin 手写 fromJson/toJson/copyWith,对齐服务端
GET/POST /v1/me/routing 契约;enabled 缺省容错默认 true,toJson 恒输出该字段
- AccountApi.routingProfile()/saveRoutingProfile() 封装两端点
- RoutingProfileNotifier(AsyncNotifier):addRule/removeRule/updateRule/reorder/
setMode/setBuiltin 均本地乐观更新后落盘;save() 失败整体回退到变更前 state
并 rethrow(不静默吞,交调用方处理)——Riverpod asyncTransition 的 seamless
copyWithPrevious 会用当前已存 state 覆盖手动挂的错误值,故不用 AsyncError
路径,改走显式回退
2026-07-28 08:27:43 +08:00
wangjia
82b3988974
feat(routing): connect 读 per-user 档案传入渲染(fail-safe 回退默认)
2026-07-28 08:11:48 +08:00