---
name: tailnet-file-share
description: 将本地文件转为 tailnet 链接，图片自动内嵌预览，其他文件给下载链接
trigger: 当用户要求查看、发送、分享、下载、导出本机上的任何文件时
---

当用户要查看或获取本机上的文件时（图片、日志、报告、构建产物、导出数据等），你必须：

1. 调用 grix_file_link 工具，传入文件的绝对路径
2. 将工具返回的 `markdown` 字段原样写入你的回复，不要修改
   - 图片文件（jpg/png/gif/webp/svg 等）：工具返回 `![文件名](url)`，在聊天中直接渲染为图片预览
   - 其他文件：工具返回 `[文件名](url)`，用户点击即可下载
3. 不要输出原始文件路径，不要尝试粘贴或转述文件内容
4. 链接有效期默认 10 分钟，如需延长可传入 ttl_ms 参数（单位毫秒，最长 24 小时）

## HTTPS 与首次安装信任证书

下载链接是 HTTPS（`https://…`），由本机内置的一个 10 年有效期自签 CA 现签发。
工具结果里还会返回 `ca_install_url` —— 这是根 CA 证书的安装链接。

- **第一次给某个用户发文件链接时**（或用户反馈"链接打不开 / 证书不受信任 / 不安全"时），
  把 `ca_install_url` 作为"安装信任证书"链接一并发给他，并附上下面的安装步骤。
- 用户在**每台设备上只需安装一次**，之后 10 年内这台机器发出的所有下载链接都不再有任何警告，
  tailnet IP 变了也不用重装。

发给用户的安装引导（按其设备选其一）：

- **iPhone / iPad**：用 Safari 打开 `ca_install_url`，会直接弹出"此网站正尝试下载一个描述文件" → 允许 →
  到「设置」顶部出现"已下载描述文件"，点进去安装 →
  再到「设置 → 通用 → 关于本机 → 证书信任设置」，把该证书开关打开（开启完全信任）。这一步必须做，否则系统仍不信任。
  （iOS 必须用 Safari 打开，其他浏览器不会触发描述文件安装。服务端已按设备自动返回 .mobileconfig，无需手动加参数。）
- **Mac**：点链接下载 `.crt` → 双击用「钥匙串访问」打开 → 找到该证书 → 双击 →「信任」展开 →「使用此证书时」选"始终信任"。
- **Android**：点 `ca_install_url` 下载 `.crt` →「设置 → 安全 → 加密与凭据 → 安装证书 → CA 证书」选择刚下载的文件安装
  （新版安卓不支持浏览器内一键安装，必须走系统设置这一步）。
- **Windows**：双击 `.crt` →「安装证书」→ 选存储位置 →「将所有证书放入下列存储」→ 选"受信任的根证书颁发机构"。

如果 grix_file_link 调用失败（如未连接 Tailscale），告诉用户文件的本地路径，让他们自行获取。

## 适用范围（重要）：这套证书只管 grix_file_link 自己的服务

上面这张内置 CA 和它签发的证书，**只让 grix_file_link 起的下载服务（本机 tailnet 地址）被设备信任**。它不负责、也解决不了用户自己另起的其它服务。

当用户在 tailnet 上**自行启动了别的 HTTPS 服务**（自建网站 / API / 媒体服务等），用浏览器打开报证书错误时，要分清这是另一回事：

- 设备只信任「它亲自装过的那张 CA 签出来的证书」。自建服务用的是它自己的 CA（如 mkcert），设备没装过，所以报 `不受信任 / 冒充 / NET::ERR_CERT_AUTHORITY_INVALID`——这跟有没有装 Grix 的 CA 无关。
- 想让自建服务也被信任，只有两条路：
  1. 让该服务改用一张设备已信任的 CA 来签证书，并且叶子证书有效期 **≤ 398 天**（否则即使信任了 CA，仍会报 `NET::ERR_CERT_VALIDITY_TOO_LONG`）；
  2. 或者干脆别让用户开自己的 HTTPS，把要分享的文件改走 grix_file_link，由本机内置服务发出来，自动被信任、有效期也合规。
- 注意：Grix 内置 CA 的**私钥只留在跑连接器的这台机器上、不对外发**（`ca_install_url` 只给公钥证书，不给私钥）。因此只有**与连接器同一台机器**上的服务能借这张 CA 来签证书；其它机器上的服务必须自带 CA，并在每台设备各装一次。

简而言之：能用 grix_file_link 发的就用它发，最省事；自建服务的证书信任问题不在本技能职责内，需在那个服务侧自行解决。

## 两条信任路：Grix app 内 vs 系统浏览器（排障先分清）

同一个链接，在 **Grix app 里打开** 和在 **系统浏览器（Safari / Chrome）里打开**，走的是两套完全独立的证书信任机制，报错和解法都不同。用户反馈"打不开 / 证书报错"时，先问清他是在哪条路上看的。

- **Grix app 内**（图片预览、应用内下载等走 app 自带的网络栈）：app 内置了一条信任规则——只要链接是 tailnet 地址（`100.64.0.0/10` 段）、且证书签发者名字里含 `Grix Tailnet Local CA`，就直接放行，**用户不需要在设备上安装任何证书**。所以 grix_file_link 的链接在 app 里通常开箱即用、零安装。app 内若仍打不开，多半是没走 tailnet IP、或证书签发者名字不符，而不是"没装证书"。
- **系统浏览器（Safari / Chrome）**：走的是手机 / 电脑的系统信任库，跟 app 那条规则毫无关系。必须按上面《HTTPS 与首次安装信任证书》把根 CA 装好（iOS 装 .mobileconfig 并开完全信任，安卓走系统设置，等等）。用户截图里出现的 `NET::ERR_CERT_AUTHORITY_INVALID`、`冒充`、`NET::ERR_CERT_VALIDITY_TOO_LONG`，几乎都是系统浏览器这条路，引导他装 CA 即可。

对**自建服务**同理，按用户要在哪看来定：

- 只需要在 **Grix app 内**展示：自建服务无需向用户分发私钥、也无需装任何证书——只要①服务挂在 tailnet IP 上、②把它那张 CA 的签发者名字带上 `Grix Tailnet Local CA`，app 就会信任。
- 需要在 **系统浏览器** 里打开：app 那条规则不起作用，仍需在每台设备装上该服务自己的 CA（见上一节《适用范围》）。

注意：app 内这条是**按签发者名字字符串匹配**，不是按某把 CA 的公钥指纹绑定。它仅作为私有 tailnet 内的便利取舍，**不是强安全边界**——同一 tailnet 内任何人只要把 CA 命名成相同前缀就会被 app 信任。不要据此把它当作可对抗攻击者的信任根。
