diff --git a/ClaudeIsland/Core/Localization.swift b/ClaudeIsland/Core/Localization.swift index a4765db1..e2662233 100644 --- a/ClaudeIsland/Core/Localization.swift +++ b/ClaudeIsland/Core/Localization.swift @@ -108,16 +108,16 @@ enum L10n { static var anthropicApiProxyDescription: String { tr( """ - Applies to: the rate-limit bar (api.anthropic.com) and every subprocess CodeIsland spawns — including the Stats plugin's claude CLI and any future plugin's shell-outs. We set HTTPS_PROXY / HTTP_PROXY / ALL_PROXY on CodeIsland's own process once at startup, so children inherit it automatically. No launchctl pollution, no per-plugin opt-in. + Applies to: the rate-limit bar (api.anthropic.com) and every subprocess MioIsland spawns — including the Stats plugin's claude CLI and any future plugin's shell-outs. HTTPS_PROXY / HTTP_PROXY / ALL_PROXY are set once at startup, all children inherit automatically. - Does NOT apply to: CodeLight sync (our own server, stays direct), or third-party plugins that use their own URLSession to reach external APIs — those honor system proxy settings instead. + Does NOT apply to: CodeLight sync (always direct) or third-party plugin URLSession calls (those use system proxy). Leave empty for direct connection. """, """ - 作用于:刘海额度条(api.anthropic.com)和 CodeIsland 启动的所有子进程 —— 包括 Stats 插件的 claude CLI、未来任何插件的 shell-out。我们在启动时给 CodeIsland 自身进程 `setenv` 一次 HTTPS_PROXY / HTTP_PROXY / ALL_PROXY,所有子进程自动继承。不污染全局,不需要每个插件单独适配。 + 作用于:刘海额度条 (api.anthropic.com) 和 MioIsland 启动的所有子进程,包括 Stats 插件的 claude CLI。启动时设置一次 HTTPS_PROXY / HTTP_PROXY / ALL_PROXY,子进程自动继承。 - 不作用于:CodeLight 同步(我们自己的服务器,始终直连);以及第三方插件自己用 URLSession 调用外部 API 的场景(那种走系统代理设置)。 + 不作用于:CodeLight 同步(始终直连)、第三方插件的 URLSession 调用(走系统代理)。 留空即直连。 """ @@ -218,6 +218,7 @@ enum L10n { static var starOnGitHub: String { tr("Star on GitHub", "GitHub 点星") } static var wechatLabel: String { tr("WeChat", "微信") } static var maintainedTagline: String { tr("Actively maintained · Your star keeps us going!", "持续更新中 · Star 是我们最大的动力!") } + static var quitApp: String { tr("Quit Mio Island", "退出 Mio Island") } // MARK: - Plugin marketplace static var pluginMarketplaceTitle: String { tr("Plugin Marketplace", "插件市场") } diff --git a/ClaudeIsland/Services/Sync/TerminalWriter.swift b/ClaudeIsland/Services/Sync/TerminalWriter.swift index d9ecdb79..d35bebed 100644 --- a/ClaudeIsland/Services/Sync/TerminalWriter.swift +++ b/ClaudeIsland/Services/Sync/TerminalWriter.swift @@ -182,9 +182,9 @@ final class TerminalWriter { } defer { AEDisposeDesc(&targetAddr) } - // Now the question is correctly: "Can Code Island automate this terminal?" + // Check: "Can this app automate the target terminal?" let status = AEDeterminePermissionToAutomateTarget( - &requestorAddr, + &targetAddr, AEEventClass(typeWildCard), AEEventID(typeWildCard), false @@ -911,13 +911,9 @@ final class TerminalWriter { let sessionId = json["sessionId"] as? String, Self.isUuidLike(sessionId) else { continue } - // Verify the process is still alive - let (out, ok) = await runShellWithTimeout( - "/bin/ps", ["-p", "\(pid)", "-o", "pid="], timeout: 1.0 - ) - guard ok, - let line = out?.trimmingCharacters(in: .whitespacesAndNewlines), - line == "\(pid)" else { continue } + // Verify the process is still alive using kill(0) signal check. + // Faster and more reliable than spawning /bin/ps subprocess. + guard kill(Int32(pid), 0) == 0 else { continue } // Prefer cwd from the JSON; fall back to lsof if absent let cwd: String diff --git a/ClaudeIsland/UI/Views/NativePluginStoreView.swift b/ClaudeIsland/UI/Views/NativePluginStoreView.swift index 6ccccce9..70953318 100644 --- a/ClaudeIsland/UI/Views/NativePluginStoreView.swift +++ b/ClaudeIsland/UI/Views/NativePluginStoreView.swift @@ -160,7 +160,7 @@ struct NativePluginStoreView: View { .foregroundColor(.white.opacity(0.45)) HStack(spacing: 8) { - TextField("https://api.miomio.chat/api/i/...", text: $installURLText) + TextField("", text: $installURLText, prompt: Text("https://api.miomio.chat/api/i/...").foregroundColor(.white.opacity(0.3))) .textFieldStyle(.plain) .font(.system(size: 12, design: .monospaced)) .foregroundColor(.white.opacity(0.9)) diff --git a/ClaudeIsland/UI/Views/SystemSettingsView.swift b/ClaudeIsland/UI/Views/SystemSettingsView.swift index 74e3cfc6..80f3118e 100644 --- a/ClaudeIsland/UI/Views/SystemSettingsView.swift +++ b/ClaudeIsland/UI/Views/SystemSettingsView.swift @@ -456,7 +456,7 @@ private struct AnthropicProxyRow: View { var body: some View { VStack(alignment: .leading, spacing: 6) { - TextField(L10n.anthropicApiProxyPlaceholder, text: $proxyURL) + TextField("", text: $proxyURL, prompt: Text(L10n.anthropicApiProxyPlaceholder).foregroundColor(.white.opacity(0.3))) .textFieldStyle(.plain) .font(.system(size: 12, design: .monospaced)) .foregroundColor(.white.opacity(0.95)) @@ -472,8 +472,9 @@ private struct AnthropicProxyRow: View { ) Text(L10n.anthropicApiProxyDescription) - .font(.system(size: 10)) - .foregroundColor(.white.opacity(0.5)) + .font(.system(size: 10, weight: .medium)) + .foregroundColor(Color(white: 0.75)) + .lineSpacing(4) .fixedSize(horizontal: false, vertical: true) } } @@ -746,6 +747,30 @@ private struct AboutTab: View { .foregroundColor(Theme.detailText.opacity(0.5)) .frame(maxWidth: .infinity, alignment: .center) .padding(.top, 4) + + Button { + NSApplication.shared.terminate(nil) + } label: { + HStack(spacing: 6) { + Image(systemName: "power") + .font(.system(size: 11)) + Text(L10n.quitApp) + .font(.system(size: 12, weight: .medium)) + } + .foregroundColor(.red.opacity(0.8)) + .frame(maxWidth: .infinity) + .padding(.vertical, 10) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.red.opacity(0.08)) + ) + .overlay( + RoundedRectangle(cornerRadius: 8) + .strokeBorder(Color.red.opacity(0.15), lineWidth: 0.5) + ) + } + .buttonStyle(.plain) + .padding(.top, 4) } }