- 桌面应用
【免费下载链接】tinycast
Tinycast — a tiny, fully native macOS launcher, hotkeys, and clipboard history.
导读
Tinycast 是一款完全原生的 macOS 启动器(launcher),同时内置热键与剪贴板历史功能,并原生运行 Raycast 扩展。本文围绕Settings → Extensions → Install这一入口,系统讲解 Tinycast 安装扩展的三种途径(注册表搜索、从 Raycast 导入、从本地文件夹添加),深入剖析其背后的双注册表模型(预编译 Store 与 GitHub 源码仓库)、包管理器自动探测与 PATH 搜索机制,以及存储与卸载的完整生命周期,帮助你在不依赖 Node 工具链的情况下完成绝大多数扩展的安装,并理解源码安装时的构建细节。
三种安装途径概览
在Settings → Extensions → Install面板中,Tinycast 提供了三种互补的安装方式,它们的核心差异在于"扩展以什么形态进入你的 Mac":
| 途径 | 形态 | 是否需要工具链 |
|---|---|---|
| Search Registries(搜索注册表) | 从已启用的注册表在线获取,安装即用 | 取决于所选注册表(Store 不需要,GitHub 源码需要) |
| Import from Raycast(从 Raycast 导入) | 直接复制本机 Raycast 已构建好的扩展 | 完全不需要 |
| Add from folder(从文件夹添加) | 从含 manifest 与构建产物的本地文件夹安装 | 不需要(但要求文件夹内是已构建产物) |
其中"从 Raycast 导入"是最省心的一条路径:不构建任何东西,不需要 Node、不需要包管理器、不需要网络,因为扩展早已构建完成,只需原样搬移。这一点在源码中有直接印证:导入逻辑(Tinycast/Features/Extensions/Service/ExtensionCatalog.swift中的importableFromRaycast())只扫描扩展目录中的package.jsonmanifest 与已存在的<command>.js构建产物,并对不满足条件的半安装或纯源码目录直接跳过。
搜索注册表(Search Registries)
搜索注册表会同时查询每一个已启用的注册表,并从任意命中者中安装。这是日常使用中最常见的安装方式。
搜索请求在客户端侧是并行发起的:ExtensionStoreClient.search(_:in:)(Tinycast/Features/Extensions/Service/ExtensionStoreClient.swift)使用withTaskGroup同时向所有启用的注册表发起查询,但结果按注册表配置顺序而非完成顺序返回,保证列表不会在多次搜索之间重新洗牌;单个注册表失败也不会拖垮其他注册表的结果。
值得注意的细节:GitHub 注册表本身没有"搜索"能力,因此 Tinycast 会在本地对仓库内的扩展文件夹名做模糊匹配(FuzzyMatch)排名,只读取排名最高的前 12 个候选(githubCandidateLimit)逐一拉取package.json摘要,避免浪费请求配额。Store 则走其官网搜索所使用的端点。
从 Raycast 导入(Import from Raycast)
该功能把你在这台 Mac上已经通过 Raycast 装好的扩展直接复制进来,无需任何构建与联网。
- Tinycast 会同时检查
~/.config/raycast与~/.config/raycast-x两个目录(ExtensionCatalog.raycastExtensionRoots()明确枚举了这两个路径,其中raycast-x对应 Beta v2 通道);当一个扩展在两个目录中都存在时,只提供一次(导入列表按 manifest 的name去重,较早的根目录优先)。 - 面板提供Import All(全部导入)按钮:批量导入时界面会实时显示
(done, total)进度(见 Tinycast/Features/Extensions/Settings/ExtensionsSettingsView.swift 中的importProgress状态与importAll(_:)方法),避免一次导入几十个扩展时"静默无反馈"。 - 每次打开该面板都会重新检查一遍,并提示你"Raycast 中有、但 Tinycast 还没有"的扩展(
pending列表在task启动时通过raycastImportCandidates()刷新),例如显示"N not here yet — …"的摘要。 - 导入只认已构建的扩展:Raycast 以 UUID 作为目录键,因此 Tinycast 只能靠 manifest 判断目录里装的是什么;只有当目录内存在对应
<command>.js构建产物时才视为可导入。
从文件夹添加(Add from folder)
第三种方式面向你自己构建好的项目:指向任意一个包含 manifest(package.json)和已构建命令文件的文件夹即可安装。
复制动作非常克制(见 Tinycast/Features/Extensions/Service/ExtensionCatalog.swift 中install(from:)的实现):
- 只复制
package.json、所有已构建的<command>.js文件以及assets/目录; - 绝不复制
node_modules,绝不复制.js.map源映射——它们既占空间又暴露源码; - 安装前会校验 manifest 是否存在(否则报
notAnExtension)、扩展是否支持 macOS(否则报wrongPlatform)、是否存在至少一个已构建命令(否则报noBuiltCommands,提示"Tinycast 只安装预构建扩展,请在扩展目录先运行ray build,或从已安装的 Raycast 导入")。
一个值得留意的细节:GitHub 源码下载会丢失文件的可执行位(mode bits),因此安装与每次扫描时,Tinycast 会按文件内容识别可执行负载(shebang#!或 Mach-O/ELF 魔数)并恢复执行权限(restoreExecutablePermissions),保证扩展内的辅助可执行脚本可以正常运行。
注册表(Registries)
Tinycast 出厂自带两个注册表,你可以自由地添加自己的注册表。两者本质上是两种完全不同的"供货渠道":
| Raycast Store | GitHub 仓库 | |
|---|---|---|
| 提供给你 | 一个已构建好的扩展 | 源代码 |
| 你需要准备 | 什么都不需要 | Node 与一个包管理器 |
Store 正是大多数人完全不需要工具链的原因——它直接把已经构建好的产物交给你。
从源码看(Tinycast/Features/Extensions/Model/ExtensionRegistry.swift),两个内置注册表的定位是:
- Raycast Store(
kind == .raycastStore):默认开启,通过 Raycast 官网搜索所用的端点提供预编译扩展;它不是一个官方 API,因此 Store 端点若变化,GitHub 注册表就是兜底方案; - 官方 GitHub 注册表(
raycast/extensions,kind == .github):默认关闭,因为它提供的是源码、安装时需要构建工具链。
GitHub 注册表的形态与添加方式
一个 GitHub 注册表就是任何"每个扩展一个文件夹"布局的仓库,例如raycast/extensions。添加时输入owner/repo,或直接粘贴仓库中某个扩展文件夹的链接。解析逻辑(ExtensionRegistry.parse(_:name:))会剥离https://、github.com/等前缀与末尾的.git,并识别浏览器复制出来的/tree/<ref>/<path>形式的链接(ref默认main,路径默认extensions,path会被规范化去掉首尾斜杠)。
几个关键行为:
- 只下载扩展自己的文件夹,绝不下载整个仓库:客户端用一次递归 Git tree API 拿到目标路径下的文件清单,再逐个拉取 raw 文件,并跳过
node_modules与metadata目录(后者体积大且与运行无关)。若目录过大导致 tree 被截断,会直接报错而不是下载一个不完整的扩展。 - 注册表还支持指定
ref(分支、标签或 commit);分支意味着"那里现在有什么就用什么"。 - 内置注册表(Store 与官方 GitHub)不可编辑、不可删除,只有用户自己添加的注册表可以删除或改名。
- 由于 Store 是预编译的,在合并搜索结果时Store 结果优先(
ExtensionStoreClient.search的注释明确写着 "the store wins, because it is prebuilt")。
从源码安装的构建流程
从 GitHub 源码安装时,Tinycast 会依次执行:
<package manager> install --ignore-scripts——安装依赖;- 运行扩展自身的构建脚本(对 Raycast 扩展而言通常是
ray build)。
安装脚本被刻意跳过(--ignore-scripts),因为那是"没人要求运行的代码"。如果扩展在缺少安装脚本的情况下无法构建,那么它会在构建步骤直接失败,而不是先装一个半残的扩展。对应的参数定义见 Tinycast/Features/Extensions/Model/ExtensionPackageManager.swift:pnpm/Yarn/Bun 使用install --ignore-scripts,npm 额外追加--no-audit --no-fund关掉审计与赞助提示。
构建细节同样值得了解(Tinycast/Features/Extensions/Service/ExtensionInstaller.swift):
- 若
node_modules/.bin/ray存在,会调用ray build -e <env> -o <output> --non-interactive,且输出目录永远不会指向源码目录(防止开发式安装清空源码);若不存在ray(非标准 Raycast 项目),则退化为运行 manifest 的build脚本并在原地校验产物。 - 构建环境参数
-e会自动探测:如果扩展目录里出现Cargo.toml(即包含 Rust 辅助组件),使用dev环境(其 Rust 插件会桩化掉仅为 Windows 服务的rust:类型命令),否则使用dist——因为dist会为 Windows 构建rust:助手,那是 macOS 上的死代码且需要本机没有的 Rust 工具链。 - 子进程设置
CI=1(阻止 npm 向输出里刷进度条)与NO_COLOR=1;失败时只截取输出的末尾 6 行展示(包管理器真正的错误信息都在尾部)。 - 整个安装有5 分钟超时(
commandTimeout = 300),足以覆盖慢速网络下的冷安装,又不会让一个卡死的子进程无限挂起;临时工作目录使用tinycast-install-<UUID>命名并保证无论成功失败都会清理(defer删除),这也是下文"存储清理"能兜底崩溃残留的基础。
安装进度会以明确的阶段呈现:Downloading…→Installing dependencies with pnpm…→Building…→Installing…,避免长时间静默被误认为卡死。
包管理器(Package managers)
配置入口:Settings → Extensions → Package manager。
Automatic(自动,默认)会按pnpm → Bun → Yarn → npm的顺序使用你本机第一个可用的包管理器(源码中ExtensionPackageManager.preferenceOrder = [.pnpm, .bun, .yarn, .npm])。理由写在注释里:最快、最省磁盘的排最前,几乎必然存在的 npm 排最后。
这里有一个关键的技术背景:从 Dock 启动的 GUI 应用不会继承你终端里的PATH。因此 Tinycast 不会依赖 shell 环境,而是自行在常规位置探测可执行文件(searchPaths数组,见ExtensionPackageManager.swift):
- Homebrew:
/opt/homebrew/bin、/usr/local/bin,以及兜底的/usr/bin、/bin - Volta:
~/.volta/bin - Bun:
~/.bun/bin - asdf:
~/.asdf/shims - mise:
~/.local/share/mise/shims - fnm:
~/.local/share/fnm/aliases/default/bin - nvm:
~/.nvm/versions/node/current/bin - Yarn:
~/.yarn/bin - 以及
~/.npm-global/bin
包管理器面板会如实显示探测结果,例如 "Found pnpm at /opt/homebrew/bin/pnpm",或者告诉你本机什么都没装(此时使用源码注册表会失败)。由于ray build运行在 Node 之上,构建前还会单独探测node可执行文件(nodeURL),并把 Node 所在目录插入子进程 PATH 的最前面——因为版本管理器常常把 Node 藏起来,而包管理器会从 PATH 上派生ray。
自定义搜索路径(Custom search paths)
对于内置列表之外的场景(典型如Nix),Registries 面板提供Custom search paths(自定义搜索路径):一个用冒号分隔的文件夹列表,语义与PATH相同,并且排在常规位置之前检查——因此你自定义的目录可以覆盖内置路径。例如:
~/.local/share/mise/shims/etc/profiles/per-user/you/home-path/bin(后者即 Nix Home Manager 的用户环境路径;~/.local/share/mise/shims同时是面板输入框的默认提示文本。)设置一次,之后每一次从源码安装都会生效。解析规则(ExtensionRegistriesPanel.parseSearchPaths)按:切分并丢弃空段与纯空白段,所以连续冒号不会产生空目录项。
哪些内容不参与备份
以下三项会被刻意排除在备份之外(参见 Tinycast 备份文档),因为它们描述的是这台 Mac,而不是可迁移的用户数据:
- 注册表列表(registry list)
- 包管理器选择(package manager choice)
- 自定义搜索路径(custom search paths)
换句话说,备份的是"内容"而不是"环境":换一台机器恢复备份时,扩展本身会回来,但"从哪里下载、用什么工具构建"这种环境偏好不会跟着走。
存储与卸载
所有扩展都存放在 Tinycast 的 Application Support 文件夹下(~/Library/Application Support/<bundle-id>/,其中extensions/存放扩展本体、extension-data/存放扩展数据、extension-support/存放每个扩展各自的 scratch 目录)。
卸载一个扩展会删除与之相关的全部内容,包括:
- 扩展本体与其存储、缓存
- 它的偏好设置与 support 文件夹
- 它在 Keychain 中的登录凭据(sign-ins)
- 图标选择(icon choice)
- 命令快捷键、收藏(favorites)、别名(aliases)与学习到的排序(learned ranking)
卸载实现(ExtensionCatalog.uninstall)同时清理扩展目录与其专属 support 目录,两条路径都覆盖到。
Settings → Extensions → Storage则负责测量并清理"残留构建文件夹"——那种崩溃的安装可能遗留下来的东西(例如命名前缀tinycast-install-的临时工作目录,以及孤立在 support/data 根下、不再对应任何已安装扩展的条目)。清理逻辑见 Tinycast/Features/Extensions/Service/ExtensionCleanup.swift:
- 只扫描三个明确根目录(临时目录、support、data),范围刻意收窄;
- 即使扩展整体被关闭也依然可用(设置面板把 Storage 区块放在"启用扩展"开关组之外,注释明确说 "leftovers are on disk whether or not extensions are on");
- 正常情况下它显示为空——因为正常安装的临时目录会被
defer及时清掉; - 清理前会先计算可回收的报告(
reclaimable),按钮按下前就能显示将释放多少项、多少字节,且计数使用与 Finder 一致的文件大小口径(ByteCountFormatter,countStyle: .file),让面板数字与"Get Info"对得上。
最后一点边界保证:Tinycast 永远不会触碰你自己的~/Library/pnpm或~/.npm——它只在自己的沙箱目录内作业,你的全局包管理器缓存始终保持干净。
小结
围绕Install入口,Tinycast 给出了清晰的取舍:日常安装走Store 注册表(预编译、零工具链);已有 Raycast 环境则一键Import from Raycast(纯复制、离线完成);想构建自己的扩展,用Add from folder指向构建产物;需要自定义来源时添加GitHub 注册表(此时才需要 Node 与包管理器,且--ignore-scripts保证只运行显式声明的构建脚本)。理解注册表两种形态、Automatic 的探测顺序与自定义搜索路径的优先级,就能在绝大多数场景下做到"安装即用、卸载干净"。
- 桌面应用
【免费下载链接】tinycast
Tinycast — a tiny, fully native macOS launcher, hotkeys, and clipboard history.
相关推荐
Tinycast 扩展系统完全指南:用 JavaScriptCore 原生运行 Raycast 扩展
Tinycast 扩展系统完全指南:用 JavaScriptCore 原生运行 Raycast 扩展 Tinycast 是一个完全原生的 macOS 启动器、热
桌面应用Tinycast 原生运行 Raycast 扩展:JavaScriptCore 嵌入式运行时架构与实践指南
Tinycast 原生运行 Raycast 扩展:JavaScriptCore 嵌入式运行时架构与实践指南 Tinycast 是一款完全原生的 macOS 启动
桌面应用Tinycast 命令全指南:内置命令、自定义 Shell 命令与 Raycast 脚本导入实战
Tinycast 命令全指南:内置命令、自定义 Shell 命令与 Raycast 脚本导入实战 本篇技术指南以 Tinycast 的命令系统为主题,覆盖三类能
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考