8.8 KiB
Executable File
VSCode/Cursor Builds & Debugging (macOS)
Status: IN PROGRESS · updated 2026-10-01
Asana: Migration to fully VSCode-supported builds&debugging
Repo: ~/DuckDuckGo/apple-browsers.git (bare + worktrees)
Findings: projects/vscode-migration/findings
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 |
Replace sandbox-test-tool with App Store UI tests (AppStoreSandboxUITests, CI leg along full DMG runs) |
✅ #6980 |
| Split app files shared with helper targets | 🔄 A+B in review (#7029), C ready — see Target split stages |
| Drop storyboards | 🔄 3 left on main: Feedback, NavigationBar, PasswordManager (drop-sb-* worktrees) |
| 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 |
Open items after the cancellation
- Closed PR #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 swiftbuildhandles assets, native doesn't. See projects/vscode-migration/findings#Asset catalogs. - Re-check whether storyboards still need dropping with Xcode 27.
Plan (next steps)
- Extract files shared with helper targets into packages — in progress, see Target split stages. Started from 38 app files also compiled into VPN / PIR agent / NetP extensions. Dead flags are gone (#6983); unused memberships trimmed and stages A+B moved (#7029). The old draft
netp-dependenciesis superseded. - Decide on strings & resources in the package (tech design): 1964
NSLocalizedStringwithoutbundle:(→Bundle.main), ~60 resource files, 8Bundle.main.url(…).bundleIdentifier/appGroupviaBundle.maincan stay. - App code as a library package + thin app target (
AppMain, Info.plist, entitlements, embed phases for login items / extensions). - VSCode tasks with cached helper targets: gate script hashes each extension's inputs (git-based, not mtime) and skips
xcodebuildwhen unchanged; assemble step copies prebuilt extensions and signs. Only pays off once the app itself builds withswift build. See projects/vscode-migration/findings#Extensions in VSCode tasks. - Convert ~57 string-name image lookups (
NSImage(named:),Image("…")) to asset symbols — they break once code moves toBundle.module.
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 |
| 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 |
| 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 | helper-owned folders | git mv + pbxproj group paths only |
small, noisy pbxproj | combine with E1 |
| 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 |
drop-sb-feedback, drop-sb-navigationbar, drop-sb-passwordmanager |
alex/drop-*-storyboard |
Remaining storyboards |
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).