mirror of
https://github.com/MioMioOS/MioIsland
synced 2026-04-21 13:37:26 +00:00
fix: cmux probe hang + UI polish + quit button
Bug fixes: - fix(#60): probeAutomationPermission passed requestorAddr instead of targetAddr to AEDeterminePermissionToAutomateTarget, causing the AE permission check to query the wrong app and hang indefinitely, freezing the entire settings panel - fix(#59): discoverClaudeSessionsFromConfig used runShellWithTimeout to spawn /bin/ps for pid liveness checks, which fails under certain code-signing configurations. Replaced with kill(pid, 0) signal check — faster, no subprocess needed, works in all environments UI improvements: - Add "Quit Mio Island" button at bottom of Settings → About tab - Anthropic API Proxy description: improve readability (medium weight, gray-white color, wider line spacing), update CodeIsland → MioIsland - TextField placeholders: change from default black to light gray (white 30% opacity) for both proxy URL and plugin install URL fields Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
031a80eaf3
commit
b7364ee6cd
4 changed files with 39 additions and 17 deletions
|
|
@ -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", "插件市场") }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue