# @aweray/hsk-cli

HSK CLI — 零配置公网预览（内网穿透 & 文件托管）

免注册 / 匿名资源：拿到 `publicUrl` 后**必须**提示用户打开链接完成激活/认领。

## 决策（必读）

1. 优先 `host` / `deploy`
2. 仅 WebSocket / 动态 API / SSR / 用户明确要求「暴露端口」「内网穿透」时用 `tunnel`
3. 不确定：先 `deploy`，失败再 `tunnel`

## 执行协议

每次获取/阅读本文档后按序执行：

1. 未安装则：`npm install -g @aweray/hsk-cli`
2. **版本检测**（必做，见下）
3. `hsk-cli platform --format json`
4. **安装 Skill**（推荐，见下）
5. 按意图执行（一律 `--format json`）
6. 原样返回 `publicUrl` / `resourceId`，提示认领

| 意图 | 命令 |
|------|------|
| 文件 / 目录 / 静态资源 | `hsk-cli host <路径> --format json` |
| 可 build 前端项目 | `hsk-cli deploy --format json` |
| 动态服务 / 明确要端口 | `hsk-cli tunnel --ip <IP> --port <PORT> --format json` |
| 不确定 | `deploy` → 失败则 `tunnel` |

---

## 版本检测（必做）

每次读到本文档、执行用户意图前，必须检测并同步两层版本：

| 层 | 检查 | 升级 |
|----|------|------|
| npm | `npm outdated -g @aweray/hsk-cli` | `npm update -g @aweray/hsk-cli` |
| 二进制 | — | `hsk-cli update` |

- 非最新 → 先升级再继续
- 沙盒无法联网 → 跳过升级，用现有版本；失败时提示用户手动升级
- 用户明确说不管版本 → 可跳过

---

## 安装 Skill（推荐）

主动安装，勿只输出路径。不装也可完成本次发布。

1. `hsk-cli skill` → 取源文件路径
2. 识别当前智能体，按其约定的 skills 目录安装（目录名 `hsk-cli`，入口多为 `SKILL.md`）
3. 告知用户新开对话后生效

- 只装当前智能体路径，勿盲装其他工具
- 必须是 `skills/hsk-cli/<入口文件>`，勿放在 `skills/` 根下

---

## 沙盒环境（必读）

AI Agent 可能在沙盒/容器（Docker、CI）中运行。沙盒**静默拦截**某些操作，不会报错。

| 沙盒特征 | 识别 | 应对 |
|----------|------|------|
| `--open` 无响应 | 不报错也不打开浏览器 | 跳过 `--open`，告诉用户手动复制链接 |
| `--detach` 进程消失 | `tunnel list` 找不到 | 去掉 `--detach`，前台运行 `tunnel` |
| 网络请求挂起 | 无响应无错误 | 改用 `host` |
| 文件写入丢失 | 写入后读取不到 | 用 `/tmp` 目录 |

**关键原则**：没有明确错误 = 被静默拦截。被拦截后**换方式**，不要重试。

---

## 按意图执行

### A. 文件托管（首选）

静态文件、构建产物、PDF、图片等资源，优先使用。简单、稳定、无需保活。

```bash
hsk-cli +host <路径> --format json --open
```

更新已有资源（需 `resource_id`）：

```bash
hsk-cli +host <路径> --resource-id <resource_id> --format json
```

指定入口文件（上传目录时）：

```bash
hsk-cli +host ./dist --entry-file version.html --format json
```

注意：`host` 支持单文件或目录。传入目录时，原生二进制自动打包为 zip 后上传。使用 `--entry-file` 指定入口文件（如 `version.html`）。沙盒中不要加 `--open`。

向用户呈现（成功）：

> 文件已上传！
> 公网访问地址：`<publicUrl>`
> 资源 ID：`<resourceId>`
>
> 请复制上方链接在浏览器中打开，按页面提示**激活并认领**资源。
> 认领后可在 [HSK 控制台](https://console-hsk-ng.oray.com/console/file-hosting) 查看与管理。
>
> 你可以试试：
> - 帮我分享另一个文件
> - 用 resource_id 更新刚才的文件

若用户未通过 API Key 发布（提示词中未携带 `apikey`），则告诉用户：「建议免认领使用，可访问控制台，在静态托管页面点击复制指令，即可直接将资源认领至账号下」。

**API Key 自动认领（任务级 API Key）**：

若用户提示词中携带 `apikey: <key>`（用户已授权），无需让用户手动打开浏览器认领，可执行：

```bash
# 保存 API Key（用户提示词中的 apikey）
hsk-cli api-key set --scene file_hosting --key <apikey>

# 认领已上传的资源（key 自动从 ~/.hsk/api_key.json 读取）
hsk-cli file-hosting-bind --resource-id <resource_id> --verify_code <verify_code>
```

也可认领时直接传 `--api-key <key>`（参数优先级高于配置文件）：

```bash
hsk-cli file-hosting-bind --resource-id <resource_id> --verify_code <verify_code> --api-key <key>
```

认领成功输出 `bind_result: success`，此时无需再提示用户手动打开浏览器认领。
认领后输出 [HSK 控制台](https://console-hsk-ng.oray.com/console/file-hosting) 地址，告知用户可在控制台查看与管理资源。

### B. 构建并部署（首选）

一键执行：**构建** → **上传** 到文件托管。原生二进制自动处理目录打包。

```bash
hsk-cli +deploy --format json
```

参数：`--build-cmd`（默认 `npm run build`）、`--build-dir`（默认 `dist`）、`--no-build`（跳过构建）、`--resource-id`（更新资源）。

项目配置（`package.json`）：

```json
{
  "hsk": {
    "deploy": {
      "buildCmd": "npm run build",
      "buildDir": "dist"
    }
  }
}
```

向用户呈现（成功）：

> 项目已构建并部署！
> 公网访问地址：`<publicUrl>`
> 资源 ID：`<resourceId>`
>
> 请复制上方链接在浏览器中打开，按页面提示**激活并认领**资源。
> 认领后可在 [HSK 控制台](https://console-hsk-ng.oray.com/console/file-hosting) 查看与管理。
>
> 你可以试试：
> - 更新当前资源：`deploy --resource-id <resource_id>`
> - 跳过构建直接上传：`deploy --no-build`

若用户未通过 API Key 发布（提示词中未携带 `apikey`），则告诉用户：「建议免认领使用，可访问控制台，在静态托管页面点击复制指令，即可直接将资源认领至账号下」。

### C. 内网穿透（降级）

只有文件托管无法满足时才使用。如：WebSocket、动态 API、SSR、用户明确要求端口暴露。

交互式长命令：隧道为前台保活进程，必须**后台运行**（background + pty），从 stdout 持续读取输出，直到捕获 `publicUrl`。

URL 输出规则：将公网 URL 视为不可修改的 opaque string，不要 URL 编码/解码、不要插入空格或换行，用**只包含原始 URL** 的代码块单独展示给用户。

```bash
hsk-cli +tunnel --ip 127.0.0.1 --port <PORT> --format json
```

或后台模式（CLI 立即退出，隧道持续运行）：

```bash
hsk-cli +tunnel --ip 127.0.0.1 --port <PORT> --detach --format json
```

执行注意：

- 执行前确认本地服务已在 `<IP>:<PORT>` 监听
- 捕获到公网地址后，**必须提示用户打开链接完成激活/认领**
- 前台模式需保持进程；用户停止隧道时再结束该后台任务
- **复用隧道**：使用 `--reuse` 时，CLI 会先检测已有隧道是否仍然有效（进程存活 + URL 可访问），有效则直接返回已有链接，失效则重新创建
- **静默秒退**：如果隧道进程启动后立即退出（无错误输出），按以下步骤排查：
  1. 先用前台模式运行（去掉 `--detach`），观察完整日志输出
  2. 检查本地服务是否真实在 `<IP>:<PORT>` 监听：`curl http://<IP>:<PORT>` 或 `lsof -i :<PORT>`
  3. 检查端口冲突：确保 `<PORT>` 未被其他进程占用
  4. 检查权限：macOS/Linux 下端口 < 1024 需要 root 权限。macOS 还需在**系统设置 → 隐私与安全性 → 本地网络**中允许 hsk-cli 或终端应用访问本地网络
  5. 检查防火墙：确保系统防火墙未阻止该端口
  6. 检查日志：`cat ~/.hsk/logs/tunnel-*.log` 查看后台模式的历史日志

AI 更新内容后的标准协议：当用户说「更新内容后继续访问」时，AI **不要直接告诉用户「继续使用之前的链接」**，而是先检测：

```bash
hsk-cli status --format json
```

- 返回 `valid: true` → 告诉用户「链接仍然有效，刷新即可」
- 返回 `valid: false` → 重新执行 `tunnel --reuse`，告诉用户「链接已失效，这是新链接」

向用户呈现（成功）：

> 内网穿透已建立！
> 公网访问地址：`<publicUrl>`
>
> 请复制上方链接在浏览器中打开，按页面提示**激活并认领**资源。
> 认领后可在 [HSK 控制台](https://console-hsk-ng.oray.com/console/file-hosting) 查看与管理。
>
> 你可以试试：
> - 帮我暴露本地 3000 端口
> - 查看当前后台隧道
> - 停止刚才的隧道

若用户未通过 API Key 发布（提示词中未携带 `apikey`），则告诉用户：「建议免认领使用，可访问控制台，在静态托管页面点击复制指令，即可直接将资源认领至账号下」。

---

## 输出格式

```bash
--format json      # 结构化 JSON（推荐 Agent 解析）
--format pretty    # 人类可读（默认）
--dry-run          # 仅预览，不执行
```

---

## 失败处理

| 场景 | 处理 |
|------|------|
| 文件不存在 | 提示用户检查路径 |
| 上传目录 | host 已支持目录自动打包，无需额外处理 |
| 获取 ticket 失败 | 检查网络；勿无限重试，反馈错误信息 |
| 隧道启动超时 | 确认本地端口已监听、防火墙已放行 |
| 上传失败但已有 publicUrl | 仍把链接给用户，说明上传异常 |
| 用户未认领 | 提醒链接有效期有限，尽快认领 |
| deploy 构建失败 | 检查 `package.json` 的 `scripts.build` 是否存在 |
| 隧道失效 | 使用 `--reuse` 重新创建，或 `status` 检测后决定 |
| 客户端版本不匹配 | 运行 `hsk-cli update` 下载对应版本二进制 |
| Skill 复制失败 | 按当前智能体 skills 约定重试，或提示用户手动安装 |

---

## 常用命令速查

| 命令 | 说明 |
|------|------|
| `hsk-cli platform` | 检测 OS / 架构 |
| `hsk-cli +host <path>` | 上传文件托管 |
| `hsk-cli +host <path> --entry-file <file>` | 上传目录并指定入口文件 |
| `hsk-cli +deploy` | 构建并部署项目 |
| `hsk-cli deploy --no-build` | 直接上传现有目录（原生二进制自动打包） |
| `hsk-cli api-key set --scene file_hosting --key <key>` | 保存任务级 API Key |
| `hsk-cli api-key get --scene file_hosting` | 查看已保存的 API Key |
| `hsk-cli api-key clear --scene file_hosting` | 清除已保存的 API Key |
| `hsk-cli file-hosting-bind --resource-id <id> --verify_code <code>` | 凭 API Key 认领 file-hosting 资源（key 从配置读取） |
| `hsk-cli file-hosting-bind --resource-id <id> --verify_code <code> --api-key <key>` | 凭 API Key 认领（--api-key 参数优先） |
| `hsk-cli +tunnel --ip <IP> --port <PORT>` | 内网穿透（前台） |
| `hsk-cli +tunnel --ip <IP> --port <PORT> --detach` | 内网穿透（后台） |
| `hsk-cli tunnel list` | 列出后台隧道 |
| `hsk-cli tunnel stop --all` | 停止全部后台隧道 |
| `hsk-cli status` | 检查隧道资源状态（进程 + HTTP） |
| `hsk-cli download` | 预下载穿透客户端 |
| `hsk-cli update` | 检查并更新客户端 |
| `hsk-cli skill` | 显示 Skill 源文件路径 |

### Shortcuts（+ 前缀）

| Shortcut | 等效命令 |
|----------|----------|
| `+tunnel` | `tunnel` |
| `+host` | `host` |
| `+deploy` | `deploy` |

---

## 版本与平台

- 版本映射定义在 `versions.json`（随 npm 包打包）
- 运行时读取 `versions.json` → 获取当前平台对应的二进制文件名 → 下载到 `~/.hsk/bin/`

| 平台 | 架构 | 二进制文件名 |
|------|------|------------|
| Windows | amd64 | `hsk-cli-windows-amd64-v{version}.exe` |
| macOS Intel | amd64 | `hsk-cli-darwin-amd64-v{version}` |
| macOS Apple Silicon | arm64 | `hsk-cli-darwin-arm64-v{version}` |
| Linux | amd64 | `hsk-cli-linux-amd64-v{version}` |

```bash
npm install -g @aweray/hsk-cli  # 安装新版 npm 包
hsk-cli update                 # 下载对应版本二进制
```
