109 lines
13 KiB
Markdown
Executable File
109 lines
13 KiB
Markdown
Executable File
# VSCode/Cursor Builds & Debugging (macOS)
|
||
|
||
Status: **IN PROGRESS** · updated 2026-10-04
|
||
|
||
**Asana:** [Migration to fully VSCode-supported builds&debugging](https://app.asana.com/1/137249556945/project/1203301625297703/task/1209808486380252)
|
||
**Repo:** `~/DuckDuckGo/apple-browsers.git` (bare + worktrees)
|
||
**Findings:** [[projects/vscode-migration/findings]]
|
||
**Tech design (package step):** [[projects/vscode-migration/tech-design-spm-browser-package]]
|
||
**Editor via Xcode build server (no package needed):** [[projects/vscode-migration/xcode-build-server]] · [[projects/vscode-migration/tech-design-xcode-build-server|tech design]]
|
||
**Next:** [[projects/vscode-migration/modularization-roadmap]] — modularization after the browser package (incl. iOS/macOS sharing)
|
||
|
||
## Goal
|
||
|
||
Build, run and debug the macOS app from VSCode/Cursor: make most of the app
|
||
SPM-compatible, so `swift build` + SourceKit-LSP work, and configure
|
||
`.vscode` (tasks, launch).
|
||
|
||
## Status
|
||
|
||
| Step | Status |
|
||
|---|---|
|
||
| Move non-Swift code to local packages | ✅ Jun 2025 |
|
||
| Missing imports, unused files cleanup | ✅ Jun 2025 |
|
||
| Initial VSCode config | ✅ Jun 2025 (stale: `sweetpad` worktree) |
|
||
| Unify WebKit private methods (Sparkle/AppStore) | ✅ Feb 2026 |
|
||
| Drop `#if SPARKLE/APPSTORE` | ✅ Mar 2026 — DMG and App Store targets now compile the same 1398 files |
|
||
| Drop dead target flags (`SANDBOX_TEST_TOOL`, `ALPHA`, `NETWORK_EXTENSION` in shared files) | ✅ [#6983](https://github.com/duckduckgo/apple-browsers/pull/6983) |
|
||
| Replace sandbox-test-tool with App Store UI tests (`AppStoreSandboxUITests`, CI leg along full DMG runs) | ✅ [#6980](https://github.com/duckduckgo/apple-browsers/pull/6980) |
|
||
| Split app files shared with helper targets | 🔄 A+B in review ([#7029](https://github.com/duckduckgo/apple-browsers/pull/7029)), C ready, G done; the rest stays shared by path — see [Target split stages](#target-split-stages) |
|
||
| Asset resource initializers instead of asset symbol extensions | ✅ committed, `alex/asset-resource-symbols` (needs a PR) |
|
||
| Drop storyboards | ✅ last one (`NavigationBar`) is `alex/drop-navigationbar-storyboard` (PR open); `Feedback` #6866, `PasswordManager` #6950 merged |
|
||
| **Browser code as a SwiftPM package** | 🔄 builds and runs from Xcode and VSCode — `alex/spm-browser-package`, see [Browser package](#browser-package) |
|
||
| Core Data models in code | ❌ **Cancelled** 2026-10-01 — Xcode 27 builds these in SPM |
|
||
| Asset catalogs for `swift build` | ❌ **Cancelled** 2026-10-01 — Xcode 27 builds these in SPM |
|
||
| swift-build fork (Provisional Inputs) | ⏸ not started; may be unnecessary |
|
||
| Remote debugging (VMs, old hardware) | ⏸ not started |
|
||
| AI instructions, GitHub MCP subtasks | ⏸ not started |
|
||
|
||
## Current decision and evidence (2026-10-04)
|
||
|
||
- Code-initialized Core Data models were proposed at Apple Weekly on 2026-09-29, then cancelled after Xcode 27 / Swift 6.4 validation. [Asana subtask 1218854852229979](https://app.asana.com/0/0/1218854852229979) is completed because the conversion became unnecessary, not because the new model code was implemented. Existing `.xcdatamodeld` files stay as SPM resources and load through `Bundle.module`; the project documents local Xcode 27.2 verification.
|
||
- [Cleanup task 1218987523298563](https://app.asana.com/0/0/1218987523298563) to remove runtime model compilation test hacks remains open. [PR #7080](https://github.com/duckduckgo/apple-browsers/pull/7080) packages the browser as SwiftPM, is currently Draft, and is separate from the cancelled code-defined model approach. GitHub shows it was temporarily closed and reopened on 2026-10-02.
|
||
- For cross-project focus and career analysis, use [[personal/projects/personal-os/project-truth-analyzer]] to distinguish proposals, decisions, implementation, and verification.
|
||
|
||
## Open items after the cancellation
|
||
|
||
- [x] Closed PR [#6976](https://github.com/duckduckgo/apple-browsers/pull/6976) (AssetCatalogPlugin) and the Core Data PR; their worktrees are removed.
|
||
- [ ] Check what Xcode 27 actually does for `swift build` (native) and SourceKit-LSP: asset symbols, `.car`, `.momd`, storyboards? Earlier finding on Xcode 26: only `--build-system swiftbuild` handles assets, native doesn't. See [[projects/vscode-migration/findings#Asset catalogs]].
|
||
- [ ] Re-check whether storyboards still need dropping with Xcode 27.
|
||
|
||
## Plan (next steps)
|
||
|
||
1. **PRs in order:** #7029 (A+B) → C (`move-vpn-pixel-event`) / G (`move-helper-only-files`) → `alex/asset-resource-symbols` → `alex/drop-navigationbar-storyboard` → `alex/spm-browser-package`.
|
||
2. **Browser package PR follow-ups** — see [Browser package](#browser-package): localization export (`loc_export.sh`), CI checks for the VSCode setup, dropping the duplicated app-target package product dependencies.
|
||
3. **Helper-target split, later:** D, E1, E2+H, F aren't needed for the package (helpers keep compiling the shared files by path); do them when there's a reason (F with the KeyedStoring migration).
|
||
4. **VSCode tasks with cached helper targets** (extensions/login items built by Xcode only when their inputs change) — the host app already contains them; revisit if host rebuilds are too slow. See [[projects/vscode-migration/findings#Extensions in VSCode tasks]].
|
||
|
||
## Browser package
|
||
|
||
Worktree `spm-browser-package`, branch `alex/spm-browser-package` (on top of `alex/move-helper-only-files` + `alex/asset-resource-symbols` + `alex/drop-navigationbar-storyboard`; package work uncommitted).
|
||
|
||
- `macOS/DuckDuckGo/Package.swift`: target `DuckDuckGo_Privacy_Browser` (same module name as the former app target: storyboards, archived class names, `@testable import`) with `path: "."` — files stay in place. Products `DuckDuckGoBrowser` (static, linked into the app targets) and `DuckDuckGoBrowserDynamic` (for `swift build`).
|
||
- Resources stay in the app targets (`Bundle.main`: strings, JSON, scripts, app icons); asset catalogs (for generated `ImageResource`/`ColorResource`) and the 8 Core Data models (codegen entity classes) are processed by the package — models now load from `Bundle.module`.
|
||
- App targets: only `DuckDuckGoApp/main.swift` (`AppMain.main()`), module `DuckDuckGoApp`; package reference + `DuckDuckGoBrowser` product added, existing product dependencies kept.
|
||
- `SPM_FORCE_DEBUG` in `Package.swift` (same as AppKitExtensions/SyncUI): the CI configuration maps to release for packages.
|
||
- `REVIEW` compilation condition can't reach the package → Browser Tools Panel debug menu item is gated at runtime (`isDebugBuild || isReviewBuild`).
|
||
- VSCode/Cursor: open `macOS/DuckDuckGo`; `.vscode/` has tasks (host app → `swift build --build-system swiftbuild` → sign), `launch.json`, `make-host-app.sh`, `sign-dylib.sh`, `launcher/launcher.c`.
|
||
- Verified (Xcode 27.2, offline): all product schemes Debug, `macOS Browser` Review, unit + integration tests `build-for-testing` Debug and CI (with `SPM_FORCE_DEBUG=1`), Xcode-signed Debug app and the VSCode host run without crashes, `swift build` of the dylib.
|
||
- Open: `loc_export.sh` / string catalog extraction now that sources are in a package; CI doesn't build the VSCode path; `Package.resolved` in `macOS/DuckDuckGo` (copied from the project) — keep in sync or generate.
|
||
|
||
## Target split stages
|
||
|
||
Goal: no file in `macOS/DuckDuckGo/` is compiled into a helper target (VPN agent, PIR agent, NetP extensions), so the app directory can become one SPM target. `InputFilesChecker` tracks the remaining files in `temporarilyAllowedMisplacedFiles` (one block per stage); a stale entry fails the build, so each stage PR must remove its block.
|
||
|
||
| Stage | Files | Used by | Home | New deps / project changes | Size & blockers | PR |
|
||
|---|---|---|---|---|---|---|
|
||
| A | `ApplicationBuildType`, `BuildFlags`, `DuckDuckGoUserAgent` | app + all 6 helpers | `AppKitExtensions` | none (all targets already link it) | 46 imports | [#7029](https://github.com/duckduckgo/apple-browsers/pull/7029) |
|
||
| B | `DBPFeatureFlagger`, `DataBrokerAuthenticationManagerBuilder`, `DataBrokerProtectionSettings+Environment`, `WebViewUserAgentProvider`, `SafariVersionReader`, `WebKitVersionProvider` | app + PIR agent | `DataBrokerProtection-macOS` | none (`Subscription` comes transitively, like elsewhere in the package) | 5 imports | [#7029](https://github.com/duckduckgo/apple-browsers/pull/7029) |
|
||
| C | `NetworkProtectionPixelEvent` (569 loc) | app, VPN agent, 3 extensions | `NetworkProtectionMac` → `VPNPixels` (new library product) | `VPNPixels` += `VPN`, `Configuration`; BSK package dep; product linked to 7 targets | 9 imports. Ready, uncommitted (`move-vpn-pixel-event`) | own PR, on top of #7029 |
|
||
| D | `SubscriptionPixel`, `SubscriptionPixelHandler`, `SubscriptionEnvironment+Default`, `WideEventFeatureFlagAdapter`, `SubscriptionFunnelOrigin` (836 loc) | app, VPN agent, PIR agent, 3 extensions | new local package (no existing one is linked by all consumers) | `Subscription`, `PixelKit`, `Networking`, `PrivacyConfig`, `WideEvent`, `AppKitExtensions`; product linked to ~8 targets | used in ~134 files — biggest diff | own PR (new package, Subscription reviewers) |
|
||
| E1 | TipKit ×4, `VPNIPCResources`, `VPNOperationErrorRecorder`, `NetworkProtectionVPNCountryLabelsModel`, `VPNSettings+Environment` (~470 loc) | app + VPN agent | `NetworkProtectionMac` (IPC / UI, or a small `TipKitSupport` target) | `Subscription` for `VPNSettings+Environment` | moderate, no strings | combine with G |
|
||
| G | 10 helper-only sources living in `DuckDuckGo/` (`Bundle+VPN`, `NetworkProtectionOptionKeyExtension`, `NetworkProtectionControllerErrorStore`, `NetworkProtectionTunnelController`, `MacPacketTunnelProvider`, `MacTransparentProxyProvider`, `NetworkProtectionNotificationsPresenterFactory`, `VPNFailureRecoveryPixel`, `Bundle+NetworkProtectionExtensions`, `SubscriptionManager+StandardConfiguration`) | helpers only, never the app | `DuckDuckGoVPN/`, new `HelperTargetsShared/` (allowed for helper targets in `InputFilesChecker`) | `git mv` + pbxproj group paths only | done | ✅ `alex/move-helper-only-files` |
|
||
| E2 | `UserText+NetworkProtection+Shared`, `DefaultVPNLocationFormatter` | app + VPN agent | `NetworkProtectionUI` (has `Localizable.xcstrings`) | strings → `Bundle.module` with translations; app and VPN agent each have their own `UserText` | blocked on the strings/resources decision | combine with H |
|
||
| H | 4 app icons, `macos-config.json`, 7 VPN Lottie JSONs, 2 NetP `.xcstrings` | app + helpers | package resources or per-target copies | resource bundles / `Bundle.module` | same decision as E2 and the app-package tech design | with E2 |
|
||
| F | `UserDefaultsWrapper` (415 loc) + `UserDefaults+NetworkProtectionShared` | app, VPN agent, all extensions; ~51 app files | don't move — deprecated in favour of `KeyedStoring` | follows the KeyedStoring migration | blocked on that migration (owner/timeline TBD) | after the migration |
|
||
| X (optional) | `NETP_SYSTEM_EXTENSION` in `MacPacketTunnelProvider`, `MacTransparentProxyProvider`, `NetworkProtectionNotificationsPresenterFactory` | extensions only | runtime check `Bundle.main.bundleURL.pathExtension == "systemextension"` | removes the last `FEATURE_FLAGS` from xcconfigs | changes keychain service / defaults selection — needs VPN team review | optional, separate |
|
||
|
||
Order: C → D → E1+G → strings/resources tech design → E2+H → F after KeyedStoring. X any time if the VPN team agrees.
|
||
|
||
## Worktrees
|
||
|
||
| Worktree | Branch | What |
|
||
|---|---|---|
|
||
| `trim-target-memberships` | `alex/trim-target-memberships` | Stages A+B + membership trim, PR #7029 |
|
||
| `move-vpn-pixel-event` | `alex/move-vpn-pixel-event` | Stage C, uncommitted, on top of #7029 |
|
||
| `move-helper-only-files` | `alex/move-helper-only-files` | Stage G (committed): helper-only sources → `DuckDuckGoVPN/`, `HelperTargetsShared/` |
|
||
| `asset-resource-symbols` | `alex/asset-resource-symbols` | Asset resource initializers (committed) |
|
||
| `spm-browser-package` | `alex/spm-browser-package` | Browser code as a SwiftPM package + VSCode setup (WIP, uncommitted) |
|
||
| `drop-sb-navigationbar` | `alex/drop-navigationbar-storyboard` | Last storyboard (PR open, merged into `spm-browser-package`) |
|
||
| `drop-sb-feedback` | `alex/drop-feedback-storyboard` | Merged (#6866); follow-up commits after the squash? |
|
||
| `coredata-spm-hacks-cleanup` | `alex/coredata-spm-hacks-cleanup` | no commits ahead of main yet |
|
||
| `netp-dependencies` | `alex/align-netp-dependencies` | Old draft: move files by target (superseded by the stages above) |
|
||
| `vscode`, `vscode2` | `alex/fix-imports-cleanup`, `alex/vscode2` | Old: SwiftGenPlugin draft (uncommitted), root `Package.swift` |
|
||
| `sweetpad` | `alex/cursor-fix-build` | Old `.vscode` (SweetPad) config |
|
||
|
||
Gone: `spm-asset-symbols-plugin`, `coredata-code-models*`, `drop-sb-bookmarksbar*` (BookmarksBar storyboard + xib are on main), `appstore-sandbox-ui-tests` (#6980), `drop-dead-target-flags` (#6983), `split-shared-target-files`.
|
||
|
||
Demo project for the (cancelled) asset approach: `~/Developer/SPMAssetSymbolsDemo` (`./verify.sh`).
|