refactor: remove mac attach-only setting
This commit is contained in:
@@ -182,14 +182,6 @@ final class AppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachExistingGatewayOnly: Bool {
|
|
||||||
didSet {
|
|
||||||
self.ifNotPreview {
|
|
||||||
UserDefaults.standard.set(self.attachExistingGatewayOnly, forKey: attachExistingGatewayOnlyKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var remoteTarget: String {
|
var remoteTarget: String {
|
||||||
didSet {
|
didSet {
|
||||||
self.ifNotPreview { UserDefaults.standard.set(self.remoteTarget, forKey: remoteTargetKey) }
|
self.ifNotPreview { UserDefaults.standard.set(self.remoteTarget, forKey: remoteTargetKey) }
|
||||||
@@ -302,8 +294,6 @@ final class AppState {
|
|||||||
self.canvasEnabled = UserDefaults.standard.object(forKey: canvasEnabledKey) as? Bool ?? true
|
self.canvasEnabled = UserDefaults.standard.object(forKey: canvasEnabledKey) as? Bool ?? true
|
||||||
self.peekabooBridgeEnabled = UserDefaults.standard
|
self.peekabooBridgeEnabled = UserDefaults.standard
|
||||||
.object(forKey: peekabooBridgeEnabledKey) as? Bool ?? true
|
.object(forKey: peekabooBridgeEnabledKey) as? Bool ?? true
|
||||||
self.attachExistingGatewayOnly = UserDefaults.standard.bool(forKey: attachExistingGatewayOnlyKey)
|
|
||||||
|
|
||||||
if !self.isPreview {
|
if !self.isPreview {
|
||||||
Task.detached(priority: .utility) { [weak self] in
|
Task.detached(priority: .utility) { [weak self] in
|
||||||
let current = await LaunchAgentManager.status()
|
let current = await LaunchAgentManager.status()
|
||||||
@@ -604,7 +594,6 @@ extension AppState {
|
|||||||
state.remoteIdentity = "~/.ssh/id_ed25519"
|
state.remoteIdentity = "~/.ssh/id_ed25519"
|
||||||
state.remoteProjectRoot = "~/Projects/clawdbot"
|
state.remoteProjectRoot = "~/Projects/clawdbot"
|
||||||
state.remoteCliPath = ""
|
state.remoteCliPath = ""
|
||||||
state.attachExistingGatewayOnly = false
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -624,9 +613,6 @@ enum AppStateStore {
|
|||||||
UserDefaults.standard.object(forKey: canvasEnabledKey) as? Bool ?? true
|
UserDefaults.standard.object(forKey: canvasEnabledKey) as? Bool ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
static var attachExistingGatewayOnly: Bool {
|
|
||||||
UserDefaults.standard.bool(forKey: attachExistingGatewayOnlyKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
|
|||||||
@@ -405,10 +405,6 @@ enum CommandResolver {
|
|||||||
cliPath: cliPath)
|
cliPath: cliPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
static var attachExistingGatewayOnly: Bool {
|
|
||||||
UserDefaults.standard.bool(forKey: attachExistingGatewayOnlyKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func connectionModeIsRemote(defaults: UserDefaults = .standard) -> Bool {
|
static func connectionModeIsRemote(defaults: UserDefaults = .standard) -> Bool {
|
||||||
self.connectionSettings(defaults: defaults).mode == .remote
|
self.connectionSettings(defaults: defaults).mode == .remote
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ final class ConnectionModeCoordinator {
|
|||||||
GatewayProcessManager.shared.setActive(true)
|
GatewayProcessManager.shared.setActive(true)
|
||||||
if GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
if GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
||||||
mode: .local,
|
mode: .local,
|
||||||
paused: paused,
|
paused: paused)
|
||||||
attachExistingOnly: AppStateStore.attachExistingGatewayOnly)
|
|
||||||
{
|
{
|
||||||
Task { await GatewayProcessManager.shared.ensureLaunchAgentEnabledIfNeeded() }
|
Task { await GatewayProcessManager.shared.ensureLaunchAgentEnabledIfNeeded() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ let peekabooBridgeEnabledKey = "clawdbot.peekabooBridgeEnabled"
|
|||||||
let deepLinkKeyKey = "clawdbot.deepLinkKey"
|
let deepLinkKeyKey = "clawdbot.deepLinkKey"
|
||||||
let modelCatalogPathKey = "clawdbot.modelCatalogPath"
|
let modelCatalogPathKey = "clawdbot.modelCatalogPath"
|
||||||
let modelCatalogReloadKey = "clawdbot.modelCatalogReload"
|
let modelCatalogReloadKey = "clawdbot.modelCatalogReload"
|
||||||
let attachExistingGatewayOnlyKey = "clawdbot.gateway.attachExistingOnly"
|
|
||||||
let cliInstallPromptedVersionKey = "clawdbot.cliInstallPromptedVersion"
|
let cliInstallPromptedVersionKey = "clawdbot.cliInstallPromptedVersion"
|
||||||
let heartbeatsEnabledKey = "clawdbot.heartbeatsEnabled"
|
let heartbeatsEnabledKey = "clawdbot.heartbeatsEnabled"
|
||||||
let debugFileLogEnabledKey = "clawdbot.debug.fileLogEnabled"
|
let debugFileLogEnabledKey = "clawdbot.debug.fileLogEnabled"
|
||||||
|
|||||||
@@ -212,12 +212,6 @@ final class ControlChannel {
|
|||||||
return "Gateway connection was closed; start the gateway (localhost:\(port)) and retry."
|
return "Gateway connection was closed; start the gateway (localhost:\(port)) and retry."
|
||||||
case .cannotFindHost, .cannotConnectToHost:
|
case .cannotFindHost, .cannotConnectToHost:
|
||||||
let isRemote = CommandResolver.connectionModeIsRemote()
|
let isRemote = CommandResolver.connectionModeIsRemote()
|
||||||
if AppStateStore.attachExistingGatewayOnly, !isRemote {
|
|
||||||
return """
|
|
||||||
Cannot reach gateway at localhost:\(port) and “Attach existing gateway only” is enabled.
|
|
||||||
Disable it in Debug Settings or start a gateway on that port.
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
if isRemote {
|
if isRemote {
|
||||||
return """
|
return """
|
||||||
Cannot reach gateway at localhost:\(port).
|
Cannot reach gateway at localhost:\(port).
|
||||||
|
|||||||
@@ -772,7 +772,7 @@ struct DebugSettings: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var canRestartGateway: Bool {
|
private var canRestartGateway: Bool {
|
||||||
self.state.connectionMode == .local && !self.state.attachExistingGatewayOnly
|
self.state.connectionMode == .local
|
||||||
}
|
}
|
||||||
|
|
||||||
private func configURL() -> URL {
|
private func configURL() -> URL {
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ enum GatewayAutostartPolicy {
|
|||||||
|
|
||||||
static func shouldEnsureLaunchAgent(
|
static func shouldEnsureLaunchAgent(
|
||||||
mode: AppState.ConnectionMode,
|
mode: AppState.ConnectionMode,
|
||||||
paused: Bool,
|
paused: Bool) -> Bool
|
||||||
attachExistingOnly: Bool) -> Bool
|
|
||||||
{
|
{
|
||||||
self.shouldStartGateway(mode: mode, paused: paused) && !attachExistingOnly
|
self.shouldStartGateway(mode: mode, paused: paused)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ final class GatewayProcessManager {
|
|||||||
|
|
||||||
func ensureLaunchAgentEnabledIfNeeded() async {
|
func ensureLaunchAgentEnabledIfNeeded() async {
|
||||||
guard !CommandResolver.connectionModeIsRemote() else { return }
|
guard !CommandResolver.connectionModeIsRemote() else { return }
|
||||||
guard !AppStateStore.attachExistingGatewayOnly else { return }
|
|
||||||
let enabled = await GatewayLaunchAgentManager.isLoaded()
|
let enabled = await GatewayLaunchAgentManager.isLoaded()
|
||||||
guard !enabled else { return }
|
guard !enabled else { return }
|
||||||
let bundlePath = Bundle.main.bundleURL.path
|
let bundlePath = Bundle.main.bundleURL.path
|
||||||
@@ -97,15 +96,6 @@ final class GatewayProcessManager {
|
|||||||
if await self.attachExistingGatewayIfAvailable() {
|
if await self.attachExistingGatewayIfAvailable() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Respect debug toggle: only attach, never spawn, when enabled.
|
|
||||||
if AppStateStore.attachExistingGatewayOnly {
|
|
||||||
await MainActor.run {
|
|
||||||
self.status = .failed("Attach-only enabled; no gateway to attach")
|
|
||||||
self.appendLog("[gateway] attach-only enabled; not spawning local gateway\n")
|
|
||||||
self.logger.warning("gateway attach-only enabled; not spawning")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await self.enableLaunchdGateway()
|
await self.enableLaunchdGateway()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,11 +204,6 @@ struct GeneralSettings: View {
|
|||||||
if !self.isNixMode {
|
if !self.isNixMode {
|
||||||
self.gatewayInstallerCard
|
self.gatewayInstallerCard
|
||||||
}
|
}
|
||||||
SettingsToggleRow(
|
|
||||||
title: "Attach only",
|
|
||||||
subtitle: "Use this when the gateway runs externally; the mac app will only attach " +
|
|
||||||
"to an already-running gateway and won't start one locally.",
|
|
||||||
binding: self.$state.attachExistingGatewayOnly)
|
|
||||||
TailscaleIntegrationSection(
|
TailscaleIntegrationSection(
|
||||||
connectionMode: self.state.connectionMode,
|
connectionMode: self.state.connectionMode,
|
||||||
isPaused: self.state.isPaused)
|
isPaused: self.state.isPaused)
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ struct MenuContent: View {
|
|||||||
Label("Send Test Notification", systemImage: "bell")
|
Label("Send Test Notification", systemImage: "bell")
|
||||||
}
|
}
|
||||||
Divider()
|
Divider()
|
||||||
if self.state.connectionMode == .local, !AppStateStore.attachExistingGatewayOnly {
|
if self.state.connectionMode == .local {
|
||||||
Button {
|
Button {
|
||||||
DebugActions.restartGateway()
|
DebugActions.restartGateway()
|
||||||
} label: {
|
} label: {
|
||||||
|
|||||||
@@ -13,19 +13,12 @@ struct GatewayAutostartPolicyTests {
|
|||||||
@Test func ensuresLaunchAgentWhenLocalAndNotAttachOnly() {
|
@Test func ensuresLaunchAgentWhenLocalAndNotAttachOnly() {
|
||||||
#expect(GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
#expect(GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
||||||
mode: .local,
|
mode: .local,
|
||||||
paused: false,
|
paused: false))
|
||||||
attachExistingOnly: false))
|
|
||||||
#expect(!GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
#expect(!GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
||||||
mode: .local,
|
mode: .local,
|
||||||
paused: false,
|
paused: true))
|
||||||
attachExistingOnly: true))
|
|
||||||
#expect(!GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
|
||||||
mode: .local,
|
|
||||||
paused: true,
|
|
||||||
attachExistingOnly: false))
|
|
||||||
#expect(!GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
#expect(!GatewayAutostartPolicy.shouldEnsureLaunchAgent(
|
||||||
mode: .remote,
|
mode: .remote,
|
||||||
paused: false,
|
paused: false))
|
||||||
attachExistingOnly: false))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
summary: "Gateway lifecycle on macOS (launchd + attach-only)"
|
summary: "Gateway lifecycle on macOS (launchd)"
|
||||||
read_when:
|
read_when:
|
||||||
- Integrating the mac app with the gateway lifecycle
|
- Integrating the mac app with the gateway lifecycle
|
||||||
---
|
---
|
||||||
@@ -10,8 +10,7 @@ uses the external `clawdbot` CLI (no embedded runtime). This gives you reliable
|
|||||||
auto‑start at login and restart on crashes.
|
auto‑start at login and restart on crashes.
|
||||||
|
|
||||||
Child‑process mode (Gateway spawned directly by the app) is **not in use** today.
|
Child‑process mode (Gateway spawned directly by the app) is **not in use** today.
|
||||||
If you need tighter coupling to the UI, use **Attach‑only** and run the Gateway
|
If you need tighter coupling to the UI, run the Gateway manually in a terminal.
|
||||||
manually in a terminal.
|
|
||||||
|
|
||||||
## Default behavior (launchd)
|
## Default behavior (launchd)
|
||||||
|
|
||||||
@@ -30,35 +29,18 @@ launchctl bootout gui/$UID/com.clawdbot.gateway
|
|||||||
|
|
||||||
Replace the label with `com.clawdbot.<profile>` when running a named profile.
|
Replace the label with `com.clawdbot.<profile>` when running a named profile.
|
||||||
|
|
||||||
## Attach‑only (developer mode)
|
|
||||||
|
|
||||||
Attach‑only tells the app to **connect to an existing Gateway** without spawning
|
|
||||||
one. This is ideal for local dev (hot‑reload, custom flags).
|
|
||||||
|
|
||||||
Steps:
|
|
||||||
|
|
||||||
1) Start the Gateway yourself:
|
|
||||||
```bash
|
|
||||||
pnpm gateway:watch
|
|
||||||
```
|
|
||||||
2) In the macOS app: Debug Settings → Gateway → **Attach only**.
|
|
||||||
|
|
||||||
The UI should show “Using existing gateway …” once connected.
|
|
||||||
|
|
||||||
## Unsigned dev builds
|
## Unsigned dev builds
|
||||||
|
|
||||||
`scripts/restart-mac.sh --no-sign` is for fast local builds when you don’t have
|
`scripts/restart-mac.sh --no-sign` is for fast local builds when you don’t have
|
||||||
signing keys. To prevent launchd from pointing at an unsigned relay binary, it:
|
signing keys. To prevent launchd from pointing at an unsigned relay binary, it:
|
||||||
|
|
||||||
- Writes `~/.clawdbot/disable-launchagent`.
|
- Writes `~/.clawdbot/disable-launchagent`.
|
||||||
- Sets `clawdbot.gateway.attachExistingOnly=true` in the macOS app defaults.
|
|
||||||
|
|
||||||
Signed runs of `scripts/restart-mac.sh` clear these overrides if the marker is
|
Signed runs of `scripts/restart-mac.sh` clear this override if the marker is
|
||||||
present. To reset manually:
|
present. To reset manually:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rm ~/.clawdbot/disable-launchagent
|
rm ~/.clawdbot/disable-launchagent
|
||||||
defaults write com.clawdbot.mac clawdbot.gateway.attachExistingOnly -bool NO
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remote mode
|
## Remote mode
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Last updated: 2026-01-01
|
|||||||
## TL;DR
|
## TL;DR
|
||||||
- **Tailoring lives outside the repo:** `~/clawd` (workspace) + `~/.clawdbot/clawdbot.json` (config).
|
- **Tailoring lives outside the repo:** `~/clawd` (workspace) + `~/.clawdbot/clawdbot.json` (config).
|
||||||
- **Stable workflow:** install the macOS app; let it run the bundled Gateway.
|
- **Stable workflow:** install the macOS app; let it run the bundled Gateway.
|
||||||
- **Bleeding edge workflow:** run the Gateway yourself via `pnpm gateway:watch`, then point the macOS app at it using **Debug Settings → Gateway → Attach only**.
|
- **Bleeding edge workflow:** run the Gateway yourself via `pnpm gateway:watch`, then let the macOS app attach in Local mode.
|
||||||
|
|
||||||
## Prereqs (from source)
|
## Prereqs (from source)
|
||||||
- Node `>=22`
|
- Node `>=22`
|
||||||
@@ -84,9 +84,7 @@ pnpm gateway:watch
|
|||||||
In **Clawdbot.app**:
|
In **Clawdbot.app**:
|
||||||
|
|
||||||
- Connection Mode: **Local**
|
- Connection Mode: **Local**
|
||||||
- Settings → **Debug Settings** → **Gateway** → enable **Attach only**
|
The app will attach to the running gateway on the configured port.
|
||||||
|
|
||||||
This makes the app **only connect to an already-running gateway** and **never spawn** its own.
|
|
||||||
|
|
||||||
### 3) Verify
|
### 3) Verify
|
||||||
|
|
||||||
@@ -98,7 +96,6 @@ pnpm clawdbot health
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Common footguns
|
### Common footguns
|
||||||
- **Attach only enabled, but nothing is running:** app shows “Attach-only enabled; no gateway to attach”.
|
|
||||||
- **Wrong port:** Gateway WS defaults to `ws://127.0.0.1:18789`; keep app + CLI on the same port.
|
- **Wrong port:** Gateway WS defaults to `ws://127.0.0.1:18789`; keep app + CLI on the same port.
|
||||||
- **Where state lives:**
|
- **Where state lives:**
|
||||||
- Credentials: `~/.clawdbot/credentials/`
|
- Credentials: `~/.clawdbot/credentials/`
|
||||||
@@ -129,4 +126,4 @@ user service (no lingering needed). See [Gateway runbook](/gateway) for the syst
|
|||||||
- [Gateway configuration](/gateway/configuration) (config schema + examples)
|
- [Gateway configuration](/gateway/configuration) (config schema + examples)
|
||||||
- [Discord](/providers/discord) and [Telegram](/providers/telegram) (reply tags + replyToMode settings)
|
- [Discord](/providers/discord) and [Telegram](/providers/telegram) (reply tags + replyToMode settings)
|
||||||
- [Clawdbot assistant setup](/start/clawd)
|
- [Clawdbot assistant setup](/start/clawd)
|
||||||
- [macOS app](/platforms/macos) (gateway lifecycle + “Attach only”)
|
- [macOS app](/platforms/macos) (gateway lifecycle)
|
||||||
|
|||||||
@@ -91,13 +91,11 @@ for arg in "$@"; do
|
|||||||
log " CLAWDBOT_GATEWAY_WAIT_SECONDS=0 Wait time before gateway port check (unsigned only)"
|
log " CLAWDBOT_GATEWAY_WAIT_SECONDS=0 Wait time before gateway port check (unsigned only)"
|
||||||
log ""
|
log ""
|
||||||
log "Unsigned recovery:"
|
log "Unsigned recovery:"
|
||||||
log " defaults write <bundle-id> clawdbot.gateway.attachExistingOnly -bool YES"
|
|
||||||
log " node dist/entry.js daemon install --force --runtime node"
|
log " node dist/entry.js daemon install --force --runtime node"
|
||||||
log " node dist/entry.js daemon restart"
|
log " node dist/entry.js daemon restart"
|
||||||
log ""
|
log ""
|
||||||
log "Reset unsigned overrides:"
|
log "Reset unsigned overrides:"
|
||||||
log " rm ~/.clawdbot/disable-launchagent"
|
log " rm ~/.clawdbot/disable-launchagent"
|
||||||
log " defaults write <bundle-id> clawdbot.gateway.attachExistingOnly -bool NO"
|
|
||||||
log ""
|
log ""
|
||||||
log "Default behavior: Auto-detect signing keys, fallback to --no-sign if none found"
|
log "Default behavior: Auto-detect signing keys, fallback to --no-sign if none found"
|
||||||
exit 0
|
exit 0
|
||||||
@@ -203,20 +201,9 @@ choose_app_bundle() {
|
|||||||
|
|
||||||
choose_app_bundle
|
choose_app_bundle
|
||||||
|
|
||||||
APP_BUNDLE_ID="$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${APP_BUNDLE}/Contents/Info.plist" 2>/dev/null || true)"
|
# When signed, clear any previous launchagent override marker.
|
||||||
|
if [[ "$NO_SIGN" -ne 1 && -f "${LAUNCHAGENT_DISABLE_MARKER}" ]]; then
|
||||||
# When unsigned, avoid the app overwriting the LaunchAgent while iterating.
|
|
||||||
if [ "$NO_SIGN" -eq 1 ]; then
|
|
||||||
if [[ -n "${APP_BUNDLE_ID}" ]]; then
|
|
||||||
run_step "set attach-existing-only" \
|
|
||||||
/usr/bin/defaults write "${APP_BUNDLE_ID}" clawdbot.gateway.attachExistingOnly -bool YES
|
|
||||||
fi
|
|
||||||
elif [[ -f "${LAUNCHAGENT_DISABLE_MARKER}" ]]; then
|
|
||||||
run_step "clear launchagent disable marker" /bin/rm -f "${LAUNCHAGENT_DISABLE_MARKER}"
|
run_step "clear launchagent disable marker" /bin/rm -f "${LAUNCHAGENT_DISABLE_MARKER}"
|
||||||
if [[ -n "${APP_BUNDLE_ID}" ]]; then
|
|
||||||
run_step "unset attach-existing-only" \
|
|
||||||
/usr/bin/defaults write "${APP_BUNDLE_ID}" clawdbot.gateway.attachExistingOnly -bool NO
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 4) Launch the installed app in the foreground so the menu bar extra appears.
|
# 4) Launch the installed app in the foreground so the menu bar extra appears.
|
||||||
|
|||||||
@@ -133,30 +133,10 @@ function noteOpencodeProviderOverrides(cfg: ClawdbotConfig) {
|
|||||||
note(lines.join("\n"), "OpenCode Zen");
|
note(lines.join("\n"), "OpenCode Zen");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAC_APP_BUNDLE_ID = "com.clawdbot.mac";
|
|
||||||
const MAC_ATTACH_EXISTING_ONLY_KEY = "clawdbot.gateway.attachExistingOnly";
|
|
||||||
|
|
||||||
function resolveHomeDir(): string {
|
function resolveHomeDir(): string {
|
||||||
return process.env.HOME ?? os.homedir();
|
return process.env.HOME ?? os.homedir();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readMacAttachExistingOnly(): Promise<boolean | null> {
|
|
||||||
const result = await runCommandWithTimeout(
|
|
||||||
[
|
|
||||||
"/usr/bin/defaults",
|
|
||||||
"read",
|
|
||||||
MAC_APP_BUNDLE_ID,
|
|
||||||
MAC_ATTACH_EXISTING_ONLY_KEY,
|
|
||||||
],
|
|
||||||
{ timeoutMs: 2000 },
|
|
||||||
).catch(() => null);
|
|
||||||
if (!result || result.code !== 0) return null;
|
|
||||||
const raw = result.stdout.trim().toLowerCase();
|
|
||||||
if (["1", "true", "yes"].includes(raw)) return true;
|
|
||||||
if (["0", "false", "no"].includes(raw)) return false;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function noteMacLaunchAgentOverrides() {
|
async function noteMacLaunchAgentOverrides() {
|
||||||
if (process.platform !== "darwin") return;
|
if (process.platform !== "darwin") return;
|
||||||
const markerPath = path.join(
|
const markerPath = path.join(
|
||||||
@@ -165,17 +145,12 @@ async function noteMacLaunchAgentOverrides() {
|
|||||||
"disable-launchagent",
|
"disable-launchagent",
|
||||||
);
|
);
|
||||||
const hasMarker = fs.existsSync(markerPath);
|
const hasMarker = fs.existsSync(markerPath);
|
||||||
const attachOnly = await readMacAttachExistingOnly();
|
if (!hasMarker) return;
|
||||||
if (!hasMarker && attachOnly !== true) return;
|
|
||||||
|
|
||||||
const lines = [
|
const lines = [
|
||||||
hasMarker ? `- LaunchAgent writes are disabled via ${markerPath}.` : null,
|
`- LaunchAgent writes are disabled via ${markerPath}.`,
|
||||||
attachOnly === true
|
|
||||||
? `- macOS app is set to Attach-only (${MAC_APP_BUNDLE_ID}:${MAC_ATTACH_EXISTING_ONLY_KEY}=true).`
|
|
||||||
: null,
|
|
||||||
"- To restore default behavior:",
|
"- To restore default behavior:",
|
||||||
` rm ${markerPath}`,
|
` rm ${markerPath}`,
|
||||||
` defaults write ${MAC_APP_BUNDLE_ID} ${MAC_ATTACH_EXISTING_ONLY_KEY} -bool NO`,
|
|
||||||
].filter((line): line is string => Boolean(line));
|
].filter((line): line is string => Boolean(line));
|
||||||
note(lines.join("\n"), "Gateway (macOS)");
|
note(lines.join("\n"), "Gateway (macOS)");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user