内容
# AppShot
## 简介
AppShot 为任何 AI 提供类似 Codex 的 App Shot 功能,适用于 macOS,并让 Claude Code 使用与 Codex 相同的 App Shot 功能。
它捕获最前面的 Mac 应用程序作为结构化上下文:应用程序元数据、可见窗口、主要窗口几何/标题、辅助功能文本/UI 树、聚焦元素文本和可选截图。仅在显式回退时提供 OCR 功能。该项目首先作为原生 macOS 应用程序发布,同时提供 CLI、MCP、Codex 技能、Claude Code 技能和插件支持作为集成层。
### 安装
```sh
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | bash
```
默认情况下,此命令会将 `AppShot.app` 安装到 `~/Applications/AppShot.app`,将 `appshot` CLI 安装到 `~/.local/bin/appshot`,将 MCP 服务器安装到 `~/.local/share/appshot/mcp`,将可选浏览器桥接扩展安装到 `~/.local/share/appshot/browser-extension/appshot-bridge`,将可选 Electron 主机桥接安装到 `~/.local/share/appshot/electron-preload/appshot-host-bridge`,将可选 Codex 主机集成适配器安装到 `~/.local/share/appshot/codex-integration/appshot-codex-host-bridge`,将训练后的 JSON 规则目录安装到 `~/Library/Application Support/AppShot/rules/seed/local-app-strategies.json`,并将 Codex 技能安装到 `~/.codex/skills/appshot`。
要让 Claude Code 使用 Codex 风格的 App Shot,请安装 Claude Code 技能和 MCP 注册:
```sh
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | APPSHOT_INSTALL_CLAUDE_CODE=1 bash
```
选项:
```sh
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | APPSHOT_INSTALL_DIR=/Applications bash
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | APPSHOT_SKILL_ONLY=1 bash
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | APPSHOT_NO_OPEN=1 bash
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | APPSHOT_RESET_PERMISSIONS=1 bash
curl -sfL https://raw.githubusercontent.com/Shiyao-Huang/appshot/main/install.sh | APPSHOT_INSTALL_CLAUDE_CODE=1 bash
```
### 功能列表
- 原生 macOS 应用程序:状态仪表盘、权限状态、捕获操作、菜单栏入口和前应用程序自动刷新跟踪,带有去重的样本。
- Swift CLI:`appshot`。
- MCP 服务器:`mcp/server.js`。
- Codex 技能:`skills/appshot/SKILL.md`。
- Codex 插件清单:`.codex-plugin/plugin.json`。
- Mac 用户发布打包:`.app`、`.zip` 和 `.dmg`。
- 训练后的 JSON 规则目录:`rules/seed/local-app-strategies.json`,安装到应用程序支持目录,以便代理可编辑规则的演化,而无需硬编码应用程序策略。
- 通过 `APPSHOT_INSTALL_CLAUDE_CODE=1` 支持 Claude Code App Shot,该选项安装 AppShot 技能和 MCP 服务器注册。
- 全局快捷键设置,默认启用,同时使用左右 Option 键。
- 共享快捷键缓存:左右 Option 键同时按下会写入最新的捕获,因此 CLI/MCP 可以立即返回它;使用 `--ignore-cache`、`--no-cache` 或 `--fresh` 进行直接捕获。
- Codex 应用程序就绪表面:`codexAppsStatus`、CLI `codex-apps-status` 和 MCP `appshot_codex_apps_status` 报告 AppShot 是否准备好作为 Codex 可访问的应用程序连接器,包括权限阻止、工具表面和强制重新获取指导。
- Codex 计算机使用率表面:`codexComputerUseStatus`、CLI `codex-computer-use-status` 和 MCP `appshot_codex_computer_use_status` 报告已安装的 Codex 计算机使用率服务、`ComputerUseAppApprovals.json` 和原生主机桥接要求,例如 `SKY_CUA_NATIVE_PIPE`、`x-codex-turn-metadata` 和 `requestComputerUseApproval`。
- 计算机使用兼容的 MCP 别名:`list_apps` 和 `get_app_state` 镜像 Codex 计算机使用工具名称;`get_app_state` 返回 Codex 风格的应用程序快照文本和 PNG 图像内容块,供 Claude Code/Codex 消费者使用。
- Codex 浏览器评论有效载体适配器:JSON 捕获包括 `codexBrowserPayload`,带有 `localBrowserContext`、`localBrowserCommentMetadata`、`localBrowserAttachedImages`、`localBrowserDesignChange.group` 和 `localBrowserScreenshot` 字段名称,供 Codex/Claude 消费者使用。浏览器 DOM 捕获优先使用真实页面 URL、目标选择器、立即目标文本、标记视口点和桥接可用性,当这些值可用时。
- Codex 浏览器截图策略:`--browser-annotation-screenshots-mode always|necessary`、MCP `browserAnnotationScreenshotsMode` 和应用程序设置 `浏览器截图` 将 `browser-annotation-screenshots-mode` 写入 `codexBrowserSettings`;`always` 默认捕获 `codexBrowserPayload` 的截图。
- Codex 浏览器运行时状态适配器:JSON 捕获包括 `codexBrowserRuntimeState`,带有 Codex `browser-sidebar-runtime-sync` 字段名称,例如 `interactionMode`、`annotationEditorMode`、`isOriginalViewEnabled`、`isDesignModifierPressed`、`isTweaksEditorOpen` 和 `activeDesignChange`。
- Codex 浏览器运行时协议适配器:JSON 捕获包括 `codexBrowserRuntimeProtocol`,带有 Codex 522 `browser-sidebar-runtime-*` 事件集,包括注释编辑器、注释预览、截图、设计擦除、设计修改器、图像拖动、同步和锚点更新事件。
- 浏览器 DOM 集成:`--include-browser-dom`、MCP `includeBrowserDOM` 和应用程序设置 `浏览器 DOM` 在 Apple Events 允许的情况下运行定时只读 Safari/Chrome DOM 探针,生成 `codexBrowserDOMIntegration.browserRuntimeEvents`,带有 Codex 运行时形状的候选事件、图像拖动 `sourceUrl`、注释/设计 `anchorState` 和 `designEditorState`。
- 浏览器远程调试目标检测:DOM 捕获识别 Codex 样式的调试页面,例如 `content shell remote debugging`、`inspectable webcontents` 和本地调试端口 `9222` / `9229` 在 `codexBrowserDOMIntegration.remoteDebuggingTarget` 中。
- Electron/CDP 远程调试探针:`--include-electron-debugging`、MCP `includeElectronDebugging` 和针对 Electron 的 `--include-browser-dom` 扫描已知 Codex 调试端口以及目标应用程序的监听端口,读取 `/json/version` / `/json/list`,并且当存在可检查的 `webSocketDebuggerUrl` 时,通过 Chrome DevTools Protocol 采样 DOM 文本和 `Accessibility.getFullAXTree`。如果 VS Code 或另一个 Electron 应用程序不公开可检查的 WebContents,捕获报告 `codexElectronRemoteDebugging.reason: noInspectableTargets` 以及 `scannedPorts` 而不是假装缺少的内容已被捕获。
- 目标激活和 AX 暴露诊断:显式 `windowID` / `pid` / `bundleID` 捕获默认激活目标,报告 `targetActivation`,并包括 `accessibility.targetWindowMatch.axWindowExposure`,以便将 VS Code/Electron 浅捕获与权限失败区分开来。
- AX 窗口发现:`list-windows` 包括 CG 窗口和 `accessibilityWindows`,以及 `windowDiscovery.hasAccessibilityOnlyWindows`。使用 `capture --window-title "Title"` 或 MCP `windowTitle` 定位 Electron/VS Code 窗口,这些窗口对 macOS 辅助功能可见,但不出现在 CGWindow 中。当仅有 AX 的目标没有 CG `windowID` 时,截图使用 AX 窗口边界并报告 `screenshot.captureMode: bounds`。
- GUI 应用程序捕获请求:`--request-app-capture` 和 MCP `requestAppCapture` 请求正在运行的 `AppShot.app` 进程执行捕获并等待其共享缓存。这为 CLI/MCP 提供了一个类似 Codex 的路径,通过签名的 GUI 应用程序会话,当 shell 前台状态不可靠时。
- 浏览器运行时桥接:`--browser-dom-install-bridge`、MCP `browserDOMInstallBridge` 和应用程序设置 `浏览器桥接` 可选地安装一个页面级 Safari/Chrome 监听器和 `window.codex_desktop.sendMessageToHost` / `subscribeToHostMessages` 垫片。它记录真实的 `browser-sidebar-runtime-*` 桥接事件到 `browserRuntimeBridgeEvents` 并报告 `codexDesktopShimAvailable`、`nativeCodexDesktopAvailable`、`codexHostBridgeAvailable`、`hostAPI` 和 `hostChannel`;`--browser-dom-clear-bridge-log` 清除该选项卡本地日志。
- 浏览器扩展/预加载助手:`browser-extension/appshot-bridge` 作为可选的未打包 MV3 助手打包和安装。它从页面预加载公开 `window.codex_desktop`,通过 `window.postMessage+extension-runtime` 传递,并将 `extensionHelperAvailable`、`hostOwner` 和 `hostTransport` 显示在 `codexBrowserDOMIntegration.browserRuntimeBridge` 中。
- Electron 预加载/主机助手:`electron-preload/appshot-host-bridge` 作为可选的 Electron 集成打包和安装。它从 `preload.cjs` 公开 `window.codex_desktop`,在 `host.cjs` 中注册 `installAppShotElectronHostBridge(ipcMain)`,并在 `codexBrowserDOMIntegration.browserRuntimeBridge` 中显示 `electronHostBridgeAvailable`、`hostOwner: electron-preload` 和 `hostTransport: electron-ipc`。
- Codex 主机集成适配器:`codex-integration/appshot-codex-host-bridge` 作为 Codex 端主机适配器打包和安装。它导出 `installAppShotCodexHostBridge`,组合 Electron 助手,报告 `hostOwner: codex-electron-host`,并遵循 Codex 522 的真实拆分 IPC 路径:`codex_desktop:browser-sidebar-runtime-message` 用于预加载到主机 `ipcRenderer.invoke` / `ipcMain.handle`,以及 `codex_desktop:message-for-view` 用于主机到预加载 `webContents.send` / `ipcRenderer.on`。`scripts/analyze_codex_electron_host_injection.mjs` 验证这些打包插入点,而无需修改 Codex.app;发布/安装还包括分析器、`patch_codex_electron_host_for_appshot.mjs` 和 `materialize_codex_host_patch_for_appshot.mjs` 在安装的 Codex 集成目录下,以便明确的 Codex 主机补丁实验不需要源代码检查。编译器可以提取打包的 `app.asar` 加上 `app.asar.unpacked` 到一个修补的副本,同时保持原始的 Codex.app 不变。独立的 CLI/MCP 状态保持 `privateCodexWebviewHostAttached: false`,直到真正的 Codex Electron 主机加载或包装它。
### 构建和运行
在 Xcode 中,打开 `AppShot.xcodeproj`,选择 `AppShot` 方案,并运行应用程序目标。不要在 Xcode 中运行 `install.sh`;它是终端/curl 安装程序,不是构建目标。
```sh
swift build
swift scripts/generate_app_icon.swift
xcodebuild -project AppShot.xcodeproj -scheme AppShot -configuration Release build
```
对于完整的本地发布包:
```sh
chmod +x scripts/build_release.sh
scripts/build_release.sh 0.1.15
open dist/AppShot-macOS-0.1.15/AppShot.app
```
对于公共 macOS 发布,签名时使用 `Developer ID Application` 身份,并对 DMG 进行公证:
```sh
APPSHOT_PUBLIC_RELEASE=1 \
APPSHOT_CODESIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \
APPSHOT_NOTARY_PROFILE="appshot-notary" \
scripts/build_release.sh 0.1.15
```
公共发布路径拒绝 Apple Development 或临时签名,将 DMG 提交给 Apple 进行公证,钉上票根,并运行 Gatekeeper 评估。
CLI 示例:
```sh
.build/debug/appshot status --pretty
.build/debug/appshot codex-apps-status --pretty
.build/debug/appshot permissions --prompt --pretty
.build/debug/appshot capture --pretty
.build/debug/appshot capture --include-screenshot --screenshot appshot.png --output appshot.json --pretty
.build/debug/appshot capture --include-ocr --screenshot appshot.png --output appshot.json --pretty
```
Codex 一致性检查:
```sh
scripts/verify_codex_parity.sh
```
这会构建 Swift CLI 和原生 `AppShot.app`,检查包标识/版本,验证 Codex 样式的 JSON 别名,并运行 MCP 烟雾测试。有关证据支持的对齐矩阵,请参见 `docs/codex-parity.md`。
### 效果评估
2026-06-08 从可见应用集中捕获的最新本地全应用规则门控:
| 检查项 | 结果 |
| --- | --- |
| Live 全应用训练 | 17 个样本,0 次失败 |
| 选择规则得分 | 最低 0.9338,平均 0.9804 |
| 重放相同的实时原始捕获 | 17 个样本,最低 0.9410,平均 0.9827 |
| 重放之前的原始捕获集 | 22 个样本,最低 0.8559,平均 0.9850 |
| 规则输出合约 | `ruleOutputKind: upsertable-json-rule`,`ruleArtifactFormat: json` |
| 治理和一致性门控 | `scripts/verify_rule_governance.py` ok,`scripts/verify_codex_parity.sh` ok |
最低实时选择得分是 Safari,值为 0.9338;Codex 和 Feishu 选择的规则得分分别为 0.9410 和 0.9416。VS Code Windows 的得分均高于 0.9697,之前崩溃的 AI 微信桌面捕获现在完成,得分 1.0000。规则训练器仍然将 OCR 视为教师/评估器信号;有效性改进编码在 JSON 规则中,例如锚点拒绝、加权提升、行上限和 `transport.maxLineChars`。有关演变过程,请参见 [docs/rule-training-evolution.md](docs/rule-training-evolution.md)。
应用/窗口 QA 示例:
```sh
scripts/qa_app_capture.py --bundle-id com.apple.dt.Xcode --window-title 'appshot —' --accessibility-timeout 20 --expect-hierarchy 'Source Editor'
```
可访问性输出包括 `accessibility.text` 用于完整的 AX/document 文本和 `accessibility.visibleText` 用于坐标排序的可见 UI 文本。当一个大型文本控件暴露 `AXBoundsForRange` 时,AppShot 使用行片段,以便编辑器/正文文本可以加入可见阅读流。
对于 Electron 应用,例如 VS Code,AppShot 还尝试 `AXManualAccessibility` 和 `AXEnhancedUserInterface`,然后遍历树。结果报告在 `accessibility.electronAccessibility` 中,包括每个尝试的 AX 属性,以便可以诊断浅层 Electron 捕获,而不是像正常的 macOS AX 输出一样静默。
当请求的 `windowID` 无法与 macOS `AXWindow` 匹配时,AppShot 报告 `accessibility.targetWindowMatch`,包含候选分数、聚焦/主要 AX 结果、最佳候选、 `bestCandidateIsAXWindow`、`axWindowExposure.roleCounts` 和恢复步骤。显式目标捕获默认激活目标应用/窗口并写入 `targetActivation`;仅当焦点必须更改时,传递 `--no-activate-target`。如果 shell/MCP 前台状态不可靠,请添加 `--request-app-capture` 以询问正在运行的 GUI `AppShot.app` 捕获并写入共享缓存;结果包含 `appCaptureRequest`。如果 `axWindowExposure.suspectedSelfReferentialAXWindows` 为真,则 macOS 返回应用级 AX 候选而不是真正的窗口候选。在这种情况下,`accessibility.rootSource` 成为 `targetWindowUnmatchedApplication` 或 `targetWindowUnmatchedFocusedWindow`,而不是假装应用级菜单树是请求的窗口;Codex 文本还抑制应用菜单栏外壳,以免菜单噪音主导输出。当调试 Electron 帮助程序/渲染进程时,显式 `--pid` 捕获可以直接针对非 `NSRunningApplication` PID,并报告 `auxiliaryProcessCapture` 而不是回退到前台应用。
对于具有多个窗口的 Electron 应用,Codex 通常通过 Accessibility 树看到窗口,即使 CGWindow 未列出它们。`appshot list-windows --pretty` 现在报告 `accessibilityWindows`、`windowDiscovery.preferredAccessibilityWindow` 和 `windowDiscovery.hasAccessibilityOnlyWindows`,用于每个应用。如果所需 VS Code 窗口仅出现在该 AX 列表中,请按标题定位它;AX 仅限窗口的截图会回退到 AX 边界矩形并报告 `screenshot.captureMode: bounds`:
```sh
appshot capture --bundle-id com.microsoft.VSCode --window-title "image.png — 自媒体" --pretty
```
JSON 捕获输出还包括 `codexBrowserPayload`,这是 Codex 浏览器注释有效载荷字段的原生 AppShot 适配器。它将应用/窗口/AX/截图证据映射到 Codex 使用的相同 `localBrowser*` 名称,但不声称 AppShot 实现 Codex 的嵌入式浏览器设计编辑器或图像拖动运行时。当 `--include-browser-dom` 可用时,有效载荷使用浏览器页面 URL 作为 `localBrowserContext.pageUrl` / `frameUrl`,公开目标值,例如 `targetSelector`、`targetImmediateText`、`targetPath`,并写入视口元数据,例如 `markerViewportPoint`。当 Codex/Claude 消费者应该默认接收 `localBrowserScreenshot` 时,请使用 `--browser-annotation-screenshots-mode always`。
对于 Codex 浏览器运行时状态一致性,JSON 捕获包括 `codexBrowserRuntimeState`,并将 `activeDesignChange` 映射到 `codexBrowserPayload.localBrowserDesignChange.group`,匹配 Codex 浏览器注释有效载荷形状。CLI 和 MCP 调用可以通过 `--browser-annotation-editor-mode design`、`--browser-original-view-enabled`、`--browser-design-modifier-pressed`、`--browser-tweaks-editor-open` 和 `--browser-active-design-change-json '{"id":"design","declarations":[]}'` 等选项设置这些适配器字段。JSON 捕获还包括 `codexBrowserRuntimeProtocol`,这是整个 Codex 522 `browser-sidebar-runtime-*` 事件集的证据支持的协议适配器;它映射到 `codexBrowserPayload.localBrowserRuntimeProtocol`。
对于支持的前台浏览器应用,`--include-browser-dom` 添加 `codexBrowserDOMIntegration`。它使用短超时 Apple Events JavaScript 探针,用于 Safari 和 Chromium 样式浏览器,读取页面图像和设计目标候选,然后发出 Codex 运行时事件形状的候选条目,例如 `browser-sidebar-runtime-open-editor`、`browser-sidebar-runtime-create-comment-at-point`、`browser-sidebar-runtime-update-anchor`、`browser-sidebar-runtime-open-design-editor`、`browser-sidebar-runtime-design-scrub-changed`、`browser-sidebar-runtime-image-drag-started` 和 `browser-sidebar-runtime-image-drag-ended`。`--browser-dom-install-bridge` 更进一步,通过安装临时页面监听器和页面本地 `window.codex_desktop` 垫片,带有 `sendMessageToHost` / `subscribeToHostMessages`;它将指针、键盘、拖动、同步和垫片消息事件记录到 `codexBrowserDOMIntegration.browserRuntimeBridgeEvents`。对于浏览器拥有的桥,加载位于 `~/.local/share/appshot/browser-extension/appshot-bridge` 的解包帮助程序;其 `page-bridge.js`、`content.js` 和 `background.js` 通过 `window.postMessage+extension-runtime` 将相同的 Codex 形状的消息路由。对于应用中您控制的 Electron 拥有的桥,将 `~/.local/share/appshot/electron-preload/appshot-host-bridge/preload.cjs` 编入 `BrowserWindow.webPreferences.preload` 并从 `host.cjs` 注册 `installAppShotElectronHostBridge(ipcMain)`。如果存在可观察的原生 Codex 预加载主机 API,AppShot 报告 `nativeCodexDesktopAvailable`、`codexHostBridgeAvailable`、`hostOwner: codex-electron-host`、`hostTransport: codex-electron-ipc`,并保持 `codexDesktopShimAvailable: false`。对于 Codex 端主机集成实验,运行 `scripts/analyze_codex_electron_host_injection.mjs`,然后在 Codex 注册 `ipcMain.handle(Ts)` 之前加载 `~/.local/share/appshot/codex-integration/appshot-codex-host-bridge/codex-host-adapter.cjs`,或用 `wrapCodexRuntimeMessageHandler` 包装现有处理程序。分析器和 `scripts/patch_codex_electron_host_for_appshot.mjs` 发现来自 IPC 锚点的哈希 `main-*.js` 包;使用 `--asar-root /path/to/unpacked/app.asar` 用于真正的解包 Codex asar,使用 `--codex-app /Applications/Codex.app` 仅检查应用是否已经公开解包的 asar。如果 Codex.app 仅包含打包的 `Contents/Resources/app.asar`,运行 `scripts/materialize_codex_host_patch_for_appshot.mjs --codex-app /Applications/Codex.app --output-dir /tmp/codex-appshot-host --copy-app-bundle --pretty`;它提取 `app.asar` 加上 `app.asar.unpacked`,修补复制的 asar 目录,语法检查修补的 JS,并留下原始 Codex.app 不变。检查 `codexBrowserDOMIntegration.browserRuntimeBridge.codexDesktopShimAvailable`、`nativeCodexDesktopAvailable`、`codexHostBridgeAvailable`、`extensionHelperAvailable`、`electronHostBridgeAvailable`、`hostAPI`、`hostChannel`、`hostInboundChannel`、`hostOutboundChannel`、`ipcPattern`、`hostOwner` 和 `hostTransport` 以验证活动桥;检查 `codexComputerUseStatus.hostBridge.codexHostIntegration` 以查看 Codex 主机适配器工件是否已安装以及私有 Codex webview 主机是否实际附加。这些桥接事件合并到 `codexBrowserPayload.localBrowserRuntimeEvents` 中,并使 `localBrowserRuntimeProtocol.liveEventStreamAvailable` 对该选项卡为真。如果 Apple Events 脚本不可用、被阻止或超时,捕获将返回 `available: false` 以及原因而不是挂起。此桥接是页面级/浏览器扩展/Electron 预加载/Codex 主机检测,但独立 CLI/MCP 路径仍然无法声称 Codex 的内部 Electron 预加载生命周期。
对于 Electron 应用,添加 `--include-electron-debugging` 或针对 Electron 目标使用 `--include-browser-dom`。AppShot 将报告 `codexElectronRemoteDebugging`,包含扫描的端口、DevTools 目标、选定的目标评分和可选的 CDP DOM/AX 快照。这是与 DevTools 相邻的公共路径,用于类似 Codex 的 Electron 内容,但它仍然依赖于目标应用公开可检查的 WebContents。
DOM 捕获还包括 `codexBrowserDOMIntegration.remoteDebuggingTarget`,匹配 Codex 应用会话证据,用于 `content shell remote debugging`、`inspectable webcontents` 和本地调试端口 `9222` / `9229`。相同的分类映射到 `codexBrowserPayload.localBrowserCommentMetadata.browserDOMIntegration.remoteDebuggingTarget`。
`status` 和 `capture` 还包括 `codexAppsStatus`,并且可以通过 `appshot codex-apps-status --pretty` 或 MCP `appshot_codex_apps_status` 获得此有效载荷。此有效载荷镜像聚焦差异的 Codex 应用列表就绪形状:`codexAppsReady` 源自权限阻止器,`forceRefetchSupported` / `retryWhenNotReady` 记录重试路径,`tools` 列出 AppShot MCP 界面,Claude Code 或 Codex 可以调用。
### 权限
Accessibility 权限是用于丰富 UI/文本树的主要路径,需要 AppShot 的权限。Screen Recording 权限是用于截图和 OCR 的必要条件。OCR 是不通过 Accessibility 暴露可见内容的应用程序的备用方案。在 macOS 上,权限属于启动的应用身份,因此在授予 AppShot 权限时,请运行已安装的 `AppShot.app`。
全局快捷键默认启用:同时按下左右 Option 键以捕获当前应用。您可以在 AppShot 设置中关闭它。
快捷键捕获会写入共享的最近缓存。CLI 和 MCP 捕获在没有显式目标的情况下默认读取该缓存;添加 `--ignore-cache`、`--no-cache` 或 `--fresh`,当您需要直接当前窗口捕获时。
如果 macOS 在隐私和安全中显示 AppShot 已启用,但 AppShot 仍然报告缺少权限,请检查身份漂移:
```sh
scripts/diagnose_tcc_identity.sh
```
Xcode Debug 构建、已安装的发布构建和 SwiftPM CLI 二进制文件可以具有相同的可见名称,但具有不同的代码签名身份。临时签名的构建特别脆弱,因为重建可以更改 `CDHash`,使 TCC 视为不同的应用程序。对于稳定的开发/发布权限,请使用一个已安装的应用身份或通过 `APPSHOT_CODESIGN_IDENTITY` 使用稳定的签名身份进行构建。
要从陈旧的隐私和安全条目中恢复,请重置旧的 TCC 行,一次打开确切的已安装应用程序,并再次授予权限:
```sh
tccutil reset Accessibility com.qppshot.AppShot
tccutil reset ScreenCapture com.qppshot.AppShot
open ~/Applications/AppShot.app
```
### 实现说明
第一个版本使用公共的 macOS API。窗口解析将继续针对本地差异的 Codex Mac App 证据进行改进,而不是从头开始猜测。
### 包含内容
- 原生 macOS 应用:状态面板、权限状态、捕捉操作、菜单栏入口,以及带重复抑制的前台应用自动刷新轨迹。
- Swift 命令行界面(CLI):`appshot`。
- MCP 服务器:`mcp/server.js`。
- Codex 技能:`skills/appshot/SKILL.md`。
- Codex 插件清单:`.codex-plugin/plugin.json`。
- 面向 Mac 用户的发布包:`.app`、`.zip`、`.dmg`。
- 训练好的 JSON 规则目录:`rules/seed/local-app-strategies.json`,安装到 Application Support,后续由代理继续编辑和演进,不把应用策略硬编码进运行时代码。
- 通过 `APPSHOT_INSTALL_CLAUDE_CODE=1` 给 Claude Code 安装 AppShot 技能和 MCP 注册,让 Claude Code 拥有 Codex 风格的 App Shot 能力。
- 全局快捷键设置,默认使用左 Option + 右 Option。
- 共享快捷键缓存:左 Option + 右 Option 会写入最近一次捕捉,CLI/MCP 可以立即读取;需要直接重新捕捉时使用 `--ignore-cache`、`--no-cache` 或 `--fresh`。
- Codex 应用就绪度接口:`codexAppsStatus`、CLI `codex-apps-status` 和 MCP `appshot_codex_apps_status` 会报告 AppShot 作为 Codex 可访问应用连接器是否就绪,包括权限阻止器、工具列表和强制重新捕捉指引。
- Codex 计算机使用一致性接口:`codexComputerUseStatus`、CLI `codex-computer-use-status` 和 MCP `appshot_codex_computer_use_status` 会报告已安装的 Codex 计算机使用服务、`ComputerUseAppApprovals.json`,以及 `SKY_CUA_NATIVE_PIPE`、`x-codex-turn-metadata`、`requestComputerUseApproval` 等主机桥依赖。
- 计算机使用兼容 MCP 别名:`list_apps` 和 `get_app_state` 对齐 Codex 计算机使用的工具名称;`get_app_state` 会返回 Codex 风格的应用快照文本和 PNG 图片内容,方便 Claude Code/Codex 消费。
- Codex 浏览器评论载荷适配器:JSON 捕捉会包含 `codexBrowserPayload`,内部使用 `localBrowserContext`、`localBrowserCommentMetadata`、`localBrowserAttachedImages`、`localBrowserDesignChange.group`、`localBrowserScreenshot` 这些 Codex/Claude 消费端字段名称。浏览器 DOM 捕捉在可用时会优先使用真实页面 URL、目标选择器、目标即时文本、标记器视口点和桥可用状态。
- Codex 浏览器截图策略:`--browser-annotation-screenshots-mode always|necessary`、MCP `browserAnnotationScreenshotsMode`、应用设置 `Browser Screenshots` 会把 `browser-annotation-screenshots-mode` 写入 `codexBrowserSettings`;`always` 会默认给 `codexBrowserPayload` 捕捉截图。
- Codex 浏览器运行时状态适配器:JSON 捕捉会包含 `codexBrowserRuntimeState`,使用 Codex `browser-sidebar-runtime-sync` 同名字段,例如 `interactionMode`、`annotationEditorMode`、`isOriginalViewEnabled`、`isDesignModifierPressed`、`isTweaksEditorOpen`、`activeDesignChange`。
- Codex 浏览器运行时协议适配器:JSON 捕捉会包含 `codexBrowserRuntimeProtocol`,内部是 Codex 522 的 `browser-sidebar-runtime-*` 事件集合,覆盖评论编辑器、评论预览、截图、设计扫描、设计修改器、图像拖动、同步和锚点更新。
- 浏览器 DOM 集成:`--include-browser-dom`、MCP `includeBrowserDOM`、应用设置 `Browser DOM` 会在 Apple Events 允许时,对 Safari/Chrome 进行带超时的只读 DOM 探测,生成 `codexBrowserDOMIntegration.browserRuntimeEvents`,包含 Codex 运行时形状的候选事件、图像拖动 `sourceUrl`、评论/设计 `anchorState` 和 `designEditorState`。
- 浏览器远程调试目标检测:DOM 捕捉会在 `codexBrowserDOMIntegration.remoteDebuggingTarget` 中识别 Codex 风格的调试页面,例如 `content shell remote debugging`、`inspectable webcontents`,以及本地调试端口 `9222` / `9229`。
- Electron/CDP 远程调试探测:`--include-electron-debugging`、MCP `includeElectronDebugging`,以及面向 Electron 目标的 `--include-browser-dom` 会扫描 Codex 已知调试端口和目标应用的监听端口,读取 `/json/version` / `/json/list`;如果存在可检查的 `webSocketDebuggerUrl`,会通过 Chrome DevTools Protocol 提取 DOM 文本和 `Accessibility.getFullAXTree`。如果 VS Code 或其他 Electron 应用没有暴露可检查的 WebContents,捕捉会返回 `codexElectronRemoteDebugging.reason: noInspectableTargets` 和 `scannedPorts`,不会把缺失内容伪装成已捕捉。
- 目标激活和 AX 暴露诊断:显式指定 `windowID` / `pid` / `bundleID` 时默认会先激活目标,输出 `targetActivation`,并在 `accessibility.targetWindowMatch.axWindowExposure` 中记录 AX 窗口候选暴露情况,方便把 VS Code/Electron 浅捕捉和权限失败区分开。
- AX 窗口发现:`list-windows` 同时输出 CG 窗口和 `accessibilityWindows`,并带有 `windowDiscovery.hasAccessibilityOnlyWindows`。使用 `capture --window-title "标题"` 或 MCP `windowTitle` 可以选中 macOS Accessibility 可见、但 CGWindow 缺失的 Electron/VS Code 窗口。当 AX-only 目标没有 CG `windowID` 时,截图会用 AX 窗口边界裁剪,并输出 `screenshot.captureMode: bounds`。
- GUI 应用捕捉请求:`--request-app-capture` 和 MCP `requestAppCapture` 会请求正在运行的 `AppShot.app` 进程执行捕捉,并等待它写入共享缓存。这样 CLI/MCP 可以通过签名 GUI 应用会话接近 Codex 内置 AppShot 路径,避开 shell 前台不可靠的问题。
- 浏览器运行时桥:`--browser-dom-install-bridge`、MCP `browserDOMInstallBridge`、应用设置 `Browser Bridge` 会可选安装一个页面级 Safari/Chrome 监听器和 `window.codex_desktop.sendMessageToHost` / `subscribeToHostMessages` shim,把真实 `browser-sidebar-runtime-*` 桥事件写入 `browserRuntimeBridgeEvents`,并报告 `codexDesktopShimAvailable`、`nativeCodexDesktopAvailable`、`codexHostBridgeAvailable`、`hostAPI`、`hostChannel`;`--browser-dom-clear-bridge-log` 可以清空当前标签页的本地日志。
- 浏览器扩展/预加载助手:`browser-extension/appshot-bridge` 会作为可选 unpacked MV3 助手打包和安装。它从页面预加载暴露 `window.codex_desktop`,通过 `window.postMessage+extension-runtime` 转发,并在 `codexBrowserDOMIntegration.browserRuntimeBridge` 中输出 `extensionHelperAvailable`、`hostOwner`、`hostTransport`。
- Electron 预加载/主机助手:`electron-preload/appshot-host-bridge` 会作为可选 Electron 集成打包和安装。它从 `preload.cjs` 暴露 `window.codex_desktop`,在 `host.cjs` 中注册 `installAppShotElectronHostBridge(ipcMain)`,并输出 `electronHostBridgeAvailable`、`hostOwner: electron-preload`、`hostTransport: electron-ipc`。
- Codex 主机集成适配器:`codex-integration/appshot-codex-host-bridge` 会作为 Codex 端主机适配器打包和安装。它导出 `installAppShotCodexHostBridge`,复用 Electron 助手,报告 `hostOwner: codex-electron-host`,并按 Codex 522 的真实双通道 IPC 工作:`codex_desktop:browser-sidebar-runtime-message` 用于预加载到主机 `ipcRenderer.invoke` / `ipcMain.handle`,`codex_desktop:message-for-view` 用于主机到预加载 `webContents.send` / `ipcRenderer.on`。`scripts/analyze_codex_electron_host_injection.mjs` 可以在不修改 Codex.app 的情况下验证这些打包产物接入点;发布/安装也会把分析器、`patch_codex_electron_host_for_appshot.mjs` 和 `materialize_codex_host_patch_for_appshot.mjs` 放进已安装的 Codex 集成目录,所以显式 Codex 主机补丁实验不需要源码 checkout。materializer 可以把打包的 `app.asar` 和 `app.asar.unpacked` 解进补丁副本,同时不修改原始 Codex.app;在真实 Codex Electron 主机接入之前,独立 CLI/MCP 会保持 `privateCodexWebviewHostAttached: false`。
### 构建和运行
在 Xcode 里打开 `AppShot.xcodeproj`,选择 `AppShot` scheme,然后运行 App 目标。不要在 Xcode 里运行 `install.sh`;它是给 Terminal/curl 使用的安装脚本,不是构建目标。
```sh
swift build
swift scripts/generate_app_icon.swift
xcodebuild -project AppShot.xcodeproj -scheme AppShot -configuration Release build
```
完整生成本地发布包:
```sh
chmod +x scripts/build_release.sh
scripts/build_release.sh 0.1.15
open dist/AppShot-macOS-0.1.15/AppShot.app
```
公开 macOS 发布包需要 `Developer ID Application` 证书并完成 DMG 公证:
```sh
APPSHOT_PUBLIC_RELEASE=1 \
APPSHOT_CODESIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \
APPSHOT_NOTARY_PROFILE="appshot-notary" \
scripts/build_release.sh 0.1.15
```
公开发布路径会拒绝 Apple Development 或 ad-hoc 签名,提交 Apple notarization,staple 公证票据,并运行 Gatekeeper 校验。
CLI 示例:
```sh
.build/debug/appshot status --pretty
.build/debug/appshot codex-apps-status --pretty
.build/debug/appshot permissions --prompt --pretty
.build/debug/appshot capture --pretty
.build/debug/appshot capture --include-screenshot --screenshot appshot.png --output appshot.json --pretty
.build/debug/appshot capture --include-ocr --screenshot appshot.png --output appshot.json --pretty
```
Codex 一致性检查:
```sh
scripts/verify_codex_parity.sh
```
这个脚本会构建 Swift CLI 和原生 `AppShot.app`,检查 bundle 身份和版本,验证 Codex 风格 JSON 别名,并运行 MCP smoke test。证据化的一致性矩阵见 `docs/codex-parity.md`。
### 效果衡量
最近一次本地全应用规则门控于 2026-06-08 基于当前可见应用集合完成:
| 检查项 | 结果 |
| --- | --- |
| Live all-app training | 17 个样本,0 个失败 |
| Selected rule 分数 | 最低 0.9338,平均 0.9804 |
| 同批 live raw replay | 17 个样本,最低 0.9410,平均 0.9827 |
| 上一批 raw capture replay | 22 个样本,最低 0.8559,平均 0.9850 |
| Rule 输出契约 | `ruleOutputKind: upsertable-json-rule`,`ruleArtifactFormat: json` |
| Governance 和 parity gate | `scripts/verify_rule_governance.py` 通过,`scripts/verify_codex_parity.sh` 通过 |
最终 live selected 最低分是 Safari 的 0.9338;Codex 和飞书分别为 0.9410、0.9416。VS Code 窗口均为 0.9697 以上;此前会触发 SIGTRAP 的 AI WeChat Desktop 现在能完成捕捉,得分 1.0000。训练仍保持 OCR 只作为 teacher/evaluator 信号,提效内容都在 JSON rule 中表达,例如 anchor reject、weighted boost、line cap 和 `transport.maxLineChars`。完整演进过程见 [docs/rule-training-evolution.md](docs/rule-training-evolution.md)。
应用/窗口 QA 示例:
```sh
scripts/qa_app_capture.py --bundle-id com.apple.dt.Xcode --window-title 'appshot —' --accessibility-timeout 20 --expect-hierarchy 'Source Editor'
```
Accessibility 输出同时包含完整 AX/document 文本 `accessibility.text`,以及按坐标排序的可见 UI 文本 `accessibility.visibleText`。当大块文本控件暴露 `AXBoundsForRange` 时,AppShot 会使用行级片段,让编辑器/正文文本也进入可见阅读流。
对于 VS Code 这类 Electron 应用,AppShot 会在遍历 UI 树之前尝试 `AXManualAccessibility` 和 `AXEnhancedUserInterface`。结果会记录到 `accessibility.electronAccessibility`,包括每个 AX attribute 的尝试结果,这样 Electron 捕捉过浅时可以诊断,而不是伪装成普通 macOS AX 输出。
当指定的 `windowID` 无法匹配到 macOS `AXWindow` 时,AppShot 会输出 `accessibility.targetWindowMatch`,包含候选得分、focused/main AX 结果、top candidates、`bestCandidateIsAXWindow`、`axWindowExposure.roleCounts` 和恢复步骤。显式目标捕捉默认会先激活目标 App/window,并写入 `targetActivation`;只有在不能改变焦点时才传 `--no-activate-target`。如果 shell/MCP 的 frontmost 状态不可靠,可以加 `--request-app-capture`,让正在运行的 GUI `AppShot.app` 执行捕捉并写入共享缓存;结果会包含 `appCaptureRequest`。如果 `axWindowExposure.suspectedSelfReferentialAXWindows` 为 true,说明 macOS 返回的是 app 级 AX 候选而不是真正窗口候选。这时 `accessibility.rootSource` 会变成 `targetWindowUnmatchedApplication` 或 `targetWindowUnmatchedFocusedWindow`,避免把 app 级菜单树伪装成指定窗口;Codex 文本也会压掉 app 菜单栏 shell,避免菜单噪声淹没正文。调试 Electron helper/renderer 进程时,显式 `--pid` 可以直接探测非 `NSRunningApplication` PID,并用 `auxiliaryProcessCapture` 标记结果,而不是回退到前台 App。
对于多窗口 Electron 应用,Codex 经常能从 Accessibility 树看到一些 CGWindow 没列出的窗口。`appshot list-windows --pretty` 现在会为每个 App 输出 `accessibilityWindows`、`windowDiscovery.preferredAccessibilityWindow` 和 `windowDiscovery.hasAccessibilityOnlyWindows`。如果目标 VS Code 窗口只出现在 AX 列表里,可以按标题捕捉;这类 AX-only 窗口的截图会退到 AX bounds 矩形裁剪,并输出 `screenshot.captureMode: bounds`:
```sh
appshot capture --bundle-id com.microsoft.VSCode --window-title "image.png — 自媒体" --pretty
```
JSON 捕捉还会包含 `codexBrowserPayload`,这是 AppShot 原生捕捉到 Codex browser-comment payload 字段的适配层。它会把 App/窗口/AX/截图证据映射到 Codex 使用的 `localBrowser*` 字段名,但不声称 AppShot 已经实现 Codex 内置浏览器的 design editor 或 image-drag runtime。当 `--include-browser-dom` 可用时,payload 会用浏览器页面 URL 填充 `localBrowserContext.pageUrl` / `frameUrl`,并暴露 DOM 目标字段,例如 `targetSelector`、`targetImmediateText`、`targetPath`,以及 `markerViewportPoint` 这类 viewport 元数据。需要默认给 Codex/Claude 消费侧提供 `localBrowserScreenshot` 时,使用 `--browser-annotation-screenshots-mode always`。
为了靠近 Codex browser runtime state,JSON 捕捉还会包含 `codexBrowserRuntimeState`,并把 `activeDesignChange` 镜像到 `codexBrowserPayload.localBrowserDesignChange.group`,对齐 Codex browser comment payload 的结构。CLI 和 MCP 可以通过 `--browser-annotation-editor-mode design`、`--browser-original-view-enabled`、`--browser-design-modifier-pressed`、`--browser-tweaks-editor-open`、`--browser-active-design-change-json '{"id":"design","declarations":[]}'` 设置这些 adapter 字段。JSON 捕捉也会包含 `codexBrowserRuntimeProtocol`,这是基于 Codex 522 证据的完整 `browser-sidebar-runtime-*` 事件协议适配,并镜像到 `codexBrowserPayload.localBrowserRuntimeProtocol`。
对于支持的前台浏览器应用,`--include-browser-dom` 会额外生成 `codexBrowserDOMIntegration`。它通过短超时的 Apple Events JavaScript 探测只读 Safari 和 Chromium 系浏览器页面,提取图片和可设计元素候选,再生成 Codex runtime event 形状的候选数据,例如 `browser-sidebar-runtime-open-editor`、`browser-sidebar-runtime-create-comment-at-point`、`browser-sidebar-runtime-update-anchor`、`browser-sidebar-runtime-open-design-editor`、`browser-sidebar-runtime-design-scrub-changed`、`browser-sidebar-runtime-image-drag-started`、`browser-sidebar-runtime-image-drag-ended`。`--browser-dom-install-bridge` 会再向 Codex 靠近一步:安装临时页面监听器和页面级 `window.codex_desktop` shim,提供 `sendMessageToHost` / `subscribeToHostMessages`,把真实 pointer、keyboard、drag、sync 和 shim message 事件记录到 `codexBrowserDOMIntegration.browserRuntimeBridgeEvents`。如果需要 browser-owned bridge,可以在浏览器里加载 unpacked helper:`~/.local/share/appshot/browser-extension/appshot-bridge`;其中 `page-bridge.js`、`content.js`、`background.js` 会把同一组 Codex-shaped messages 通过 `window.postMessage+extension-runtime` 转发。如果需要 Electron-owned bridge,并且你控制目标 Electron 应用,可以把 `~/.local/share/appshot/electron-preload/appshot-host-bridge/preload.cjs` 接进 `BrowserWindow.webPreferences.preload`,再从 `host.cjs` 注册 `installAppShotElectronHostBridge(ipcMain)`。如果页面能观察到 Codex 原生 preload host API,AppShot 会报告 `nativeCodexDesktopAvailable`、`codexHostBridgeAvailable`、`hostOwner: codex-electron-host`、`hostTransport: codex-electron-ipc`,并保持 `codexDesktopShimAvailable: false`。如果要做 Codex-side host integration 实验,先运行 `scripts/analyze_codex_electron_host_injection.mjs`,再在真实 Codex Electron host 注册 `ipcMain.handle(Ts)` 之前加载 `~/.local/share/appshot/codex-integration/appshot-codex-host-bridge/codex-host-adapter.cjs`,或用 `wrapCodexRuntimeMessageHandler` 包住现有 handler。analyzer 和 `scripts/patch_codex_electron_host_for_appshot.mjs` 会根据 IPC anchors 自动发现带 hash 的 `main-*.js`;真实可 patch 入口是 `--asar-root /path/to/unpacked/app.asar`,`--codex-app /Applications/Codex.app` 只用来检查该 app 是否已经暴露 unpacked asar。如果 Codex.app 只有 packed `Contents/Resources/app.asar`,运行 `scripts/materialize_codex_host_patch_for_appshot.mjs --codex-app /Applications/Codex.app --output-dir /tmp/codex-appshot-host --copy-app-bundle --pretty`;它会抽取 `app.asar` 和 `app.asar.unpacked`,patch 一个 copied asar directory,检查 patched JS 语法,并保留原始 Codex.app 不变。查看 `codexBrowserDOMIntegration.browserRuntimeBridge.codexDesktopShimAvailable`、`nativeCodexDesktopAvailable`、`codexHostBridgeAvailable`、`extensionHelperAvailable`、`electronHostBridgeAvailable`、`hostAPI`、`hostChannel`、`hostInboundChannel`、`hostOutboundChannel`、`ipcPattern`、`hostOwner`、`hostTransport` 可以确认当前 bridge;查看 `codexComputerUseStatus.hostBridge.codexHostIntegration` 可以确认 adapter artifact 是否已安装,以及私有 Codex webview host 是否真的接入。bridge 事件会合并进 `codexBrowserPayload.localBrowserRuntimeEvents`,并让当前标签页的 `localBrowserRuntimeProtocol.liveEventStreamAvailable` 变成 true。如果 Apple Events scripting 不可用、被权限挡住或超时,capture 会返回 `available: false` 和原因,不会卡住。这个 bridge 是页面级/browser-extension/Electron-preload/Codex-host instrumentation;standalone CLI/MCP 路径仍不能声称拥有 Codex 内部 Electron preload lifecycle。
对于 Electron 应用,可以显式加 `--include-electron-debugging`,也可以对 Electron 目标使用 `--include-browser-dom`。AppShot 会输出 `codexElectronRemoteDebugging`,包含扫描端口、DevTools targets、目标评分和可选的 CDP DOM/AX snapshot。这是靠近 Codex Electron 内容提取的公开 DevTools 路径,但仍依赖目标应用暴露 inspectable WebContents。
DOM capture 也会包含 `codexBrowserDOMIntegration.remoteDebuggingTarget`,对齐 Codex app-session 证据中对 `content shell remote debugging`、`inspectable webcontents` 和 localhost 调试端口 `9222` / `9229` 的识别。同一个分类会镜像到 `codexBrowserPayload.localBrowserCommentMetadata.browserDOMIntegration.remoteDebuggingTarget`。
`status` 和 `capture` 还会包含 `codexAppsStatus`,同一份 payload 也可以通过 `appshot codex-apps-status --pretty` 或 MCP `appshot_codex_apps_status` 获取。这一层对齐 Codex focused diff 里的 app-list readiness 形状:`codexAppsReady` 由权限 blockers 推导,`forceRefetchSupported` / `retryWhenNotReady` 说明重试路径,`tools` 列出 Claude Code 或 Codex 可调用的 AppShot MCP surface。
### 权限
完整 UI/文本树需要辅助功能权限,这是 AppShot 的主文本路径。截图和 OCR 需要屏幕录制权限。当应用没有通过 Accessibility 暴露正文时,OCR 才作为兜底从可见像素里恢复文字。在 macOS 上,权限归属于启动的应用身份,所以授权时请运行已安装的 `AppShot.app`,不要只跑 SwiftPM 里的 CLI 可执行文件。
全局快捷键默认开启:同时按下左 Option 和右 Option 可以捕获当前应用。你可以在 AppShot Settings 里关闭它。
快捷键捕捉会写入共享 recent cache。没有指定明确窗口目标时,CLI 和 MCP 默认读取这个缓存;如果需要直接抓当前窗口,加 `--ignore-cache`、`--no-cache` 或 `--fresh`。
如果 macOS 隐私设置里已经显示 AppShot 打开了,但 AppShot 仍然识别不到权限,先检查身份漂移:
```sh
scripts/diagnose_tcc_identity.sh
```
Xcode Debug 构建、已安装 release App、SwiftPM CLI 可能显示同一个名字,但代码签名身份不同。尤其是 ad-hoc 签名,重新构建后 `CDHash` 可能变化,TCC 会把它当成另一个应用。要让开发/发布权限稳定,请固定使用同一个已安装应用身份,或者通过 `APPSHOT_CODESIGN_IDENTITY` 使用稳定签名身份构建。
如果隐私设置里有旧记录导致状态错乱,可以先重置旧 TCC 记录,再打开同一个已安装应用重新授权:
```sh
tccutil reset Accessibility com.qppshot.AppShot
tccutil reset ScreenCapture com.qppshot.AppShot
open ~/Applications/AppShot.app
```
### 实现说明
首个版本使用公开 macOS API。后续窗口解析会严格对照本地 diff 出来的 Codex Mac App 证据继续补齐,不凭空猜实现。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器