Skip to content

feat: network proxy settings for tmux sessions#16

Merged
vaayne merged 5 commits intomainfrom
feature/proxy-settings
Mar 22, 2026
Merged

feat: network proxy settings for tmux sessions#16
vaayne merged 5 commits intomainfrom
feature/proxy-settings

Conversation

@vaayne
Copy link
Copy Markdown
Owner

@vaayne vaayne commented Mar 22, 2026

Summary

  • Add a Network tab in Settings to configure proxy environment variables (http_proxy, https_proxy, all_proxy, no_proxy)
  • Proxy values are persisted in UserDefaults and applied to all Mori-managed tmux sessions via tmux set-environment -g
  • Both lowercase and uppercase variants (e.g. http_proxy and HTTP_PROXY) are set automatically
  • Includes en + zh-Hans localization
image

Implementation

  • TmuxBackend: new setEnvironment/unsetEnvironment methods wrapping tmux set-environment -g/-gu
  • ProxySettingsModel: data model with entries/allEntries computed properties
  • ProxySettingsApplicator: load/save via UserDefaults, apply to tmux
  • NetworkSettingsContent: SwiftUI settings view with text fields + Clear All button
  • Proxy is applied on app launch, after session creation (handles fresh-launch), and on settings change
  • Apply tasks are debounced via task cancellation to prevent interleaved writes from rapid edits

Test plan

  • Open Settings > Network, enter proxy values, verify they appear in tmux show-environment -g
  • Clear all fields, verify env vars are unset (tmux show-environment -g no longer shows them)
  • Quit and relaunch Mori, verify proxy values are restored and applied
  • Fresh launch (no tmux server): add a project, verify proxy is applied after first session creation
  • Type rapidly in proxy fields, verify no interleaved/stale values in tmux env
  • Verify zh-Hans translations display correctly

vaayne added 2 commits March 22, 2026 20:40
Add a Network tab in Settings that lets users configure proxy environment
variables (http_proxy, https_proxy, all_proxy, no_proxy) which are
automatically applied to all tmux sessions managed by Mori via
`tmux set-environment -g`. Both lowercase and uppercase variants are set.
- Cancel in-flight proxy apply task before starting a new one to prevent
  interleaved tmux writes from rapid edits
- Add onSessionCreated callback to WorkspaceManager so proxy env vars
  are reapplied after the tmux server starts (fixes fresh-launch case
  where no server exists yet)
- Centralize proxy apply logic in applyProxyToTmux() helper
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ba712a55b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +267 to +268
public func setEnvironment(name: String, value: String) async throws {
_ = try await runner.run("set-environment", "-g", name, value)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Scope proxy env writes to Mori's own tmux server

set-environment -g mutates tmux's global environment, which tmux merges into every new window on that server. In this repo TmuxCommandRunner.run still executes plain tmux with no -L/-S socket isolation (Packages/MoriTmux/Sources/MoriTmux/TmuxCommandRunner.swift:170-177), so users who also run non-Mori sessions on the default server will inherit or lose these proxy variables too. That makes the feature affect unrelated tmux workflows, not just Mori-managed sessions.

Useful? React with 👍 / 👎.

Comment on lines +33 to +37
static func apply(_ model: ProxySettingsModel, tmuxBackend: TmuxBackend) async {
for (envName, value) in model.allEntries {
do {
if value.isEmpty {
try await tmuxBackend.unsetEnvironment(name: envName)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Stop stale apply tasks before issuing more tmux writes

proxyApplyTask?.cancel() in AppDelegate.applyProxyToTmux() does not actually debounce the update, because this loop keeps awaiting tmux commands without ever checking cancellation, and TmuxCommandRunner.run is not cancellation-aware. If a user edits a proxy field quickly, an older apply can resume after a newer one and leave later variables (for example HTTP_PROXY or NO_PROXY) at old values, so the final tmux environment can be mixed or stale.

Useful? React with 👍 / 👎.

Comment on lines +512 to +515
proxyApplyTask = Task { [weak self] in
guard let tmuxBackend = self?.workspaceManager?.tmuxBackend else { return }
let model = ProxySettingsApplicator.load()
await ProxySettingsApplicator.apply(model, tmuxBackend: tmuxBackend)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait for proxy setup before creating templated windows

This method always fire-and-forgets the proxy update. In the new worktree flow, WorkspaceManager.createWorktree() calls onSessionCreated?() and then immediately runs TemplateApplicator.apply(...) (Sources/Mori/App/WorkspaceManager.swift:381-387), so on a fresh tmux server the template can create windows and send startup commands before the proxy env has been installed. Any template command that depends on the proxy will start without it.

Useful? React with 👍 / 👎.

vaayne added 3 commits March 22, 2026 21:18
- Add Task.isCancelled guard in ProxySettingsApplicator.apply() loop so
  cancelled tasks stop issuing tmux writes immediately
- Make onSessionCreated async so WorkspaceManager awaits proxy setup
  before running TemplateApplicator (ensures proxy env is available for
  template commands)
- Three proxy modes: System (reads macOS scutil --proxy), Manual, None
- System mode auto-detects HTTP/HTTPS/SOCKS proxy and bypass list from
  macOS system configuration
- Manual mode with "Same as HTTP" toggle for HTTPS proxy
- Explicit Apply button instead of fire-on-keystroke (eliminates race
  conditions entirely)
- Read-only fields in System mode to show detected values
- Renamed allProxy to socksProxy for clarity
- Updated en + zh-Hans localization strings
- Update settings hint to clearly state proxy changes only affect new
  tabs/panes, existing shells keep their current environment
- Add docs/network-proxy.md with full documentation: modes, env vars,
  the new-panes-only limitation with manual workaround, and system
  proxy detection details
- Updated en + zh-Hans localization
@vaayne vaayne merged commit 736b947 into main Mar 22, 2026
1 check passed
@vaayne vaayne deleted the feature/proxy-settings branch March 22, 2026 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant