wangjia
cadd527680
feat(backend): 挂载 /v1 API + 实现 nodes/connect 端到端
...
- 新增 internal/dpcred 包,统一 DeriveHy2Password + DefaultFlow
agentd 与 HTTP connect handler 共享同一实现
- 新增迁移 000011:nodes 表拆分 reality_prk 私钥 / reality_pbk 公钥
reality_short_id;修正 handler_grpc.go 使用私钥字段
- 新增迁移 000012:connect_credentials 持久化凭证
实现 CredentialsForNode 修复 agent 重连 resync 原先返回空的桩
- 扩展 NodeStore 接口:ListUp / EntitlementForUser /
PersistCredential / DeleteCredential;同步 grpc_test.go mock
- 新增 httpapi/nodes.go:GET /nodes、POST /nodes/id/connect
Hub.Push + PersistCredential + 渲染完整 sing-box client 配置 JSON
POST /nodes/id/disconnect
- 新增 httpapi/account.go:GET /me、GET /plans、GET /notices
- 新增 httpapi/clientconfig.go:BuildClientConfig 服务端渲染
- 重写 cmd/server/main.go:手写 chi public/protected 分组
nodes.Service/Hub 在 main 构造并共享;SMTPMailer/LogMailer
go build ./... && go vet ./... && go test ./... 全部通过
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-15 23:09:56 +08:00
wangjia
b35bfe10dc
merge: 自动更换编排 + 养机灰度 [tsk_mxEFSvKHX64G]
2026-06-15 22:05:22 +08:00
wangjia
7627c8a195
feat(scheduler): 自动更换编排 + 养机灰度 [tsk_mxEFSvKHX64G]
...
实现 15E 任务:Replacer 状态机(pending→creating→probing→activating→draining_old→done/failed)
+ Grayscale 权重梯度(10→25→50→75→100,每步 6h)。
关键设计:
- Redis JSON 记录(sched:replace:{uuid})+ SetNX 崩溃安全,防止重复 CreateNode
- 幂等 key:attempt 0 = uuid,retry N = uuid:retry:N
- probePass:国内 ≥2/3 ISP 通过 + 海外 L1 全通,连续 2 Tick 才晋级
- 探活超时 15min → failProbeAttempt → 轮换 provider;3 次失败 → failed + NotifyFault
- StubBreaker(15F 未就绪);NewReplacer(Config{}) 依赖注入
- 6 个集成测试全部通过(happy path / max-retry / crash recovery / queue idempotency / grayscale)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-15 21:26:07 +08:00
wangjia
fb267e1114
merge: iOS 端 PoC M3 + entitlement 申请 [tsk_F5r4Kt9m_wQU]
2026-06-15 20:56:46 +08:00
wangjia
be44ef1226
merge: iOS M3 PoC — PacketTunnelProvider + entitlement [tsk_nsobbj_rJdy0]
2026-06-15 20:56:46 +08:00
wangjia
2ebd8c4054
merge: Android M2 VPN 隧道 PangolinVpnService [tsk_w1NvZdmwGPyd]
2026-06-15 20:56:37 +08:00
wangjia
323e1da04d
merge: 桌面端 PoC M1 — sing-box 子进程 TUN 接线 [tsk_SLCsjNgtmng3]
2026-06-15 20:56:37 +08:00
wangjia
58e2bb0190
merge: gRPC server + hub + 跨实例 pub/sub [tsk_mF5RWPEwngai]
2026-06-15 20:56:28 +08:00
wangjia
5d54aa2fb2
merge: 判定引擎 signals+rules+streak [tsk_OYEiDCzM9_0Y]
2026-06-15 20:56:22 +08:00
wangjia
690f990722
merge: devices + 订阅校验中间件 [tsk_x7wrlA87orsY]
2026-06-15 20:56:14 +08:00
wangjia
2c182fcdcf
merge: probe ingest endpoint + Redis store [tsk_rBPr0Xuy10bz]
2026-06-15 20:55:32 +08:00
wangjia
bfecb4314c
merge: gRPC server + hub + 跨实例 pub/sub [tsk__58l3wTLvaSn]
2026-06-15 20:53:25 +08:00
wangjia
bf3b6fd210
merge: apierr + idgen + CONVENTIONS.md [tsk_nI2T8qpcoier]
2026-06-15 20:51:08 +08:00
wangjia
1648871a2a
docs(infra): 补全拓扑图 CSS;todo: 更新任务进度
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-15 19:26:08 +08:00
wangjia
b2cb20be47
chore(design): 删除 design/flutter fork,更新 .gitignore
...
删除 design/flutter/(21 个文件):
- Flutter token/组件的 canonical 实现已在 client/lib/
- Token 数值层改由 design/codegen/gen_flutter_tokens.mjs codegen
- 设计规格由 design/preview/ specimens + SKILL.md 表达
.gitignore 新增:
- client/android/local.properties、client/android/app/src/main/java/
- client/ios/Flutter/ephemeral/、client/pubspec.lock
- .claude/worktrees/(临时工作目录)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-15 19:11:01 +08:00
wangjia
b04cef3cc4
chore(design): 建立 token 单源管线,删除 design/flutter fork
...
- 新增 design/codegen/gen_flutter_tokens.mjs:
从 colors_and_type.css codegen 出 client/lib/pangolin_tokens.gen.dart
覆盖 PangolinColors/Spacing/Radius/Motion/Shadow(纯数值层)
- 重构 client/lib/pangolin_theme.dart:
删除手抄数值,import+export pangolin_tokens.gen.dart
保留实现层 PangolinScheme/PangolinText/PangolinTheme/PangolinContext
19 个引用方零改动,对外 API 完全不变
- 新增 web/usercenter/scripts/build-tokens.mjs:
仿 website 样板,prebuild/predev 自动从 css 生成 public/colors_and_type.css
去除 usercenter 手抄副本的漂移风险
- 更新 CLAUDE.md:补 token codegen 使用说明与单源模型
- 更新 design/SKILL.md:移除已删 flutter/ 引用,补 codegen 入口
验证:改 clay-500 → 三端 codegen 同步变化;flutter analyze 无新增 error。
注:design/flutter/ fork 手动删除(git rm 需用户执行)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-15 18:27:22 +08:00
wangjia
88757b2ac4
feat(detect): 判定引擎 signals+rules+streak (tsk_OYEiDCzM9_0Y)
...
新建 server/internal/scheduler/detect/ 包,实现任务 15D:
## 核心模块
**lifecycle.go**
- 定义 LifecycleService Go interface(ListNodes / TransitionStatus / SetWeight /
BumpVersion / GetLoad / GetLoadHistory),供 #5 真实实现,内含乐观锁语义(0 行
受影响即本周期放弃,幂等可重入)
- 提供 MockLifecycle 内存 stub(SetConflict / Events 等测试辅助方法)
**signals.go**
- computeSignals:读 SnapshotsByNode,归一化为 NodeSignal
- domesticFailISPs:按 ISP 聚合(stripPrefix "3rd-" 合并 15B/15C 同 ISP 视角),
L3 失败权重最高(L3 挂即记该 ISP 失败,即使 L1/L2 通),无数据 vantage 不计分母
- overseasOK:境外对照点全部 L1 通为真
- trafficDropPct:15min 前后半段在线数降幅百分比
- ProbeSnapshotter interface(解耦 probe.Store,便于 mock)
**rules.go**
- DetectConfig:全量阈值常量(DomesticFailNumerator/Denominator=2/3、
SuspectStreakMin=2、TrafficDropThreshold=80%、TrafficBaselineMin=20、
ConfirmedStreakMin=6、RecoverStreakMin=2、SuspectWeight=10)
- isSuspectTriggered:整数算术避免浮点误差(fail×den >= total×num)
- isFault / effectiveSuspectStreakMin / isTrafficWarning 规则助手
**streak.go**
- StreakStore:Redis hash detect:streak:{node}(fail_streak / suspect_streak /
recover_streak),TTL 2h(宽于 6×5min=30min),进程重启后自动恢复
**engine.go**
- Engine.Tick(ctx):列举 up/blocked_suspect 节点,按节点依序运行五条规则
- Rule 1 suspect:≥2/3 ISP 失败 + 境外正常 → 连续 2 周期 → up→blocked_suspect,
weight→10,写 probe:freq:{node}=60(1min 提频标记),BumpVersion
- Rule 2 流量预警:trafficDrop≥80% + 基线≥20 → suspect 门槛放宽至 1 周期
- Rule 3 confirmed:blocked_suspect 连续 6 周期 → blocked_confirmed → down(跳过
draining),入队 detect:replace:queue(JSON: nodeId + replacementUuid)
- Rule 4 recover:suspect 期间境内连续 2 周期恢复 → up(weight 交 15E warmup)
- Rule 5 fault:境内+境外同时失败 → 不迁移,调 Notifier.NotifyFault(log stub)
- Notifier interface + LogNotifier stub(15G 就绪前输出 slog.Warn)
**engine_test.go**(19 个测试,全部通过)
- 表驱动覆盖:恰好 2/3 失败、1/3 失败不触发、9min vs 10min streak、
流量预警 1 周期即 suspect、suspect 第 6 周期 confirmed、境内外同挂 fault 不迁移、
恢复 2 周期回 up、3rd- 前缀合并、L3 覆盖 L1/L2
- 乐观锁冲突:SetConflict → 放弃本周期 → 无副作用 → 解冲突后正常重试
- 进程重启:同一 miniredis,新 Engine 读取已存在 streak 继续计数不误清零
- 产出验证:replace queue JSON 结构、probe:freq 标记、weight 变更、事件 detail 字段
**migrations/000010_node_blocked_statuses.{up,down}.sql**
- 扩展 nodes.status ENUM 加入 blocked_suspect / blocked_confirmed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 20:15:13 +08:00
wangjia
7a1715bd09
merge: iOS 端 PoC M3 + entitlement 申请 [tsk_F5r4Kt9m_wQU]
...
解决合并冲突(原任务 tsk_nsobbj_rJdy0 分支 maestro/tsk_nsobbj_rJdy0):
两分支修改文件集合无重叠,手动 apply iOS PoC commit (e129f09 )。
变更内容:
- client/ios/PacketTunnel/PacketTunnelProvider.swift:完整 M3 实现
(startTunnel/stopTunnel/handleAppMessage/LibboxPlatformInterface)
- client/ios/PacketTunnel/MemoryMonitor.swift:新增 NE 进程内存打点
- client/ios/PacketTunnel/PacketTunnel.entitlements:NE + App Group 权限
- client/ios/Runner/Runner.entitlements:主 App NE + App Group 权限
- client/ios/Runner/VpnManager.swift:红线词修复 + App Group 缓存 + NEVPNStatus 订阅
- client/ios/Runner/Info.plist:NSVPNUsageDescription 红线词修复
- client/ios/PacketTunnel/Info.plist:CFBundleDisplayName 红线词修复
- client/ios/Runner.xcodeproj/project.pbxproj:
CODE_SIGN_ENTITLEMENTS 添加到全部 build config;MemoryMonitor 加入 Sources
- app/kernel/build-ios.sh:M3 内存裁剪决策记录
- doc/ne-entitlement-申请指引.md:新增 NE entitlement 申请完整指引
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 20:14:32 +08:00
wangjia
8ed1cfcc75
merge: gRPC server + hub + 跨实例 pub/sub [tsk_mF5RWPEwngai]
...
Resolve merge conflict between maestro/tsk__58l3wTLvaSn (gRPC nodes feature)
and main (admin backend + JWT config + OpenAPI routes):
- server/cmd/server/main.go: keep admin backend (startAdminIfConfigured) AND
add gRPC agent server (startGRPC) — both coexist as independent optional
listeners governed by their respective env vars
- server/internal/config/config.go: keep JWT fields (JWTPrivateKeyPath /
JWTKeyID / JWTPublicKeys) AND add gRPC fields (GRPCAddr / CAKeyPath /
CACertPath / GRPCCertPath / GRPCKeyPath)
- server/internal/nodes/: add all new files from tsk__58l3wTLvaSn
(hub.go, hub_test.go, load.go, handler_grpc.go, grpc_test.go,
service.go, store.go) — 18 tests, all passing
Test: go test ./internal/nodes/... → PASS (18/18)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 20:10:01 +08:00
wangjia
628440b3f9
style(pangolin): gofmt store/mysql.go(import 排序)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-13 18:52:30 +08:00
wangjia
20a1f8e2af
merge: 管理端最小后台 + TOTP 双因素 [tsk_SCMtcGF4F434]
...
以 main 现有 cmd/server 设计为准(保留 probe + /v1 路由),叠加分支新增:internal/admin/ 自包含后台(session/2FA/IP 白名单/审计/模板)、internal/totp/ + cmd/adminctl/(TOTP + 管理员创建 CLI)、cmd/server/main.go 的 startAdminIfConfigured()(opt-in:ADMIN_SECRET_KEY+DB_DSN 才起)。统一 getenvDefault 命名;go.mod 取 HEAD + go mod tidy(x/term 提为直接依赖);admins 迁移与 main 既有 000008_provision 撞号,重排为 000009_admins。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-13 18:47:38 +08:00
wangjia
03b00b9a0f
merge: config + store(UTC DSN) + 自动迁移 [tsk_zRA6fGU1JuHj]
...
以 main 现有 config 设计为准(FromEnv/*Config/单 DSN/RS256),移植分支新增的 store 层:mysql.go 的 Open(*config.Config) 改用 cfg.DSN、结构化强制 UTC + 会话时区断言;migrate.go + migrations/embed.go 提供 golang-migrate 嵌入式迁移;cmd/migrate/main.go 实现 migrate CLI(读 DB_DSN)。未采用分支的 Load()/PANGOLIN_ 前缀/MySQL 拆分字段(与 main 设计冲突)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-13 18:42:46 +08:00
wangjia
e91f0063e0
chore(pangolin): 还原批量合并误并入的 doc/todo WIP(回退到 WIP 前,WIP 抽回为未提交)
2026-06-13 18:06:53 +08:00
wangjia
3c6a8a517a
feat: 桌面端 PoC M1 — sing-box 子进程 TUN 接线 [tsk_SLCsjNgtmng3]
...
实现桌面端(macOS PoC)内核子进程管理,打通 sing-box TUN 模式全链路:
### client/lib/bridge/kernel_process.dart(完整实现,替换原有 stub)
- ClashApiClient: HTTP 客户端,支持 /connections / /proxies / /traffic(SSE) / /traffic(plain)
- Bearer Token 鉴权;getConnections 用于就绪探测与流量统计;getTraffic SSE 读首帧后断开
- KernelProcess 接口: 新增 statusStream / statsStream 至接口定义
- DesktopKernelProcess:
- spawn(configPath): 解析 Clash API 端口/secret → sudo sing-box run(macOS PoC)→
轮询 /connections 等待就绪(20s 超时)→ emit connecting→on
- kill(): SIGTERM + 等待 gracePeriod(5s) → SIGKILL → emit off
- 意外退出: emit error(UI 可一键重连,不崩溃)
- 统计轮询: 每秒 GET /connections,差分算 uploadSpeed/downloadSpeed
- 二进制解析: ENV > exe同目录 > macOS Bundle Resources > 开发目录 > /usr/local/bin
- 辅助函数: generateClashApiPort(高位随机)、generateClashApiSecret(32B hex)
### client/lib/bridge/desktop_vpn_bridge.dart(新文件)
- DesktopVpnBridge implements VpnBridge:
- start(configJson): injectClashApi(注入随机端口+secret)→ writeConfig(0600)→ kernel.spawn
- stop(): kernel.kill(5s)
- statusStream / statsStream: 代理 KernelProcess 事件流
- selectOutbound: Clash API PUT /proxies/{group}
- getActiveOutbound: 从 /proxies 读 now 字段
- configDirOverride: 测试注入支持
- injectClashApi: 静态方法,尊重已有 clash_api 配置,合并保留 experimental 其他字段
### client/test/bridge/kernel_process_test.dart(新文件)
- ClashApiClient 完整测试: headers / 解析 / PUT body / DELETE / 非 200 抛 HttpException
- generateClashApiPort / generateClashApiSecret 生成范围和格式测试
- DesktopVpnBridge.injectClashApi: 注入 / 尊重已有 / 保留字段 / 保留其他 experimental / 非法 JSON
- DesktopVpnBridge + FakeKernelProcess 集成: connecting→on / stop→off / statsStream / 意外退出 / spawn失败
### app/kernel/poc/(新目录)
- reality_client.config.json.tmpl: VLESS+REALITY+TUN 客户端配置模板
- TUN inbound: auto_route + strict_route(macOS kill-switch 基础保护)
- DNS: 防泄露(remote via VPN + cn 直连)
- experimental.clash_api: 随机端口 + secret 占位符
- gen-poc-config.sh: 渲染模板为可用 JSON(从环境变量读 REALITY 参数)
- README.md: 完整 PoC 接线与 M1 验收步骤
提权说明(macOS PoC):
· sudo 提权(开发机需配 /etc/sudoers.d/pangolin-singbox 或有 sudo 缓存)
· 正式版: SMJobBless Helper + 公证(BACKLOG-11D-HELPER)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 17:53:50 +08:00
wangjia
83c23f968a
feat(android): 实现 M2 Android VPN 隧道 — PangolinVpnService 接入 libbox [tsk_w1NvZdmwGPyd]
...
接线 11B libbox.aar + 11C Dart 桥接骨架,完成 Android 端 M2 PoC:
### PangolinVpnService(完整实现)
- `handleStart(configJson)` → 后台线程 → `Libbox.newBoxService(platformInterface, json)` → `start()`
- 内 inner class `PangolinPlatformInterface` 实现 libbox `PlatformInterface`:
- `openTun(TunOptions)`: 调用 `VpnService.Builder()` 配置地址/MTU/路由,`establish()` 取 TUN fd
- `autoDetectInterfaceControl(fd)`: `VpnService.protect(fd)` 防环路
- 安全 getter 兜底:TunOptions 方法名与 libbox.aar 不符时降级到 PoC 默认值
- 统计双轨:优先 libbox `CommandClient`(status/traffic)→ 失败时退回 `TrafficStats` 定时器
- 幂等 `doStop()`:commandClient.disconnect → boxService.close → tunPfd.close → stopForeground
- `onRevoke()` 推 error 状态再 doStop,不留假 on
### VpnEventBus
- 新增 `currentStatus` 字段(volatile),供 `getStatus()` 一次性查询
### MainActivity
- `VpnService.prepare()` 权限流程:未授权 → 弹 prepare Intent → `onActivityResult` 后启动
- `getStatus()` 从 `VpnEventBus.currentStatus` 返回真实状态
- 首次连接时引导 `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`(后台存活)
### AndroidManifest.xml
- `android:foregroundServiceType="specialUse"`(Android 14 API 34 强制要求)
- 新增权限:`FOREGROUND_SERVICE_SPECIAL_USE`、`REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`
### build.gradle
- `implementation files('../../../app/kernel/dist/android/libbox.aar')`(条件存在检查)
- `minSdkVersion` 提升至 21(gomobile -androidapi 21 要求)
### 新增文件
- `assets/poc_config.json`: PoC 单节点测试配置模板(含占位符 __NODE_HOST__ 等)
通知文案已过红线词扫描:「加速已开启」「正在连接…」「穿山甲加速」,无 VPN/翻墙等禁词。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 17:45:13 +08:00
wangjia
e129f094c2
feat(ios): M3 PoC — PacketTunnelProvider + entitlement + 内存监控 [tsk_nsobbj_rJdy0]
...
### 新增文件
- client/ios/PacketTunnel/MemoryMonitor.swift
周期打点 NE 进程内存(os_proc_available_memory iOS13+ / mach_task_basic_info 兼容
iOS12);每 10s 采样一次;availableMemory < 5MB 时输出 ⚠️ 警告;提供
summaryString() 供 handleAppMessage/getMemory IPC 返回。
- client/ios/PacketTunnel/PacketTunnel.entitlements
Extension 的 NE + App Group entitlement 文件;申请说明写入注释。
- client/ios/Runner/Runner.entitlements
主 App 的 NE + App Group entitlement 文件;申请说明写入注释。
- doc/ne-entitlement-申请指引.md
完整申请操作手册:Bundle ID 清单、Apple Developer Portal 步骤、
专项审批英文申请文案(已脱敏,无红线词)、审批 lead time 说明。
### 修改文件
- client/ios/PacketTunnel/PacketTunnelProvider.swift
完整 M3 实现(替换原骨架 TODO):
· startTunnel:解析 configJson(options/App Group 两路回退)→
buildNetworkSettings → setTunnelNetworkSettings → setupTunBridge
→ startLibbox → startPacketBridging → memoryMonitor.start()
· stopTunnel:memoryMonitor.stop() → stopLibbox → closeTunBridge
· handleAppMessage:JSON IPC 协议(getStatus/getMemory/selectOutbound)
· LibboxPlatformInterface 扩展(#if canImport(Libbox)):
openTun 返回 socketpair libbox 侧 fd,autoDetectInterfaceControl no-op,
writeLog 转 os.log,useProcFS 返回 false
· packetFlow 双向桥接(readFromPacketFlow/writeToPacketFlow 循环)
· parseTunAddress/parseDNSServers 从 JSON 提取网络参数
- client/ios/Runner/VpnManager.swift
· localizedDescription "穿山甲 Pangolin VPN" → "Pangolin 加速"(红线词修复)
· 新增 appGroup 常量(group.com.pangolin.pangolinVpn)
· start() 写入 App Group UserDefaults 缓存 configJson
- client/ios/Runner/Info.plist
NSVPNUsageDescription "穿山甲使用 VPN…" → "Pangolin 使用网络加速通道…"(红线词修复)
- client/ios/PacketTunnel/Info.plist
CFBundleDisplayName "穿山甲 Tunnel" → "Pangolin 加速通道"(红线词修复)
- client/ios/Runner.xcodeproj/project.pbxproj
· Runner + PacketTunnel 所有 build config 添加 CODE_SIGN_ENTITLEMENTS
· 新增 MemoryMonitor.swift 到 PacketTunnel Sources 构建阶段
· 新增 Runner.entitlements / PacketTunnel.entitlements / MemoryMonitor.swift
文件引用及分组
- app/kernel/build-ios.sh
添加 M3 内存裁剪决策记录:gVisor→grpc→QUIC 优先裁减顺序及内存估算,
等待真机 10min 压测结果后更新最终结论
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 17:44:11 +08:00
wangjia
ed5eabea58
merge: 第三方拨测 API 适配 [tsk_-WC9smQK7YRt]
2026-06-13 17:32:26 +08:00
wangjia
bf1717a369
merge: 控制面联调 M6 [tsk_nuoKSM4Vt-zK]
...
# Conflicts:
# .gitignore
# client/lib/widgets/home_shell.dart
# client/lib/widgets/server_tile.dart
# client/pubspec.yaml
2026-06-13 17:32:26 +08:00
wangjia
b89aeb0905
merge: app/kernel 构建管线(AAR/XCFramewor [tsk_d8KmVEzJTCjl]
...
# Conflicts:
# .gitignore
2026-06-13 17:32:26 +08:00
wangjia
b05d7ed416
merge: oapi-codegen 接线 + 生成代码入库 [tsk_Kp80nvHV2yLc]
...
# Conflicts:
# server/Makefile
# server/cmd/server/main.go
# server/go.mod
# server/go.sum
2026-06-13 17:32:25 +08:00
wangjia
605bfa1ec9
feat(nodes): gRPC server + Hub + Redis pub/sub cross-instance delivery (tsk__58l3wTLvaSn)
...
Implements AgentService gRPC server with all 6 RPCs (Enroll/Register/Heartbeat/
Subscribe/Ack/ReportUsage), Hub command routing with Redis ZSET at-least-once
persistence and cross-instance pub/sub delivery, LoadCache for node:load metrics,
NodeStore SQL interface + MySQL implementation, and full mTLS gRPC listener in main.
Integration tests: 18 tests covering full Enroll→Register→Heartbeat→Subscribe→Ack
flow, reconnect resume with last_command_id, and cross-instance pub/sub delivery
via bufconn + miniredis + mockNodeStore + real mTLS certificates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 17:30:42 +08:00
wangjia
8de32eb611
merge: 弹性节点基建:Terraform + 一键更换 [tsk_6u0FxmbC7Yeq]
...
# Conflicts:
# .gitignore
# infra/cloud-init/node.yaml.tmpl
2026-06-13 17:30:37 +08:00
wangjia
6f6cb97509
merge: Flutter 逐屏还原 + iPad 断点 [tsk_gpPXi-icyeOE]
...
# Conflicts:
# client/lib/widgets/connect_button.dart
# client/lib/widgets/home_shell.dart
# todo/todo.html
# todo/todo.json
2026-06-13 17:30:36 +08:00
wangjia
4e2a444572
merge: usage 用量 + 广告解锁 [tsk_1taxhtV2k3RP]
...
# Conflicts:
# server/internal/apierr/apierr.go
2026-06-13 17:30:36 +08:00
wangjia
34c9909608
merge: auth 模块 [tsk_2PFfyviECIXh]
...
# Conflicts:
# server/go.mod
2026-06-13 17:29:49 +08:00
wangjia
a47121f99b
feat(probe): add third-party dial-test adapter for 15C (tsk_-WC9smQK7YRt)
...
Implements ProberAgent interface + Alibaba Cloud CloudMonitor Synthetic adapter:
- ProbeTarget / VantageResult types aligned with 15A schema (L3 always nil)
- AliyunSyntheticAgent: CreateSiteMonitor → poll → map to VantageResult
- ISP vantage uses "3rd-{ISP}" prefix; Redis key probe:{node}:CN:{region}:3rd-*
- Degradation: API error/rate-limit/timeout → skip vantage, log + counter (no write)
- RunOnce(ctx, targets) shape for 15H assembly wiring
- Credentials via cfg only (env-var injection, zero hardcoded secrets)
- 6 new tests (mock vendor server): normalization, rate-limit, timeout, Redis keys,
failed-target L1, no-credentials check; all 22 probe-package tests pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 17:21:43 +08:00
wangjia
9423069a0b
merge: maestro/tsk_iP5-_Ztq5THx [tsk_iP5-_Ztq5THx]
2026-06-13 17:04:18 +08:00
wangjia
b456a8816f
merge: maestro/tsk_V9IrIk2g5Q78 [tsk_V9IrIk2g5Q78]
2026-06-13 17:04:17 +08:00
wangjia
3bcf1d7b4c
merge: maestro/tsk_NU9JuUweHWMt [tsk_NU9JuUweHWMt]
2026-06-13 17:04:17 +08:00
wangjia
96040c802f
merge: maestro/tsk_3FIPC8lSnAfJ [tsk_3FIPC8lSnAfJ]
2026-06-13 17:04:17 +08:00
wangjia
c642daec42
merge: maestro/tsk_acMYQ-Z-EIF_ [tsk_acMYQ-Z-EIF_]
2026-06-13 17:04:17 +08:00
wangjia
5a6b4a2dbb
merge: maestro/tsk__R8M4jEw43JR [tsk__R8M4jEw43JR]
2026-06-13 17:04:17 +08:00
wangjia
5a485fbcf6
merge: maestro/tsk_FrRarw9YO8Nf [tsk_FrRarw9YO8Nf]
2026-06-13 17:04:17 +08:00
wangjia
908f75de75
merge: maestro/tsk_VRzw-af__qWx [tsk_VRzw-af__qWx]
2026-06-13 17:04:17 +08:00
wangjia
b7aca4848a
merge: maestro/tsk_rcNKc3GQHBUd [tsk_rcNKc3GQHBUd]
2026-06-13 17:04:17 +08:00
wangjia
6f3ceba7a9
merge: maestro/tsk_eu2qVvni1HJR [tsk_eu2qVvni1HJR]
2026-06-13 17:04:17 +08:00
wangjia
e2646346a6
feat(web/usercenter): Next.js 用户中心静态导出 + mock/http 双数据层 (tsk_3FIPC8lSnAfJ)
...
新建 web/usercenter/:Next.js App Router + output:'export' 纯静态导出,
直接复用 design/ui_kits/usercenter React 源码(概览/订阅/兑换/邀请/设置)。
阶段 A(mock,本提交):
- 复刻五大页面,明/暗 × zh/en 四态;colors_and_type.css 原样链入;
顶栏主题切换 + 语言段控,移动端底部 Tab + 左右滑动切换。
- 设置页新增:偏好(语言/主题) + 设备管理(列表/移除/二次确认+刷新) +
TOTP 2FA(绑定二维码占位+密钥/验证/解禁),登录二段式 TOTP。
- 数据层 lib/api:ApiClient 抽象 + MockClient/HttpClient 双实现,构建期
NEXT_PUBLIC_API_MODE 切换;统一错误体 {code,message_zh,message_en} → 双语映射。
- 会话:access token 仅内存,refresh header token + localStorage,静默续期,
登出失效(取舍:静态导出无服务端 cookie 能力,详见 README)。
- 安全:构建期注入 SRI(sha384);_headers 严格 CSP + 安全基线;
红线词扫描(铁律13) CI 红线,零命中。
阶段 B(占位待联调):HttpClient 已写好域名池+退避重试+401 续期;
TOTP/登录二段式端点占位待 #1 契约增补;me/redeem/devices 切真实链路依赖 #2/#3/#4。
验证:npm run lint / redline / build 均通过,静态产物 out/ 无服务端依赖。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-13 15:23:18 +08:00
wangjia
6ec7cd8146
merge: maestro/tsk_V9IrIk2g5Q78 [proto 契约 + buf 工具链] (tsk_FrRarw9YO8Nf)
...
合并 proto 契约 + buf 工具链任务到 main(已含 apierr + idgen + CONVENTIONS.md):
- server/proto/pangolin/agent/v1/agent.proto: AgentService 6 个 RPC(Enroll/Register/
Heartbeat/Subscribe/Ack/ReportUsage)及全量消息类型,隐私红线注释保留
- server/buf.yaml: v2 格式,STANDARD lint + FILE breaking 规则
- server/buf.gen.yaml: remote protoc-gen-go v1.36.4 + protoc-gen-go-grpc v1.5.1 插件
- server/internal/pb/: 生成的 agent.pb.go + agent_grpc.pb.go 提交入库
- server/Makefile: 新增 proto / proto-lint / proto-breaking 目标
- server/tools.go: 新增 buf v1.70.0、protoc-gen-go、protoc-gen-go-grpc 工具依赖
- server/go.mod / go.sum: 合并 buf 工具链依赖;github.com/google/uuid 保留为 direct
依赖(idgen 直接 import);go 版本升至 1.25.10
冲突解决:两侧均修改 go.mod,以 proto 分支(超集)为基础,将 google/uuid 移至
直接依赖 require 块,保留 apierr/idgen 的已有文件不变。
go build ./... ✓ | go test ./internal/apierr/... ./internal/idgen/... ✓
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 15:11:11 +08:00
wangjia
d88c1ae647
merge: maestro/tsk_x7wrlA87orsY [devices + 订阅校验中间件] (tsk_VRzw-af__qWx)
...
手动合并 tsk_x7wrlA87orsY(设备管理 + 订阅校验中间件)到 main:
冲突解决:
- server/internal/apierr/apierr.go:保留 tsk_GXDoc3Cs07Rn 版本(New/StatusFor/
Middleware/ErrConflict/改善文档),并入 tsk_x7wrlA87orsY 新增的 ErrAccountBanned
及对应 StatusFor case(→ 403)。
新增文件(来自 tsk_x7wrlA87orsY):
- server/internal/devices/doc.go package 文档(替换占位 stub)
- server/internal/devices/context.go CtxKeyUserID / Plan / WithPlan / PlanFromCtx
- server/internal/devices/handler.go GET /v1/me/devices · DELETE /v1/me/devices/{id}
- server/internal/devices/middleware.go SubscriptionMiddleware · CheckDeviceQuota · RequirePaidTier
- server/internal/devices/service.go RegisterIfAbsent / DeleteDevice / ResolvePlan + 纯函数 resolveEffectivePlan
- server/internal/devices/store.go MySQL 数据访问层
- server/internal/devices/service_test.go 15 个单测(全通过)
- server/internal/devices/devices_integration_test.go testcontainers 集成测试
OpenAPI 更新(来自 tsk_x7wrlA87orsY):
- server/api/openapi.yaml:SubscriptionInfo.source 枚举补 free
- design/server/openapi.yaml:SubscriptionInfo.source 枚举补 admin, free
测试:go build ./... ✓;go test ./internal/apierr/... ✓(8 tests);
go test ./internal/devices/... ✓(15 tests)。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 15:09:51 +08:00
wangjia
c84b6ea7da
merge: maestro/tsk_iP5-_Ztq5THx [桥接 API 面 Channel 契约 + 三端原生骨架] [tsk_rcNKc3GQHBUd]
...
合并冲突补救:原分支从 merge base 7871512 分叉,仅修改 client/ 目录,
与 main 新增的 server/(apierr/idgen/CONVENTIONS.md) 完全不重叠,
无真实文件冲突,手动应用 feature branch 的全部 client/ 改动。
client 侧新增:
- lib/bridge/vpn_bridge.dart — Dart↔原生通道契约(冻结)
- lib/bridge/vpn_bridge_mock.dart — 假内核,UI 联调用
- lib/bridge/kernel_process.dart — 桌面子进程管理接口
- ios/PacketTunnel/{Info.plist,PacketTunnelProvider.swift} — NEPacketTunnel 骨架
- ios/Runner/VpnManager.swift — NETunnelProviderManager 封装
- android/.../PangolinVpnService.kt — VpnService 骨架
- android/.../VpnEventBus.kt — Application 级状态总线
- test/bridge/vpn_bridge_mock_test.dart — 桥接层单元测试
client 侧修改:
- android/.../MainActivity.kt — 注册三通道(MethodChannel + 2×EventChannel)
- android/.../AndroidManifest.xml — 声明 FOREGROUND_SERVICE + PangolinVpnService
- ios/Runner/AppDelegate.swift — 注册通道 + VpnManager 初始化
- ios/Runner/Info.plist — 新增 NSVPNUsageDescription
- ios/Runner.xcodeproj/project.pbxproj — 添加 PacketTunnel extension target
- lib/widgets/connect_button.dart — VpnStatus 迁移到 bridge/vpn_bridge.dart
- lib/widgets/home_shell.dart — error 状态 UI 分支补全
2026-06-13 14:58:38 +08:00