别高兴太早:147 个 Raycast 命令里 33 个在 Tinycast 上跑不起来
别高兴太早147 个 Raycast 命令里 33 个在 Tinycast 上跑不起来【免费下载链接】tinycastTinycast — a tiny, fully native macOS launcher, hotkeys, and clipboard history.项目地址: https://gitcode.com/GitHub_Trending/ti/tinycast当一款开源启动器宣布原生运行 Raycast 扩展时第一批冲上去试用的人往往会得到一个让人心情复杂的结果扩展装上了、命令列出来了、一部分跑得又快又顺另一部分却直接甩给你一行报错。Tinycast 的官方文档给出了一个罕见的、可以自行复现的诚实数字在开发机上实测 37 个真实安装的扩展中32 个能完整启动并渲染147 个 view 命令中有 114 个正常运行——换句话说有整整 33 个命令是跑不起来的。这篇文章不打算替这 33 个失败辩护而是想把哪些能跑、哪些不能跑、为什么不能跑、升级前怎么预检这四件事讲清楚。结论全部来自仓库源码docs/features/extensions.md的实测数据、Scripts/raycast-runtime/的运行时实现你可以拿着这些方法在自己机器上复现不用信任何二手结论。数字是诚实的32/37 个扩展、114/147 个命令能跑这个数字不是营销话术而是刻在源码里的测试基线。在 docs/features/extensions.md 的Whats supported一节末尾原文写着Measured against the 37 extensions installed in a real Raycast on the development machine:32 extensions / 114 of 147 view commandsboot and render.更关键的是这句话的后半段Scripts/raycast-runtime/test.mjs dir和Scripts/run-tests.sh ext-test可以原样复现这个测量。也就是说兼容性边界不是开发者说能跑而是一套任何人可跑的测试资产。Tinycast 运行 Raycast 扩展的方式决定了这个边界的性质。它不内置 Electron、不依赖浏览器、也不需要 Node.js——扩展在 Raycast 里构建出来的是一个预编译 CommonJS bundleTinycast 用 macOS 自带的 JavaScriptCoreJSContext执行这个 bundle再通过自研的raycast/apishim 和 Node polyfill 补齐外部依赖最后把 React 渲染出的组件树翻译成原生界面。架构图在 docs/features/extensions.md 的How it works一节简化为command.js (esbuild output, deps inlined) │ require(raycast/api), require(react), require(node:fs), … ▼ RaycastRuntime.generated.js ← React 19 react-reconciler raycast/api shim polyfills │ render tree as JSON ▲ dispatch(handlerId, args) ▼ │ ExtensionRuntime (JavaScriptCore) │ host calls ▼ │ ExtensionManager ── ExtensionHostBridge ── Clipboard / storage / toasts / fetch / exec运行时源码全部放在 Scripts/raycast-runtime/src/api/components.js是组件面、api/system.js是剪贴板/存储/偏好等系统 API、node-shims.js是 Node 内建模块 shim、polyfills.js补 JavaScriptCore 缺失的全局对象含 WebAssembly 的 promise 形式修补。这套零二进制成本的路线换来的是极低的常驻资源占用——一个运行中的命令持有一个 JS 引擎仅此而已这也是 Tinycast 敢自称tiny的原因之一。需要泼一盆冷水的是32/37并不等于能跑的 32 个扩展体验完全一致。能启动和能完整交互之间还有大量细节差异后面会专门讲。哪些扩展能完整渲染UI 面和 Node 面都比想象中全先说好消息。Tinycast 对 Raycast 组件面的覆盖几乎是全组件级别的。以 Scripts/raycast-runtime/src/api/components.js 和官方文档的Whats supported为准列表与网格List含Item、Section、EmptyView、Item.Detail、Dropdown、Grid含磁贴布局、Dropdown详情与表单Detail含Metadata的Label/Link/TagList/Separator、Form全家桶TextField、PasswordField、TextArea、Checkbox、Dropdown、TagPicker、DatePicker、FilePicker动作系统ActionPanel含Section、Submenu与全部Action便捷变体CopyToClipboard、Paste、Open、Push、SubmitForm、PickDate等连废弃别名ActionPanel.Item、CopyToClipboardAction…都保留了因为线上 bundle 还在用API 面Clipboard、LocalStorage、Cache、environment、getPreferenceValues、showToast、showHUD、confirmAlert、open、getSelectedText、launchCommand、useNavigation等。Node 内建模块的覆盖同样深path、fs含fs/promises、流式createReadStream、os、child_processexec/spawn/同步四件套、crypto哈希/HMAC/PBKDF2/AES、zlib、http/httpsrequest/get/Agent、stream全家、url、buffer、events、timers以及WebAssembly和WebSocket全局。注意这不是简单的能用就行——文档里记录了三个被当作基准案例的硬核场景Homebrew 扩展用stream-chainstream-json构建 object-mode 管道解析包索引再走fetch→pipeThrough→pipeline→fs.createWriteStream全链路Zotero 扩展搜索数据库依赖 sql.js即WebAssembly——JavaScriptCore 的 promise 形式在私有队列上永不 settleScripts/raycast-runtime/src/polyfills.js 里用同步构造器包了一层才救活Home Assistant 扩展homeassistant.local的 mDNS 解析由 Swift 的getaddrinfo代为回答见 Scripts/raycast-runtime/src/dgram.js 的造假 UDP 包实现WebSocket 走URLSessionWebSocketTask。这些都是文档中白纸黑字、可在Scripts/raycast-runtime/test.mjs里逐步复现的完整渲染案例。33 个失败命令的共性都断在四个缺口上那 33 个跑不起来的命令不是随机散布在各扩展里的bug而是集中在四个明确的技术缺口上。这是好消息缺口是可枚举、可预判的而不是薛定谔的兼容性。缺口一Raycast 专属服务没有本地对应物。这是最大的一类。打开 Scripts/raycast-runtime/src/api/index.js你会看到一个清晰的取舍const AI { ...rejectingNamespace(AI, [ask]), Model: Object.freeze({}), Creativity: Object.freeze({}), }; const BrowserExtension rejectingNamespace(BrowserExtension, [getContent, getTabs]); const WindowManagement { DesktopType: nestedEnums.WindowManagement.DesktopType, ...rejectingNamespace(WindowManagement, [getWindowsOnActiveDesktop, getActiveWindow, setWindowBounds, getDesktops]), };rejectingNamespace的实现很直白命名空间照常导出import不报错但一旦调用就 reject 并给出明确原因。这意味着所有依赖AI.ask的 AI 类命令、依赖BrowserExtension读标签页的命令、依赖WindowManagement做窗口布局的命令全部落在 33 个失败名单里。注意一个微妙点Tinycast 自己内置了 34 个原生窗口管理命令见 docs/features/window-management.md但那是 Swift 直调 macOS Accessibility 的实现跟运行 Raycast 的窗口管理扩展是两条完全不同的路——后者在 Tinycast 的扩展沙箱里就是调用WindowManagement.getWindowsOnActiveDesktop()并收到not supported。缺口二裸 socket 与流式 HTTP。Scripts/raycast-runtime/src/node-shims.js 顶部维护了一张UNSUPPORTED_EXPORTS表net、tls、dns、vm、http2、domain等模块resolve but throw on use——bundle 只是require它们能正常加载一旦真的用就抛错。文档的 gap 表里说得很清楚net/tls没有任何 bridge 原始 sockethttp.request是一次性返回整个 body所以Server-Sent EventsSSE、网络级进度、socket 背压全部不可达。依赖 SSE 的实时流类扩展、依赖tls做自签名证书客户端校验的扩展都会在这一类里阵亡。fetch的AbortSignal倒是完整的但信号不跨 bridge——调用方能拿到AbortError底层的URLSessionTask还是会跑完所以超时只约束调用方不约束网络。缺口三交互式子进程。spawn的 stdout/stderr 是流式的但 stdin 只在子进程启动的同一 tick 发送一次之后的stdin.write会被丢弃。任何需要启动一个交互式 CLI 并持续喂输入的命令REPL 类、密码交互类都会卡在这一条。缺口四tools/入口未暴露。Raycast 生态里 AI 工具扩展声明tools/目录、被 Raycast 的 AI 功能调用在 Tinycast 里完全不上层文档原话是 Not surfaced。把这些缺口套回 33 这个数字就能解释为什么它不是一个常数你装了什么扩展就有对应的失败命令但失败的模式只有这几种。更重要的设计取向在 Scripts/raycast-runtime/src/api/system.js 的unsupported()里export function unsupported(what) { return Promise.reject( new Error(${what} is not supported in Tinycast extensions yet. See docs/extensions.md.), ); }所有缺口都是显式报错而不是静默降级。一个命令不会假装跑起来了但结果不对它会直接告诉你断在哪。这在工程上是兼容层最难能可贵的性质——可验证、可诊断用户不会在不知情的情况下拿到错误数据。别被能跑骗了三个最容易踩的隐形坑33 个明确失败之外114 个能跑的命令里还藏着三类只有真上手才会撞见的问题它们比显式报错更难排查。坑一空参数有语义。文档里记录了一个很精彩的案例Coffee 扩展的 Caffeinate for… 命令曾执行caffeinate -t NaN然后瞬间退出。根因是 Raycast 的契约——每个声明的 argument 都会被发送未填写时是空字符串而不是 undefined。Number()是0Number(undefined)是NaNTinycast 忠实实现了空串契约ExtensionCommand.completeArguments反而是那些习惯性省略空参数的扩展自己写出了 bug。这类问题从 Tinycast/Features/Extensions/Model/ExtensionManifest.swift 的参数解析一路牵扯到具体命令的逻辑是兼容性之外最常见的真实故障源。坑二JavaScriptCore 不是 V8。运行时两次栽过的差异都被记在文档里Error.stack只含帧、不重复消息MessageChannel缺失导致 React scheduler 回退到setTimeout。还有react-dom被显式置为调用即抛错Scripts/raycast-runtime/src/index.js因为 Tinycast 渲染扩展不走 DOM。依赖这些环境细节的扩展即使逻辑正确也可能在 JSC 下表现异常。坑三OAuth 与第三方代码信任。社区里流传的OAuth PKCE 全链路实现需要打一个问号检索整个 Tinycast/Features/Extensions/ 的 Swift 源码扩展宿主侧ExtensionHostBridge的 dispatch 面只有 clipboard / storage / cache / window / feedback / system / fetch / websocket / dns / proc没有任何 OAuth 流程OAuth PKCE 基础设施MCPOAuth*.swift一整套属于 MCP 模块服务于 AI 聊天连接工具服务器与 Raycast 扩展的授权流程无关。一个在 Raycast 里通过 OAuth 登录的扩展迁移到 Tinycast 后那条登录路径是不存在的。此外扩展开关本身就是运行第三方代码的同意首次开启需要确认且不会跟着设置备份自动迁移——这是刻在 docs/features/extensions.md 的 Off means off 不变量。升级前用兼容性清单预检工作流所以正确的姿势不是装完再撞而是在把工作流迁移过来之前做一次预检。Tinycast 仓库提供了一条完整的验证链路从上到下越来越接近真实环境第一步看 manifest过滤已知缺口。打开每个扩展的package.json按命令逐个检查 mode 和代码里用到的 API。凡是在源码里能搜到AI.、WindowManagement.、BrowserExtension.、net.、tls.、http2.调用的命令直接判为迁移后有风险。这类静态检查不需要跑任何代码。第二步JS 层渲染树验证。对任意一个已构建的扩展 bundle运行node Scripts/raycast-runtime/test.mjs ~/.config/raycast/extensions/uuid [command]这个 harnessScripts/raycast-runtime/test.mjs在一个裸vm上下文里跑真实运行时打印 Swift 端会收到的完整渲染树任何unsupported调用都会以 failure 形式暴露出来。它还能用EXT_TEST_PREFS{version:v8}模拟用户在设置里配的偏好值——很多扩展的代码路径被一个没有 manifest 默认值的偏好挡着不喂这个值根本走不到。第三步真实引擎验证。JS 层通过不代表 JavaScriptCore 下也通过用Scripts/run-tests.sh ext-testext-test编译的是真实引擎源码没有第二份拷贝需要同步EXT_TEST_VERBOSE1能看到扩展自己的console.error。对于装完第一次能跑、第二次卡在 Starting…这类诡异问题文档还专门解释过那是复用 JSContext 导致 React scheduler 的 timer 被连带取消的历史 bug现在的修复是每命令一 context跑完即弃。第四步对着 gap 表做兜底方案。预检出失败的命令先别急着弃用整个扩展——Tinycast 的定位是启动器本身带原生功能大量 Raycast 工作流在它身上有原生替代窗口布局用内置的 34 个原生窗口命令系统操作用内置的 31 个系统级命令文件搜索走 Spotlight 白名单式 scopes见 docs/features/file-search.md。如果某个第三方扩展的独有能力正好踩在 AI / 浏览器 / 窗口管理的缺口中那要么接受这部分暂时没有要么把它留在 Raycast 里做双轨。最后记住一个时间维度这 33 个缺口不是静态的。运行时源码就摆在 Scripts/raycast-runtime/src/README级的构建命令写在文档末尾node gen-enums.mjs→node build.mjs→ 提交Resources/RaycastRuntime.generated.js。今天的 33 个失败是明天某个 commit 就能缩小的数字——这正是兼容性有明确边界、边界可测量比宣称完全兼容更值得信任的地方。别高兴太早147 个 Raycast 命令里 33 个在 Tinycast 上跑不起来当一款开源启动器宣布原生运行 Raycast 扩展时第一批冲上去试用的人往往会得到一个让人心情复杂的结果扩展装上了、命令列出来了、一部分跑得又快又顺另一部分却直接甩给你一行报错。Tinycast 的官方文档给出了一个罕见的、可以自行复现的诚实数字在开发机上实测 37 个真实安装的扩展中32 个能完整启动并渲染147 个 view 命令中有 114 个正常运行——换句话说有整整 33 个命令是跑不起来的。这篇文章不打算替这 33 个失败辩护而是想把哪些能跑、哪些不能跑、为什么不能跑、升级前怎么预检这四件事讲清楚。结论全部来自仓库源码docs/features/extensions.md 的实测数据、Scripts/raycast-runtime/ 的运行时实现你可以拿着这些方法在自己机器上复现不用信任何二手结论。数字是诚实的32/37 个扩展、114/147 个命令能跑这个数字不是营销话术而是刻在源码里的测试基线。在 docs/features/extensions.md 的Whats supported一节末尾原文写着Measured against the 37 extensions installed in a real Raycast on the development machine:32 extensions / 114 of 147 view commandsboot and render.更关键的是这句话的后半段Scripts/raycast-runtime/test.mjs dir和Scripts/run-tests.sh ext-test可以原样复现这个测量。也就是说兼容性边界不是开发者说能跑而是一套任何人可跑的测试资产。Tinycast 运行 Raycast 扩展的方式决定了这个边界的性质。它不内置 Electron、不依赖浏览器、也不需要 Node.js——扩展在 Raycast 里构建出来的是一个预编译 CommonJS bundleTinycast 用 macOS 自带的 JavaScriptCoreJSContext执行这个 bundle再通过自研的raycast/apishim 和 Node polyfill 补齐外部依赖最后把 React 渲染出的组件树翻译成原生界面。架构图在 docs/features/extensions.md 的How it works一节简化为command.js (esbuild output, deps inlined) │ require(raycast/api), require(react), require(node:fs), … ▼ RaycastRuntime.generated.js ← React 19 react-reconciler raycast/api shim polyfills │ render tree as JSON ▲ dispatch(handlerId, args) ▼ │ ExtensionRuntime (JavaScriptCore) │ host calls ▼ │ ExtensionManager ── ExtensionHostBridge ── Clipboard / storage / toasts / fetch / exec运行时源码全部放在 Scripts/raycast-runtime/src/api/components.js是组件面、api/system.js是剪贴板/存储/偏好等系统 API、node-shims.js是 Node 内建模块 shim、polyfills.js补 JavaScriptCore 缺失的全局对象含 WebAssembly 的 promise 形式修补。这套零二进制成本的路线换来的是极低的常驻资源占用——一个运行中的命令持有一个 JS 引擎仅此而已这也是 Tinycast 敢自称tiny的原因之一。需要泼一盆冷水的是32/37并不等于能跑的 32 个扩展体验完全一致。能启动和能完整交互之间还有大量细节差异后面会专门讲。哪些扩展能完整渲染UI 面和 Node 面都比想象中全先说好消息。Tinycast 对 Raycast 组件面的覆盖几乎是全组件级别的。以 Scripts/raycast-runtime/src/api/components.js 和官方文档的Whats supported为准列表与网格List含Item、Section、EmptyView、Item.Detail、Dropdown、Grid含磁贴布局、Dropdown详情与表单Detail含Metadata的Label/Link/TagList/Separator、Form全家桶TextField、PasswordField、TextArea、Checkbox、Dropdown、TagPicker、DatePicker、FilePicker动作系统ActionPanel含Section、Submenu与全部Action便捷变体CopyToClipboard、Paste、Open、Push、SubmitForm、PickDate等连废弃别名ActionPanel.Item、CopyToClipboardAction…都保留了因为线上 bundle 还在用API 面Clipboard、LocalStorage、Cache、environment、getPreferenceValues、showToast、showHUD、confirmAlert、open、getSelectedText、launchCommand、useNavigation等。Node 内建模块的覆盖同样深path、fs含fs/promises、流式createReadStream、os、child_processexec/spawn/同步四件套、crypto哈希/HMAC/PBKDF2/AES、zlib、http/httpsrequest/get/Agent、stream全家、url、buffer、events、timers以及WebAssembly和WebSocket全局。注意这不是简单的能用就行——文档里记录了三个被当作基准案例的硬核场景Homebrew 扩展用stream-chainstream-json构建 object-mode 管道解析包索引再走fetch→pipeThrough→pipeline→fs.createWriteStream全链路Zotero 扩展搜索数据库依赖 sql.js即WebAssembly——JavaScriptCore 的 promise 形式在私有队列上永不 settleScripts/raycast-runtime/src/polyfills.js 里用同步构造器包了一层才救活Home Assistant 扩展homeassistant.local的 mDNS 解析由 Swift 的getaddrinfo代为回答见 Scripts/raycast-runtime/src/dgram.js 的造假 UDP 包实现WebSocket 走URLSessionWebSocketTask。这些都是文档中白纸黑字、可在Scripts/raycast-runtime/test.mjs里逐步复现的完整渲染案例。33 个失败命令的共性都断在四个缺口上那 33 个跑不起来的命令不是随机散布在各扩展里的bug而是集中在四个明确的技术缺口上。这是好消息缺口是可枚举、可预判的而不是薛定谔的兼容性。缺口一Raycast 专属服务没有本地对应物。这是最大的一类。打开 Scripts/raycast-runtime/src/api/index.js你会看到一个清晰的取舍const AI { ...rejectingNamespace(AI, [ask]), Model: Object.freeze({}), Creativity: Object.freeze({}), }; const BrowserExtension rejectingNamespace(BrowserExtension, [getContent, getTabs]); const WindowManagement { DesktopType: nestedEnums.WindowManagement.DesktopType, ...rejectingNamespace(WindowManagement, [getWindowsOnActiveDesktop, getActiveWindow, setWindowBounds, getDesktops]), };rejectingNamespace的实现很直白命名空间照常导出import不报错但一旦调用就 reject 并给出明确原因。这意味着所有依赖AI.ask的 AI 类命令、依赖BrowserExtension读标签页的命令、依赖WindowManagement做窗口布局的命令全部落在 33 个失败名单里。注意一个微妙点Tinycast 自己内置了 34 个原生窗口管理命令见 docs/features/window-management.md但那是 Swift 直调 macOS Accessibility 的实现跟运行 Raycast 的窗口管理扩展是两条完全不同的路——后者在 Tinycast 的扩展沙箱里就是调用WindowManagement.getWindowsOnActiveDesktop()并收到not supported。缺口二裸 socket 与流式 HTTP。Scripts/raycast-runtime/src/node-shims.js 顶部维护了一张UNSUPPORTED_EXPORTS表net、tls、dns、vm、http2、domain等模块resolve but throw on use——bundle 只是require它们能正常加载一旦真的用就抛错。文档的 gap 表里说得很清楚net/tls没有任何 bridge 原始 sockethttp.request是一次性返回整个 body所以Server-Sent EventsSSE、网络级进度、socket 背压全部不可达。依赖 SSE 的实时流类扩展、依赖tls做自签名证书客户端校验的扩展都会在这一类里阵亡。fetch的AbortSignal倒是完整的但信号不跨 bridge——调用方能拿到AbortError底层的URLSessionTask还是会跑完所以超时只约束调用方不约束网络。缺口三交互式子进程。spawn的 stdout/stderr 是流式的但 stdin 只在子进程启动的同一 tick 发送一次之后的stdin.write会被丢弃。任何需要启动一个交互式 CLI 并持续喂输入的命令REPL 类、密码交互类都会卡在这一条。缺口四tools/入口未暴露。Raycast 生态里 AI 工具扩展声明tools/目录、被 Raycast 的 AI 功能调用在 Tinycast 里完全不上层文档原话是 Not surfaced。把这些缺口套回 33 这个数字就能解释为什么它不是一个常数你装了什么扩展就有对应的失败命令但失败的模式只有这几种。更重要的设计取向在 Scripts/raycast-runtime/src/api/system.js 的unsupported()里export function unsupported(what) { return Promise.reject( new Error(${what} is not supported in Tinycast extensions yet. See docs/extensions.md.), ); }所有缺口都是显式报错而不是静默降级。一个命令不会假装跑起来了但结果不对它会直接告诉你断在哪。这在工程上是兼容层最难能可贵的性质——可验证、可诊断用户不会在不知情的情况下拿到错误数据。别被能跑骗了三个最容易踩的隐形坑33 个明确失败之外114 个能跑的命令里还藏着三类只有真上手才会撞见的问题它们比显式报错更难排查。坑一空参数有语义。文档里记录了一个很精彩的案例Coffee 扩展的 Caffeinate for… 命令曾执行caffeinate -t NaN然后瞬间退出。根因是 Raycast 的契约——每个声明的 argument 都会被发送未填写时是空字符串而不是 undefined。Number()是0Number(undefined)是NaNTinycast 忠实实现了空串契约ExtensionCommand.completeArguments反而是那些习惯性省略空参数的扩展自己写出了 bug。这类问题从 Tinycast/Features/Extensions/Model/ExtensionManifest.swift 的参数解析一路牵扯到具体命令的逻辑是兼容性之外最常见的真实故障源。坑二JavaScriptCore 不是 V8。运行时两次栽过的差异都被记在文档里Error.stack只含帧、不重复消息MessageChannel缺失导致 React scheduler 回退到setTimeout。还有react-dom被显式置为调用即抛错Scripts/raycast-runtime/src/index.js因为 Tinycast 渲染扩展不走 DOM。依赖这些环境细节的扩展即使逻辑正确也可能在 JSC 下表现异常。坑三OAuth 与第三方代码信任。社区里流传的OAuth PKCE 全链路实现需要打一个问号检索整个 Tinycast/Features/Extensions/ 的 Swift 源码扩展宿主侧ExtensionHostBridge的 dispatch 面只有 clipboard / storage / cache / window / feedback / system / fetch / websocket / dns / proc没有任何 OAuth 流程OAuth PKCE 基础设施MCPOAuth*.swift一整套属于 MCP 模块服务于 AI 聊天连接工具服务器与 Raycast 扩展的授权流程无关。一个在 Raycast 里通过 OAuth 登录的扩展迁移到 Tinycast 后那条登录路径是不存在的。此外扩展开关本身就是运行第三方代码的同意首次开启需要确认且不会跟着设置备份自动迁移——这是刻在 docs/features/extensions.md 的 Off means off 不变量。升级前用兼容性清单预检工作流所以正确的姿势不是装完再撞而是在把工作流迁移过来之前做一次预检。Tinycast 仓库提供了一条完整的验证链路从上到下越来越接近真实环境第一步看 manifest过滤已知缺口。打开每个扩展的package.json按命令逐个检查 mode 和代码里用到的 API。凡是在源码里能搜到AI.、WindowManagement.、BrowserExtension.、net.、tls.、http2.调用的命令直接判为迁移后有风险。这类静态检查不需要跑任何代码。第二步JS 层渲染树验证。对任意一个已构建的扩展 bundle运行node Scripts/raycast-runtime/test.mjs ~/.config/raycast/extensions/uuid [command]这个 harnessScripts/raycast-runtime/test.mjs在一个裸vm上下文里跑真实运行时打印 Swift 端会收到的完整渲染树任何unsupported调用都会以 failure 形式暴露出来。它还能用EXT_TEST_PREFS{version:v8}模拟用户在设置里配的偏好值——很多扩展的代码路径被一个没有 manifest 默认值的偏好挡着不喂这个值根本走不到。第三步真实引擎验证。JS 层通过不代表 JavaScriptCore 下也通过用Scripts/run-tests.sh ext-testext-test编译的是真实引擎源码没有第二份拷贝需要同步EXT_TEST_VERBOSE1能看到扩展自己的console.error。对于装完第一次能跑、第二次卡在 Starting…这类诡异问题文档还专门解释过那是复用 JSContext 导致 React scheduler 的 timer 被连带取消的历史 bug现在的修复是每命令一 context跑完即弃。第四步对着 gap 表做兜底方案。预检出失败的命令先别急着弃用整个扩展——Tinycast 的定位是启动器本身带原生功能大量 Raycast 工作流在它身上有原生替代窗口布局用内置的 34 个原生窗口命令系统操作用内置的 31 个系统级命令文件搜索走 Spotlight 白名单式 scopes见 docs/features/file-search.md。如果某个第三方扩展的独有能力正好踩在 AI / 浏览器 / 窗口管理的缺口中那要么接受这部分暂时没有要么把它留在 Raycast 里做双轨。最后记住一个时间维度这 33 个缺口不是静态的。运行时源码就摆在 Scripts/raycast-runtime/src/构建命令写在文档末尾node gen-enums.mjs→node build.mjs→ 提交Resources/RaycastRuntime.generated.js。今天的 33 个失败是明天某个 commit 就能缩小的数字——这正是兼容性有明确边界、边界可测量比宣称完全兼容更值得信任的地方。【免费下载链接】tinycastTinycast — a tiny, fully native macOS launcher, hotkeys, and clipboard history.项目地址: https://gitcode.com/GitHub_Trending/ti/tinycast创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考