bo2themax/Siriously

GitHub: bo2themax/Siriously

该项目修复了在 macOS 27 上启用全新 Siri 后 Apple Intelligence 写作工具弹窗消失的问题,允许用户在不关闭 Siri 的情况下继续使用原生校对和改写等功能。

Stars: 0 | Forks: 0

# Siriously — 在启用全新 Siri 后,恢复 macOS 27 上的 Writing Tools **你是否在开启全新 Siri 后发现 Apple Intelligence 的 Writing Tools 不见了?** 当你在 macOS 27 上启用全新的 Siri / Apple Intelligence 助手("NewSiri")时,**Writing Tools** 弹窗(Proofread、Rewrite、Summarize 以及语气工具)将会消失:菜单项不复存在,且 `Edit → Writing Tools` / 右键点击**只会直接打开 Siri**。**Siriously 可恢复经典的 Writing Tools 弹窗**,让你能够继续对选中的文本使用 Proofread 和 Rewrite —— **而无需禁用全新的 Siri**。 关键词:_macOS 26–27 上 Writing Tools 缺失 / 消失 / 不显示 / 灰色不可用,启用 Siri 后 Apple Intelligence Writing Tools 消失,如何恢复 Writing Tools,恢复 Proofread 和 Rewrite,NewSiri,macOS Tahoe。_ 它作为一个基于工具的 macOS **服务(Services)**代理运行:在任意应用中选择文本 → **右键点击 → 服务 → Proofread / Rewrite / Siriously** → 真正的 Writing Tools UI 将在你的选区上运行,并将结果直接原地写回。 ## 要求 Siriously 仅在**支持 Apple Intelligence 且已启用全新 Siri / Apple Intelligence 助手("NewSiri")**的 Mac 上有效: - **支持并已设置 Apple Intelligence** — Apple 芯片、受支持的区域/语言,以及已下载的设备端模型。Writing Tools _本质上就是_ Apple Intelligence;若缺少它,`WritingToolsViewService.xpc` 背后的引擎将无法响应请求,Siriously 也无法产生任何结果。 - **已启用 NewSiri** — 这正是问题的关键所在:启用 NewSiri 会移除/劫持内置的 Writing Tools 入口,而 Siriously 能将弹窗重新带回。在_没有_ NewSiri 的 Mac 上,系统自带的 Writing Tools 依然有效,因此你不需要此工具。 - **macOS 27**(在 27.0,build 26A5368g,arm64 上构建并验证)— 它依赖于系统更新可能会更改的私有框架细节。 - **辅助功能权限(Accessibility permission)**(用于读取选中文本并将结果原地写回)。 如果设备上未提供/未启用 Apple Intelligence,Siriously 只会呈现一个空白/无功能的弹窗 —— 因为没有可供其交互的底层引擎。 ## 为什么在全新 Siri 下 Writing Tools 会消失(macOS 27.0,build 26A5368g,arm64) - 在启用 NewSiri 的情况下,Writing Tools 框架依然完整存在且功能正常:`/System/Library/PrivateFrameworks/WritingTools.framework`(`WTSession`)以及 `WritingToolsUI.framework`(`WTWritingToolsViewController`、`WTWritingToolsConfiguration`、`WTWritingToolsPanel`、进程外的 `WritingToolsViewService.xpc` 等)。 - `+[WTWritingToolsViewController isAvailable] == isEnabled == 1` 且 `isEnhancedSiriAvailable == 1` —— 即底层引擎仍然在处理请求;NewSiri 只是更改了**客户端入口点**: - 公开的 `-[NSResponder showWritingTools:]` action 被**劫持 → 转而打开 Siri**。 - 由 `NSWritingToolsCoordinator` 提供的浮窗/菜单项被隐藏。 - 因此,我们直接驱动**私有**类 `WTWritingToolsViewController`,它仍然会与拥有相应权限的 `WritingToolsViewService.xpc` 通信并返回真实结果。 ## 工作原理 1. **触发(Trigger)** — 一个 macOS _服务(Service)_(`NSApp.servicesProvider`),每个工具对应一个菜单项。 2. **捕获(Capture)** — 调用时,通过**辅助功能 API(Accessibility API)**(`AXContext`)读取宿主应用的聚焦元素、选中文本以及选区在屏幕上的矩形区域。 3. **呈现(Present)** — 将文本填入一个进程内的 `NSTextView`(作为 WT 的_客户端_,保持透明/离屏),并在一个 `NSPopover` 中呈现 `WTWritingToolsViewController`。该弹窗的锚点是一个**覆盖在宿主选区上**的透明悬浮窗口(弹窗的锚点视图与 WT 的客户端视图是独立的配置字段,因此当 WT 在我们的视图上操作时,弹窗会悬浮在宿主应用上方)。 4. **写回(Write back)** — 一旦用户接受结果(通过 `-[WTWritingToolsRemoteViewController replaceSelectionWithText:]` 进行挂钩拦截),立即恢复原始选区范围,并通过 AX(`AXUIElementSetAttributeValue`)设置宿主元素的选中文本,随后迅速重新激活宿主应用,以便用户继续输入。对于 AX 无法写入的应用(如 VSCode 等 Electron/Qt 应用 —— 没有聚焦的 AX 元素),则会弹出一个带有结果和**复制(Copy)**按钮的警告框。 已处理的可靠性细节:视图服务会被**预热**,且呈现过程**受限于预热完成**(不会出现空白弹窗);在写回前会**恢复原始的选区范围**(修复了“追加而非替换”的问题);弹窗使用 `.applicationDefined`(进程外的视图在首次点击时会导致 `.transient` 弹窗关闭);**`WTWritingToolsViewController` 被设为弹窗的 delegate**,因此在菜单中选择某个工具时(这会触发一个_临时的_ `closePopoverTransientlyToShowTool:` 关闭动作),视图控制器(VC)会**重新打开**弹窗并显示该工具,而不是直接销毁 —— 会话结束通过轮询来检测(如果弹窗保持关闭的时间超过了临时“关闭→重开”间隔的宽限期,即判定为结束)。 ## 安装 ``` ./install.sh # build → /Applications, register Services ./install.sh --resident # also install a login LaunchAgent (keeps the WT service warm) ``` 接着: 1. **系统设置 → 隐私与安全性 → 辅助功能** → 启用 _Siriously_(这是读取选区并原地写回结果所必需的)。 2. **系统设置 → 键盘 → 键盘快捷键 → 服务 → 文本** → 勾选你想要的 Siriously 项目。所有工具都作为独立项提供,因此只需挑选你实际使用的几个即可 —— 例如 **Proofread** 和 **Siriously**(完整菜单): 在系统设置 → 键盘快捷键 → 服务 → 文本 中启用 Siriously 项目 使用方法:选中文本 → **右键点击 → 服务 → Proofread / Rewrite / Siriously**,或者使用应用菜单中的**服务**子菜单:

Siriously items in the right-click Services menu on selected text   Siriously items in an app's Services submenu

卸载:`./uninstall.sh` ## 构建与签名 `build-app.sh` 会按以下顺序选择签名身份: 1. **`WT_SIGN_IDENTITY`** 环境变量 — 用于分发的显式身份(例如 `Developer ID Application: …`);应用会使用**硬化运行时**进行签名,以便进行公证。 2. **`WTReviveDev`** — 一个稳定的本地自签名身份(推荐用于开发):辅助功能/TCC 授权随后将**在多次重新构建后保持有效**,而不是每次重置。只需创建一次: openssl req -x509 -newkey rsa:2048 -keyout k.pem -out c.pem -days 3650 -nodes \ -subj "/CN=WTReviveDev" -addext "extendedKeyUsage=critical,codeSigning" \ -addext "basicConstraints=critical,CA:false" openssl pkcs12 -export -legacy -inkey k.pem -in c.pem -out id.p12 -passout pass:wt -name WTReviveDev security import id.p12 -k ~/Library/Keychains/login.keychain-db -P wt -T /usr/bin/codesign rm k.pem c.pem id.p12 3. **ad-hoc(临时签名)** — 其他任何情况(每次重新构建后 AX 授权都会重置)。 ### GitHub Actions (`.github/workflows/build.yml`) 每次推送/PR 都会构建 `.app`(**默认为 ad-hoc 签名** — 无需 secrets),并将其作为工作流工件上传;推送 `v*` 标签时还会将其附加到 Release 中。自定义签名和公证需通过仓库的 **secrets** 按需开启: | secret | 用途 | | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | `MACOS_CERTIFICATE_P12_BASE64` / `MACOS_CERTIFICATE_PASSWORD` | Developer ID 证书(base64 编码的 `.p12` 及其导出密码) → 使用硬化运行时签名 | | `MACOS_SIGN_IDENTITY` | 可选的精确身份名称(若未提供,则从证书自动检测) | | `AC_API_KEY_P8_BASE64` / `AC_API_KEY_ID` / `AC_API_ISSUER_ID` | App Store Connect API 密钥 → 磕绊并装订 | 如果未设置任何 secrets,工作流依然会生成一个可用的 ad-hoc 构建版本。注意:运行环境必须自带 Writing Tools 私有框架(macOS 15.1+);待可用后,请使用 macOS 26/Xcode 26 运行环境以获取 Icon Composer 图标和真正的 macOS 27 SDK。 ## 工具 / `requestedTool` 枚举 经测试确认: | 值 | 工具 | | ------- | ------------------------------------ | | 0 | **Menu**(完整工具列表) | | 1 | **Proofread** | | 2 | **Rewrite** | | 11 | **Friendly**(语气) | | 12 | **Professional**(语气) | | 13 | **Concise**(语气) | | 21 | **Summary** | | 22 | **List** | | 23 | **Table** | | 3/4 | Proofread 变体 / 无效 | | Compose | 尚未映射(约30秒,仍在寻找) | 作为服务项暴露出来:**Proofread、Rewrite、Friendly、Professional、Concise、Summary、List、Table**(直接访问),加上 **Siriously**(0 — 完整菜单)。 **“Siriously”项是完整的解决方案** — 它会显示完整的工具列表,并且由于 VC 是弹窗的代理,**在其中选择任何工具都能正常工作**(临时的关闭→重新打开动作会进行分发)。其他项目则是特定工具的快速访问快捷方式。 ### 添加更多直接(快捷访问)项 如果你希望将另一个工具作为单独的服务项(而不是通过菜单访问):运行 `./explore.sh`(一个带有 **T0…T39** 按钮的窗口),点击每个按钮查看哪个值映射到哪个工具,然后在 `Sources/main.swift` 中添加一个调用 `run(pb, tool: N)` 的 `@objc func`,并在 `build-app.sh` 中添加相应的 `NSServices` 条目。 ## 文件 | 文件 | 用途 | | ----------------------------------- | -------------------------------------------------------------------- | | `Sources/main.swift` | 服务代理(AX 捕获、呈现器、写回) | | `WritingToolsPrivate.h` | 桥接头文件 — 私有 WT 接口(源自运行时内省) | | `build-app.sh` | 构建 + 签名 + 注册 `.app` | | `install.sh` / `uninstall.sh` | 安装到 /Applications(+ 可选的 LaunchAgent) | | `explore.sh` / `explore.swift` | 工具映射辅助工具(T0…T39 按钮) | | `dump.mm` / `dump2.mm` / `dump3.mm` | 研究产物:运行时类/选择器/枚举转储 | | `Siriously.icon` | Icon Composer 源文件(在 `build-app.sh` 中由 `actool` 编译) | | `FINDINGS.md` | 逆向工程知识库(私有 API、流程、陷阱) | ## 限制 - **宿主应用中没有内联的重写动画。** WT 将结果渲染到_我们_进程内的文本视图中;我们通过 AX 将最终结果桥接回宿主应用。动画/预览发生在我们(隐藏)的视图中,因此宿主应用只会接收到最终的文本。 - **临时实例。** macOS 会按需启动服务提供者,并在任务结束后让其退出;使用 `--resident` 可以保持一个活跃实例,以避免冷启动延迟。 - **依赖于 AX。** 原生应用(如 TextEdit/Notes/Safari/...)可通过 AX 原地替换文本。不支持 AX 文本操作的应用(如 VSCode/Electron)无法被写入 —— 结果会通过带有“复制”按钮的警告框提供,且弹窗会锚定在聚焦窗口的中心(无法获取选区矩形范围)。服务项在注册时配置了广泛的发送类型且无返回类型,因此它们会在任何文本选区(无论是否可编辑)中出现。 - **私有 API / 受限于系统版本。** 选择器是在 26A368g 版本中提取的;系统更新可能会改变它们。重新运行 `dump.mm`/`dump2.mm` 以进行刷新。 ## 许可证 [MIT](LICENSE)。 ## 免责声明 Siriously 是一个驱动 Apple **私有**框架的非官方黑科技工具。它**不隶属于 Apple,也未获得 Apple 的认可或支持**,且 "Apple Intelligence"、"Siri" 和 "Writing Tools" 是 Apple Inc. 的商标。由于它依赖于未公开的私有 API,任何 macOS 更新都可能导致其失效,且无法在 Mac App Store 上架。使用风险需自负。按“原样”提供,不提供任何保证。
标签:Apple Intelligence, 快捷服务, 系统修复, 系统工具, 辅助功能