Conversation
…ures, remove stale gost linker flags
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…eRepository
Two fixes:
1. Directory guard in importFile(from:):
- Added a check using fileExists(atPath:isDirectory:) to reject directory sources
- Throws FileRepositoryError.notAFile(name) if source is a directory
- Prevents accidentally copying a directory tree into the flat files/ directory
2. validateName now returns the trimmed name:
- Changed signature from throws -> Void to throws -> String
- All callers (exists, importFile, exportFile, renameFile, deleteFile, filePath)
now use the returned trimmed name for appending paths, ensuring names with
leading/trailing whitespace don't create files with spaces in their names.
- renameFile no longer does a separate inline trim; both oldName and newName
go through validateName.
Co-Authored-By: Claude <noreply@anthropic.com>
…te dialogs Co-Authored-By: Claude <noreply@anthropic.com>
- Moved .fileImporter from emptyView and fileListView to the top-level body Group - Removed redundant as? String cast in .fileExporter's item parameter Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace SettingsView body with TabView wrapper (Profiles + Files tabs) - Extract existing NavigationSplitView into profilesTab computed property - Add selectedTab state variable - Add FileManageView.swift and FileRepository.swift to Xcode project target - Add @available(macOS 14.0, *) annotations to fix build errors - Fix NSHostingController<SettingsView> reference in MacExtrasConfigurator Co-Authored-By: Claude <noreply@anthropic.com>
…tion Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…mport/export Required by NSOpenPanel (.fileImporter) and NSSavePanel (.fileExporter) in sandboxed macOS apps. Co-Authored-By: Claude <noreply@anthropic.com>
.fileImporter provides security-scoped URLs that require startAccessingSecurityScopedResource() before reading in sandboxed apps. Also make ensureDir() throw instead of silently failing. Co-Authored-By: Claude <noreply@anthropic.com>
…ct toolbar - Profiles tab: hide scroll background for cleaner sidebar look - Files tab: remove header text, replace ellipsis button with contextMenu - Files tab: add compact import button at bottom, plain list style Co-Authored-By: Claude <noreply@anthropic.com>
…using plain list style Co-Authored-By: Claude <noreply@anthropic.com>
- Use ToolbarItem(placement: .principal) for centered GostX title - Remove window.title from MacExtrasConfigurator (now handled by SwiftUI toolbar) - Restore .sidebar list style for native macOS sidebar appearance Co-Authored-By: Claude <noreply@anthropic.com>
…ore window.title
- Remove scrollContentBackground(.hidden) — caused visual glitches
- Restore window.title in MacExtrasConfigurator
- Use fixed .navigationTitle("GostX") instead of dynamic profile name
Co-Authored-By: Claude <noreply@anthropic.com>
- LogOptionsView: change @State to @binding for loggingEnabled and logLevel so parent SettingsView state flows through to LogContentView - SettingsView: add logLevel @State, pass bindings to LogOptionsView - FileListView: restore isAvailable guard with unavailable view when App Group container is nil
- LogOptionsView: use LabeledContent + .menu picker (dropdown) instead of radio group - ProfileListView/FileListView: add 8pt horizontal padding for content margins - MacExtrasConfigurator: unifiedTitleAndToolbar + transparent titlebar + .unified toolbarStyle for Liquid Glass sidebar-titlebar fusion
Matches NetNewsWire's storyboard configuration. fullSizeContentView makes the NavigationSplitView content extend into the titlebar area, enabling the sidebar to fuse with the window titlebar like Liquid Glass.
Combined with fullSizeContentView + titlebarAppearsTransparent + .unified toolbarStyle, this allows the NavigationSplitView sidebar to extend into the titlebar area.
Per Apple docs, NavigationSplitView automatically adopts Liquid Glass on macOS 26. Custom fullSizeContentView/ignoresSafeArea may interfere.
Minimal toolbar delegate provides the toolbar area that NavigationSplitView sidebar can potentially fuse into on macOS 26.
…bar fusion Restores fullSizeContentView + titlebarAppearsTransparent + .unified toolbarStyle alongside NSToolbar and ignoresSafeArea — matching NetNewsWire's approach with NavigationSplitView.
NSScrollView (YamlTextView) respects safe area insets, leaving a gap matching the toolbar height. SwiftUI TextEditor (FileContentView) ignores it automatically. Add ignoresSafeArea(.container, edges: .top) to match.
Now matches Files behavior — no profile is selected by default when switching to Profiles, showing the placeholder view instead.
Matches the system Preferences pattern: section title, rounded card container with rows (label left, control right), thin dividers.
…Area top Matches FileContentView pattern: content then Divider then action buttons. Toolbar hidden when logging off. Added ignoresSafeArea(.container, .top) for toolbar-height gap fix.
…back Timer's scrollTo ran before SwiftUI re-rendered, targeting IDs that didn't exist yet. onChange(of: lines.count) fires after SwiftUI updates the view, guaranteeing the target is in the view hierarchy.
…abled - isFollowing default changed from true to false - onAppear(loggingEnabled:) checks state before starting poll timer - LogViewModelTests updated
macOS 26 is Apple Silicon only. Libgost.xcframework only ships arm64. Archiving was failing because Xcode builds for x86_64+arm64 by default.
…ned runtime - Removed CODE_SIGN_IDENTITY=Apple Development from Release (let Automatic pick Developer ID) - ENABLE_HARDENED_RUNTIME = YES for notarization compatibility
Automates: archive → export → DMG → optional notarization Requires Developer ID Application certificate. Notarization enabled via APPLE_ID, APPLE_PASSWORD, APPLE_TEAM environment variables.
Changed packet-tunnel-provider → packet-tunnel-provider-systemextension to match the provisioning profile generated by Automatic Signing.
There was a problem hiding this comment.
Pull request overview
Adds a macOS build + runtime path for GostX alongside the existing Android flow. This introduces a macOS Packet Tunnel Provider extension backed by the Go libgost engine (xcframework via gomobile bind), plus macOS Settings UX for multi-profile YAML editing, file management, and log viewing via an App Group container.
Changes:
- Add root
make macos/make macos-releasetargets and alibgostmacos-xcframeworkbuild target to produce/copyLibgost.xcframework. - Implement macOS VPN mode via
NETunnelProviderManager+NEPacketTunnelProvider, sharing YAML/log settings through an App Group. - Add macOS Settings NavigationSplitView UI: profiles (YAML editor), files (App Group
files/), logs (options + content), plus unit tests forLogViewModel.
Reviewed changes
Copilot reviewed 43 out of 53 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| Makefile | Adds macOS build and release targets; copies Libgost.xcframework into macos/Frameworks/. |
| macos/GostXTunnel/PacketTunnelProvider.swift | Implements Packet Tunnel startup/shutdown via Libgost + App Group YAML/log settings. |
| macos/GostXTunnel/Info.plist | Declares the packet-tunnel extension principal class and extension point. |
| macos/GostXTunnel/GostXTunnel.entitlements | Adds sandbox/App Group and Network Extension entitlements for the tunnel. |
| macos/GostXTests/GostXTests.swift | Adds unit tests for LogViewModel file loading/clear/copy behavior. |
| macos/GostX/YamlEditorView.swift | Adds a custom NSTextView wrapper with YAML highlighting + undo support. |
| macos/GostX/VpnManager.swift | Adds NETunnelProviderManager lifecycle + start/stop wrapper. |
| macos/GostX/SettingsView.swift | Reworks Settings into a 3-column NavigationSplitView (Profiles/Files/Logs). |
| macos/GostX/ProfileListView.swift | Adds profile CRUD UI bound to ConfigRepository. |
| macos/GostX/MacExtrasConfigurator.swift | Updates status bar menu: profiles submenu + settings window + VPN status observation. |
| macos/GostX/LogViewModel.swift | Adds log polling + copy/clear logic. |
| macos/GostX/LogOptionsView.swift | Adds logging enable toggle + level selection persisted via App Group defaults. |
| macos/GostX/LogContentView.swift | Adds log viewer with auto-scroll follow/pause and clipboard/truncate actions. |
| macos/GostX/GostX.entitlements | Adds App Group + Network Extension entitlements for the main app. |
| macos/GostX/FileRepository.swift | Adds App Group files/ directory CRUD and filename validation. |
| macos/GostX/FileManageViewModel.swift | Adds file list/import/export/rename/delete view model for sandboxed file handling. |
| macos/GostX/FileListView.swift | Adds Files list UI with importer/exporter + rename/delete dialogs. |
| macos/GostX/FileContentView.swift | Adds file content editor + save flow for selected App Group files. |
| macos/GostX/ConfigRepository.swift | Adds multi-profile YAML persistence + active profile sync to App Group YAML. |
| macos/GostX/Arguments.swift | Adds additional constants (keys/filenames) alongside defaultGostYAML. |
| macos/GostX/AppLogger.swift | Adds unified logging bridge that writes app logs to shared gost.log. |
| macos/GostX/AppGroupConfig.swift | Adds App Group YAML + logging preferences (suite defaults) helpers. |
| macos/GostX/AppDelegate.swift | Switches to Libgost and adds VPN/proxy mode start/stop orchestration. |
| macos/GostX.xcodeproj/xcshareddata/xcschemes/GostX.xcscheme | Updates scheme upgrade metadata. |
| macos/GostX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved | Removes SPM resolution for HighlightedTextEditor dependency. |
| macos/GostX.xcodeproj/project.pbxproj | Adds new targets/files/frameworks; embeds tunnel extension; updates build settings. |
| macos/Configuration/ExportOptions.plist | Adds export options for Developer ID distribution. |
| macos/Configuration/DevelopmentTeam.example.xcconfig | Adds example xcconfig for signing Team ID configuration. |
| libgost/tun.go | Makes sing-tun stack type configurable (system vs gvisor) and improves logs. |
| libgost/tun_test.go | Minor formatting change (trailing newline). |
| libgost/tun_stack_default.go | Adds default stack type for non-darwin platforms. |
| libgost/tun_stack_darwin.go | Selects gvisor stack type on darwin due to utun/system-stack behavior. |
| libgost/tun_darwin.go | Adds utun file descriptor discovery on darwin by scanning FDs. |
| libgost/tun_darwin_test.go | Adds darwin-only test for tunnel FD discovery (expects -1 typically). |
| libgost/Makefile | Adds macos-xcframework target and cleans xcframework output. |
| drawing.svg | Updates export DPI metadata. |
| docs/superpowers/specs/2026-07-14-makefile-macos-target-design.md | Adds design spec for Makefile macOS build targets. |
| docs/superpowers/specs/2026-07-13-macos-tun-design.md | Adds macOS TUN/VPN design documentation. |
| docs/superpowers/specs/2026-07-13-macos-file-manager-design.md | Adds macOS bypass-file manager design spec. |
| docs/superpowers/specs/2025-07-16-macos-settings-navigationsplitview-design.md | Adds Settings NavigationSplitView design spec. |
| docs/superpowers/plans/2026-07-14-makefile-macos-target.md | Adds implementation plan for Makefile macOS targets. |
| docs/superpowers/plans/2026-07-13-macos-tun-implementation.md | Adds detailed implementation plan for macOS TUN/VPN support. |
| docs/superpowers/plans/2026-07-13-macos-file-manager.md | Adds implementation plan for macOS bypass-file manager. |
| .gitignore | Ignores macOS build artifacts, Frameworks dir, and xcconfig secrets; adds xcframework ignores. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private func startVpnMode() { | ||
| AppLogger.log(.info, "Starting VPN mode") | ||
| // 同步 YAML 到 App Group | ||
| let yaml = UserDefaults.standard.string(forKey: defaultsYamlKey) ?? defaultGostYAML |
|
|
||
| private func startProxyMode() { | ||
| AppLogger.log(.info, "Starting proxy mode") | ||
| let yaml = UserDefaults.standard.string(forKey: defaultsYamlKey) ?? defaultGostYAML |
Comment on lines
+83
to
+88
| AppLogger.log(.info, "Stopping...") | ||
| if vpnMode { | ||
| Task { @MainActor in VpnManager.shared.stop() } | ||
| } else { | ||
| LibgostStopGost(nil) | ||
| } |
Comment on lines
+112
to
+114
| try await VpnManager.shared.start() | ||
| DispatchQueue.main.async { self.menu?.toOnState() } | ||
| AppLogger.log(.info, "VPN started") |
Comment on lines
+145
to
+146
| self.menu?.toOnState() | ||
| AppLogger.log(.info, "Proxy started") |
Comment on lines
+30
to
+33
| queue.async { | ||
| let timestamp = ISO8601DateFormatter().string(from: Date()) | ||
| let entry = "\(formatTimestamp()) \(line)\n" | ||
| if let data = entry.data(using: .utf8) { |
Comment on lines
+50
to
+52
| # macOS .xcframework via gomobile bind | ||
| # Produces Libgost.xcframework with macos-arm64_x86_64 slices. | ||
| # Xcode links this into the PacketTunnelProvider Extension target. |
Comment on lines
+126
to
+131
| .fileExporter( | ||
| isPresented: $showExporter, | ||
| item: exportName ?? "", | ||
| contentTypes: [.data], | ||
| defaultFilename: exportName ?? "file" | ||
| ) { result in |
Comment on lines
4
to
+24
| // Storage key for the YAML configuration (gost v3 format). | ||
| let defaultsArgumentsKey = "gost_yaml_config" | ||
|
|
||
| let defaultGostYAML = """ | ||
| services: | ||
| - name: socks5-outbound | ||
| addr: :1080 | ||
| handler: | ||
| type: socks5 | ||
| listener: | ||
| type: tcp | ||
| """ | ||
|
|
||
| // YAML 持久化 key(UserDefaults) | ||
| let defaultsYamlKey = "gost_yaml_config" | ||
|
|
||
| // VPN 模式 key | ||
| let defaultsVpnModeKey = "gost_vpn_mode_enabled" | ||
|
|
||
| // App Group 容器目录下 YAML 文件名 | ||
| let appGroupYamlFileName = "gost.yaml" |
| @available(macOS 14.0, *) | ||
| struct YamlEditorView: View { | ||
| let profileId: String | ||
| @StateObject private var repo = ConfigRepository.shared |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.