Files
web-terminal/docs/plans/ios-completion.md

8.8 KiB
Raw Blame History

ios-completion — 收尾波6 项整改 + P2 全波 + Android 令牌对齐

编排 doc。orchestrator 冻结的跨 agent 契约在 §1任何 builder 不得偏离 任务/Owns 表在 §2验收在 §3。进度记录仍归 docs/PROGRESS_LOG.mdorchestrator 独写)。

审计依据2026-07-29 的 16-agent iOS 完成度审计43 计划任务 27 DONE / 11 PARTIAL / 5 MISSING

用户已定的三个范围问题:

  1. P2 全 5 项T-iOS-31…35在范围内 —— 计划 §7 要求"未按 P0 规格扩写 RED 清单前不得分派" 故每个 P2 builder 的第一步就是扩写自己那一项的 RED 测试清单(写进本 doc §4 追加区),再进入 GREEN。
  2. Apple 账号 = 免费个人 teamTeam ID C738Z66SRWO=Yaojia Wang)。 ⇒ Push Notifications capability 不可用aps-environment entitlement 若默认挂上,真机构建会直接失败。 entitlements 必须做成默认不挂、env 开关(见 A1
  3. Android 的 WEBTERM_TOKEN 支持一起补(与 iOS 侧文件完全不相交,可并行)。

1. 冻结契约FROZEN — orchestrator 已核对服务端源码builder 只许实现不许改)

1.1 访问令牌(WEBTERM_TOKEN)—— 原生客户端接入方式

服务端事实(src/http/auth.tssrc/server.ts:340-430,1353-1385

出处
Cookie 名 webterm_auth auth.ts:30 AUTH_COOKIE_NAME
Cookie TTL 2592000 秒30 天) auth.ts:34
登录端点 POST /auth server.ts:393
请求体 {"token":"<t>"}Content-Type: application/json server.ts:396,408-409
Accept 必须不含 text/html server.ts:366-369,410 —— 含 text/html 会被当成表单走 302 重定向,而不是 204/401
成功 204,带 Set-Cookie: webterm_auth=… server.ts:412-414
令牌错误 401 + {"error":"invalid token"} server.ts:418
限流 42910 次/分钟/IP server.ts:100,399-402
服务端未启用鉴权 204 但没有 Set-Cookie server.ts:404-407
鉴权后 每个 HTTP 请求 + WS upgrade 都要带 Cookie: webterm_auth=<t> server.ts:1375
令牌字符集 [A-Za-z0-9._~+/=-],长度 16512 CLAUDE.md / config 校验

实现决定(冻结)

  • 原生客户端自己知道令牌,因此 直接手写 Cookie: webterm_auth=<t> 请求头即可, 不解析 Set-Cookie、不依赖系统 cookie 存储。理由URLSession/OkHttp 的 cookie jar 在 WS upgrade 上的行为不一致且难测;手写头与既有 Origin 手写头是同一个模式(Endpoints.swift:81 可被纯函数单测钉死。
  • POST /auth 只用作配对期的一次性校验探针
    • 204 Set-Cookie ⇒ 令牌正确,保存;
    • 204 Set-Cookie ⇒ 该服务器没开鉴权,令牌不必保存(不得据此认为"已认证"
    • 401 ⇒ 令牌错UI 报"令牌不正确"429 ⇒ UI 报"尝试过多,稍后再试"。
  • Cookie 头与 Origin 头正交:令牌不替代 Origin 检查,两者都要带(server.ts:1363-1379 是先 Origin 再 cookie
  • 令牌是密级材料:存 Keychain / Android Keystore-backed 存储, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnlykSecAttrSynchronizable(沿用 SecItemShim.swift 既有约定); 绝不写日志、绝不进 URL query、绝不进崩溃报告
  • 401 语义:任何 RO/G 请求收到 401 ⇒ 抛类型化 .unauthorized(不是通用网络错), UI 引导去补令牌。WS upgrade 收 401 ⇒ 终态,不进退避环(与 .replayTooLarge 同级处理)。

1.2 git 面板端点(照 Android 已实现的形状;服务端为唯一真源)

Origin-iff-G 规则(Endpoints.swift:81)照旧:写操作必带 Origin,只读绝不带

端点 方法 R/W Android 参考实现
/projects/log GET RO api-client/.../models/GitLog.kt
/projects/pr GET RO 同上
/projects/worktree/state GET RO
/projects/git/stage POST G models/GitWrite.kt
/projects/git/commit POST G 同上
/projects/git/push POST G 同上
/projects/git/fetch POST G
/projects/worktree POST G routes/GitRouteShapeTest.kt
/projects/worktree/prune POST G 同上
/sessions GET RO —(claude --resume 历史T-iOS-32
/live-sessions/:id/queue POST G w2 pty 注入队列)

真源是 src/ 的实现src/http/projects.ts / src/server.tsAndroid 只作交叉校验; 两者若不一致,src/ 为准并在返回条目里报告该不一致

1.3 免费 team 的签名与 entitlements冻结

  • DEVELOPMENT_TEAM = C738Z66SRW
  • CODE_SIGN_IDENTITY 的历史值 "iPhone Developer"已废弃串,改 "Apple Development"(或删掉让 Automatic 自己选)。
  • WebTerm.entitlements(含 aps-environment默认不挂。挂载由 env 开关控制, 未设时 CODE_SIGN_ENTITLEMENTS 必须为空 —— 免费 team 挂上就真机构建失败。 开关名冻结为 WEBTERM_PUSH_ENTITLEMENTS(值=entitlements 相对路径),并写进 ios/README.md
  • UIBackgroundModes: [remote-notification] 可以无条件加(背景模式不是 capability免费 team 不受限)。

2. 任务表Owns 铁律:不得编辑本任务 Owns 之外的文件)

Wave A串行1 agent—— 全员依赖的工程根

ID 任务 Owns
A1 签名解锁 + Info.plist 全量键 + 可选 entitlements ios/project.ymlios/App/WebTerm/WebTerm.entitlements(新)

A1 必须一次把后续所有波次需要的 Info.plist 键都加好(它是 project.yml 的唯一 owner NSMicrophoneUsageDescriptionNSSpeechRecognitionUsageDescriptionT-iOS-31UIBackgroundModes: [remote-notification]T-iOS-21

Wave B并行 5 agent目录互斥—— 包层 + CI + Android

ID 任务 Owns
B1 APIClient 全部新端点§1.1 /auth + §1.2 全表)+ 模型 + 测试覆盖率≥80% ios/Packages/APIClient/**
B2 HostRegistry按主机存访问令牌Keychain§1.1 存储约定)+ 迁移安全 ios/Packages/HostRegistry/**
B3 SessionCoreWS upgrade 带 Cookie、401→终态 .unauthorized、不进退避环 ios/Packages/SessionCore/**
B4 ClientTLS 覆盖率 55.76%→≥80% + 纳入覆盖率门 + 修 CI 三条腿 ios/Packages/ClientTLS/Tests/**ios/IntegrationTests/scripts/coverage-gate.sh.github/workflows/ios.yml
B5 Android WEBTERM_TOKEN 支持§1.1 同一契约OkHttp 侧) android/**

Wave C串行 4 agent—— App 层

串行原因:新增 .swift 文件必须 xcodegen generate 重写共享的 .xcodeproj,并行会互相踩; 串行后无文件归属冲突,每个 agent 可自由跑 xcodegen + xcodebuild 全量验证。

ID 任务 内容
C1 令牌 UI + 传输接线;移除主机 UI顺带修 PushRegistrar.handleHostRemoved 死钩子)
C2 git 面板 UI + worktree 表(含 T-iOS-32+ claude --resume 历史
C3 终端内搜索(T-iOS-33+ 语音 PTTT-iOS-31
C4 主题 + Dynamic TypeT-iOS-34+ web ?join= 互通(T-iOS-35

Wave D并行 3 agentreport-only / 文档)

ID 任务
D1 安全复核:令牌路径(两端)+ entitlements + 无令牌泄漏(日志/URL/崩溃)
D2 全量验收(T-iOS-36 + T-iOS-18/19/30 的机器可执行部分):包测/App 测/集成/覆盖率门/模拟器构建/真机构建尝试,只报真实数字
D3 文档:README.mdios/README.mddocs/PLAN_IOS_CLIENT.mddocs/PLAN_IOS_IPAD.md 勾选与过期表述

Wave E串行条件触发

ID 任务
E1 修 D1/D2 报出的 CRITICAL/HIGH无则跳过

3. 验收门(每个 builder 自查D2 复核)

  • TDD先 RED 再 GREEN§4 的 RED 清单是 P2 任务的前置交付物)。
  • swift build + swift test 本包全绿;改到 App 层则 xcodegen generate + iPhone 16 Pro 模拟器 xcodebuild ... test 全绿。
  • 受门包覆盖率 ≥80%B4 后 ClientTLS 也进门)。
  • TODO/FIXME/占位实现;零硬编码密钥;令牌零日志。
  • 诚实报告:跑不了的(真机/付费账号/CI 平台)写 DEFERRED 并给出手工步骤,不得报"通过"

4. P2 RED 测试清单(由各 P2 builder 在开工第一步追加到本节)