# XcodeGen project spec — regenerate with: cd ios && xcodegen generate # The generated WebTerm.xcodeproj is NOT committed (see ios/.gitignore). # # TOOLCHAIN DEVIATION (recorded per plan §7 T-iOS-1): the plan names # "default MainActor isolation" (SWIFT_DEFAULT_ACTOR_ISOLATION), which is # Swift 6.2+/Xcode 26 only. On Swift 6.1 / Xcode 16.3 the closest supported # equivalent is Swift 6 language mode + strict concurrency, with explicit # @MainActor annotations where isolation is required. name: WebTerm options: bundleIdPrefix: com.yaojia deploymentTarget: iOS: "17.0" createIntermediateGroups: true settings: base: SWIFT_VERSION: "6.0" # Swift 6 language mode SWIFT_STRICT_CONCURRENCY: complete IPHONEOS_DEPLOYMENT_TARGET: "17.0" TARGETED_DEVICE_FAMILY: "1" # iPhone only (iPad layout is out of v1 scope) CODE_SIGN_STYLE: Automatic packages: WireProtocol: path: Packages/WireProtocol SessionCore: path: Packages/SessionCore HostRegistry: path: Packages/HostRegistry APIClient: path: Packages/APIClient TestSupport: path: Packages/TestSupport # test doubles — WebTermTests only, never the app target # SwiftTerm is the ONLY third-party dependency, attached to the App target # ONLY (plan §2) — packages must never import it. SwiftTerm: url: https://github.com/migueldeicaza/SwiftTerm from: 1.13.0 targets: WebTerm: type: application platform: iOS sources: - App/WebTerm dependencies: - package: WireProtocol - package: SessionCore - package: HostRegistry - package: APIClient - package: SwiftTerm settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.yaojia.webterm # Target-level on purpose (T-iOS-19 finding): XcodeGen's target platform # default ("1,2") overrides a project-level value, shipping an # installable-but-untested iPad layout. Target-level wins. TARGETED_DEVICE_FAMILY: "1" info: path: App/WebTerm/Resources/Info.plist properties: CFBundleDisplayName: WebTerm UILaunchScreen: {} # Deep-link scheme (P1 T-iOS-22): webterminal://open?host=&join= # Registered here by the orchestrator (project.yml coordination point); # all parsing/validation lives in DeepLinkRouter (untrusted input). CFBundleURLTypes: - CFBundleURLName: com.yaojia.webterm.deeplink CFBundleURLSchemes: [webterminal] UISupportedInterfaceOrientations: - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight # ── Security-critical keys, transcribed verbatim from PLAN_IOS_CLIENT §5.2 ── # NO NSAllowsArbitraryLoads anywhere (release OR debug): the five CIDR # exceptions below cover LAN + hotspot + Tailscale CGNAT + simulator # loopback, so no arbitrary-loads escape hatch is needed in P0. # T-iOS-19 re-verifies all five CIDR blocks in the release ipa. NSAppTransportSecurity: NSAllowsLocalNetworking: true # only covers .local / dotless hostnames, not bare IPs NSExceptionDomains: # bare IPs use CIDR exceptions (iOS 17+ semantics) "192.168.0.0/16": NSExceptionAllowsInsecureHTTPLoads: true "10.0.0.0/8": NSExceptionAllowsInsecureHTTPLoads: true "172.16.0.0/12": # RFC1918 third block (iPhone hotspot 172.20.10.x / corp LAN) NSExceptionAllowsInsecureHTTPLoads: true "100.64.0.0/10": # Tailscale CGNAT NSExceptionAllowsInsecureHTTPLoads: true "127.0.0.0/8": # simulator dev-loop (CIDR, not a single-IP key — DevForums 6205) NSExceptionAllowsInsecureHTTPLoads: true NSLocalNetworkUsageDescription: "连接你自己电脑上的 web-terminal 服务器" NSCameraUsageDescription: "扫描 web 终端的配对二维码" # Unit-test bundle for App-target logic (ViewModels & pure UI components, # W3 T-iOS-11…14). Added by the orchestrator as a coordination point # (project.yml is T-iOS-1's Owns; same precedent as the W1 manifest wiring). # Coverage GATE still counts only the 4 packages (plan §9) — these tests # exist for correctness, not for the gate. WebTermTests: type: bundle.unit-test platform: iOS sources: - App/WebTermTests dependencies: - target: WebTerm - package: WireProtocol - package: SessionCore - package: HostRegistry - package: APIClient - package: TestSupport settings: base: GENERATE_INFOPLIST_FILE: true TARGETED_DEVICE_FAMILY: "1" TEST_HOST: "$(BUILT_PRODUCTS_DIR)/WebTerm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/WebTerm" BUNDLE_LOADER: "$(TEST_HOST)" # XCUITest — exactly ONE scripted happy path per plan §9 (T-iOS-18 finding): # pair via manual entry against a live loopback server → attach → type → # approve a held gate. Kept deliberately minimal (fragile-surface rule). WebTermUITests: type: bundle.ui-testing platform: iOS sources: - App/WebTermUITests dependencies: - target: WebTerm settings: base: GENERATE_INFOPLIST_FILE: true TARGETED_DEVICE_FAMILY: "1" TEST_TARGET_NAME: WebTerm schemes: WebTerm: build: targets: WebTerm: all WebTermTests: [test] run: config: Debug test: config: Debug targets: - WebTermTests # Separate scheme so the slow UI pass never gates the fast unit loop; CI # runs it as its own leg (see .github/workflows/ios.yml). WebTermUITests: build: targets: WebTerm: all WebTermUITests: [test] test: config: Debug targets: - WebTermUITests