# mirasim-relay

把 Mirasim 桌面版内置的「本地中继」单独拆出来，让 Linux 也能用自己账号的额度。

Mirasim 官方只发 macOS / Android 包，但它的 `SHA256SUMS` 里其实还有没在下载页挂出来的
`mirasim-server-linux-x64-0.0.146.tar.gz`。这个脚本就是从那份官方 Linux 构建里把中继部分
（登录 → 设备签名 → 转发）重新实现出来的，行为跟桌面版一致。

中继本身说的是 **Anthropic 的协议**，同时也提供 **OpenAI Responses 协议**（Codex 用的那个），
按路径分发，凭据完全一样。所以 Claude Code 和 Codex 都能直接指过来。

## 快速开始

```sh
./mirasim-relay login      # 邮箱验证码 / GitHub / Google / 直接粘 token
./mirasim-relay status     # 看账号、有效期、剩余额度（两条协议各探一次）
./mirasim-relay serve      # 起本地中继，默认 127.0.0.1:8787
```

另开一个终端，Claude Code：

```fish
set -gx ANTHROPIC_BASE_URL http://127.0.0.1:8787
set -gx ANTHROPIC_AUTH_TOKEN mirasim-relay-managed-credential
claude
```

Codex：

```sh
./mirasim-relay codex                      # 等价于 codex，但指向中继
./mirasim-relay codex -- exec "写个 fib"    # -- 后面原样透传给 codex
```

bash / zsh 用 `./mirasim-relay env --bash`，它会按当前 shell 输出对应语法。
`ANTHROPIC_AUTH_TOKEN` 的值是什么都无所谓——每个请求都会被换成真正的中继凭据，
但大多数 agent 不设这个变量就不发请求，所以得给一个占位值。

## 命令

| 命令 | 说明 |
| --- | --- |
| `login [--method email\|github\|google\|token] [--email ...]` | 登录并保存凭据 |
| `serve [--port 8787] [--host 127.0.0.1] [--agent claude\|codex] [-v]` | 起本地中继，`-v` 打印每条请求 |
| `codex [--port 8787] [--model ...] [--effort ...] [-- <codex 参数>]` | 拉起真正的 codex，指向中继 |
| `status [--model ...]` | 账号信息 + 探测两条协议的额度 |
| `env [--port 8787] [--bash] [--codex]` | 输出环境变量 |
| `logout` | 清除登录态（设备密钥保留） |

不给 `--agent` 时，`x-mirasim-agent` 按请求路径自动推断（`/v1/messages` → `claude`，
`/v1/responses` → `codex`），跟桌面版的上报一致；给了就固定。

## 两条协议

中继按路径分发，跟桌面版 `server.cjs` 里的分类函数（`tD()`）一字不差：

| 路径 | 协议 | 谁在用 |
| --- | --- | --- |
| `POST /v1/messages` | Anthropic Messages | Claude Code |
| `POST /v1/responses` | OpenAI Responses | Codex（`wire_api = responses`）|
| `POST /v1/chat/completions` | OpenAI Chat Completions | 各种 OpenAI 兼容客户端 |
| `GET /v1/models` | — | 通用 |

Codex 没有「base url 环境变量」这种东西，它只认 config.toml 里的 provider 块。桌面版的做法
是在命令行上现场注入，本脚本照抄：

```
codex -c model_providers.apodex.name=apodex \
      -c model_providers.apodex.base_url=http://127.0.0.1:8787/v1 \
      -c model_providers.apodex.wire_api=responses \
      -c model_providers.apodex.env_key=OPENAI_API_KEY \
      -c model_provider=apodex
```

加上 `OPENAI_API_KEY=mirasim-relay-managed-credential`。`mirasim-relay codex` 就是把这一串
拼好再 exec，`./mirasim-relay env --codex` 只打印不执行。

中继侧的 codex 模型：`gpt-5.6-sol`（默认）、`gpt-5.6-terra`、`gpt-5.6-luna`。
前两个支持到 `ultra` 档推理强度，`luna` 到 `max`；默认 `xhigh`。

顺带一提，`POST /backend-api/codex/responses`（ChatGPT 后端那条路径）分类函数里也认，
但中继本身对它返回 404 —— 桌面版只在 MITM 抓 `chatgpt.com` 时才会走到那儿。

## 它到底做了什么

```
agent ──► 127.0.0.1:8787 ──► https://mirasim-relay.mirofish.ai ──► Anthropic / OpenAI
             (本脚本)
```

每个请求经过时：

1. **换凭据** —— 删掉 agent 自己的 `authorization` / `x-api-key`，换成你的账号凭据。
2. **续期** —— access token 距过期不足 15 分钟就用 refresh token 走 `/auth/refresh` 换新的。
3. **设备签名** —— 首次运行生成一对 Ed25519 密钥，向 `/v1/device/session` 换一张短期
   ticket；拿到后每个请求都按 `mrs-sig-v1` 签名（`x-mirasim-device/ts/nonce/sig`）。
   中继若不支持（404/501）就退回裸 token，跟桌面版的降级路径一样。
4. **收敛 header** —— 丢掉 hop-by-hop 头；`anthropic-beta` 只保留中继真正认的
   `context-1m-2025-08-07`，其余丢弃。其它头（含 `openai-beta`）原样透传。

响应是流式透传的，SSE 不会被缓冲。客户端中途断开（Ctrl-C、取消一轮对话、关掉 pane）
只会掉这一个请求，不会影响服务端本身。

## 配置

凭据存在 `~/.config/mirasim-proxy/config.json`（`0600`），里面有账号 token、refresh token
和设备私钥。换目录用 `MIRASIM_PROXY_HOME`。

其它可覆盖项：`MIRASIM_RELAY_BASE_URL`、`MIRASIM_LOGIN_URL`、`MIRASIM_APP_VERSION`、
`MIRASIM_NODE`（指定 Node 运行时）、`MIRASIM_CODEX_BIN`（指定 codex 可执行文件）。

## Node

系统没装 Node 也能跑：`vendor/node` 是官方 Linux 包里那个 v22.23.1，启动器按
`$MIRASIM_NODE` → PATH 上的 `node` → `vendor/node` 的顺序找。
装了自己的 Node（>= 20）的话可以把 `vendor/` 删掉。

## 测试

```sh
./vendor/node test.mjs
```

21 个用例，不需要登录，也不会碰真实凭据：签名规范串、deviceId 推导、header 改写、
配置文件权限、路径分类、Codex provider 块，以及四个断连用例（起一个假上游 + 真的
proxy，客户端在流中间 / 上游还没回 header 时 / 上传中途消失，验证服务端还活着）。

## 注意

Mirasim 赠送额度的说法是 “Claude Code Max / Codex Pro usage **inside Mirasim**”。
把中继拆出来给别的 agent 用，大概率不符合他们的服务条款，最坏情况是封号。
自行判断。
