flexgate 0.4.1__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {flexgate-0.4.1 → flexgate-0.6.0}/.github/workflows/docs.yml +1 -3
  2. {flexgate-0.4.1 → flexgate-0.6.0}/CLAUDE.md +24 -20
  3. {flexgate-0.4.1 → flexgate-0.6.0}/PKG-INFO +20 -11
  4. {flexgate-0.4.1 → flexgate-0.6.0}/README.md +19 -10
  5. {flexgate-0.4.1 → flexgate-0.6.0}/docs/cli.md +56 -21
  6. {flexgate-0.4.1 → flexgate-0.6.0}/docs/configuration.md +15 -6
  7. {flexgate-0.4.1 → flexgate-0.6.0}/docs/development.md +9 -7
  8. {flexgate-0.4.1 → flexgate-0.6.0}/docs/quickstart.md +1 -1
  9. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/__init__.py +1 -1
  10. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/cli.py +338 -155
  11. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/config.py +41 -4
  12. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/doctor.py +40 -12
  13. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/healthcheck.py +2 -23
  14. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/main.py +0 -1
  15. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/migrate.py +14 -1
  16. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/proxy.py +25 -9
  17. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/router.py +42 -16
  18. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/server.py +2 -2
  19. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/service.py +180 -140
  20. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/settings.py +114 -67
  21. flexgate-0.6.0/flexgate/sync.py +106 -0
  22. flexgate-0.6.0/flexgate/ui.py +99 -0
  23. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/update.py +19 -18
  24. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/usage.py +24 -13
  25. flexgate-0.4.1/flexgate/guardian.py +0 -252
  26. flexgate-0.4.1/flexgate/sync.py +0 -203
  27. {flexgate-0.4.1 → flexgate-0.6.0}/.github/workflows/release.yml +0 -0
  28. {flexgate-0.4.1 → flexgate-0.6.0}/.gitignore +0 -0
  29. {flexgate-0.4.1 → flexgate-0.6.0}/config.yaml.template +0 -0
  30. {flexgate-0.4.1 → flexgate-0.6.0}/docs/Makefile +0 -0
  31. {flexgate-0.4.1 → flexgate-0.6.0}/docs/_static/.gitkeep +0 -0
  32. {flexgate-0.4.1 → flexgate-0.6.0}/docs/conf.py +0 -0
  33. {flexgate-0.4.1 → flexgate-0.6.0}/docs/index.md +0 -0
  34. {flexgate-0.4.1 → flexgate-0.6.0}/docs/requirements.txt +0 -0
  35. {flexgate-0.4.1 → flexgate-0.6.0}/docs/usage.md +0 -0
  36. {flexgate-0.4.1 → flexgate-0.6.0}/flexgate/__main__.py +0 -0
  37. {flexgate-0.4.1 → flexgate-0.6.0}/pyproject.toml +0 -0
  38. {flexgate-0.4.1 → flexgate-0.6.0}/test.png +0 -0
  39. {flexgate-0.4.1 → flexgate-0.6.0}/test_multimodal.py +0 -0
  40. {flexgate-0.4.1 → flexgate-0.6.0}/test_multimodal_gateway.py +0 -0
@@ -7,8 +7,6 @@ on:
7
7
  - 'docs/**'
8
8
  - 'flexgate/__init__.py'
9
9
  - '.github/workflows/docs.yml'
10
- tags:
11
- - 'v*'
12
10
  pull_request:
13
11
  branches: [main]
14
12
  paths:
@@ -60,7 +58,7 @@ jobs:
60
58
  url: ${{ steps.deployment.outputs.page_url }}
61
59
  runs-on: ubuntu-latest
62
60
  needs: build-docs
63
- if: github.ref == 'refs/heads/main' || github.ref_type == 'tag'
61
+ if: github.ref == 'refs/heads/main'
64
62
  steps:
65
63
  - name: Deploy to GitHub Pages
66
64
  id: deployment
@@ -21,8 +21,8 @@ flexgate service install # install + enable + start systemd u
21
21
  # Lifecycle
22
22
  flexgate service {install|start|stop|restart|reload|status|uninstall}
23
23
  flexgate run # foreground/debug only
24
- flexgate check # provider connectivity diagnostics
25
24
  flexgate status # providers, fallback chains, per-key usage, active routes
25
+ flexgate log # service journal (-f follow, -r route lines only)
26
26
 
27
27
  # Config
28
28
  flexgate config {init|show|set|path|edit}
@@ -31,18 +31,20 @@ flexgate config set sonnet minimax MiniMax-M3
31
31
  flexgate config edit # interactive curses TUI: pick provider/model per tier
32
32
 
33
33
  # Claude Code settings bridge
34
- flexgate settings import # read from ~/.claude/settings.json
35
- flexgate settings apply # write ANTHROPIC_BASE_URL → localhost
34
+ flexgate settings import # read from ~/.claude/settings.json* (merges keys into api_keys)
35
+ flexgate settings apply # rewrite the flexgate env keys → localhost (other fields preserved)
36
+ flexgate settings apply --dry-run # preview the env diff without writing
36
37
 
37
38
  # confsync config sync
38
- flexgate sync # pull config.yaml from your confsync server (merge keys)
39
+ flexgate sync # pull: replace local config.yaml with the remote document (backup first)
39
40
  flexgate sync push # upload local config.yaml to the server
40
- flexgate sync --full # replace local config with the remote document (backup first)
41
41
  flexgate sync --dry-run # preview changes without writing
42
42
 
43
43
  # Versioning / upgrades
44
44
  flexgate --version # print package version
45
- flexgate doctor # diagnose install/config problems (exit 1 on failure)
45
+ flexgate doctor # diagnose install/config + upstream connectivity (exit 1 on failure)
46
+ flexgate doctor --offline # skip all network checks (PyPI + upstream probing)
47
+ flexgate check # DEPRECATED alias: delegates to doctor
46
48
  flexgate update # upgrade package via pip/pipx/uv + migrate config schema
47
49
  flexgate update --check # report what would change, modify nothing
48
50
  flexgate update --config-only # only migrate the config schema
@@ -81,29 +83,30 @@ Claude Code → POST /v1/messages (model="claude-sonnet-4-6")
81
83
 
82
84
  | File | Role |
83
85
  |------|------|
84
- | `cli.py` | argparse CLI; service lifecycle commands, foreground `run`/`check`, config/settings/sync commands |
85
- | `config.py` | Pydantic-like dataclasses (`GatewayConfig`, `ProviderConfig`, `RouteConfig`, `ScheduleEntry`), YAML load/save, `TIER_PATTERNS` regex map |
86
- | `router.py` | `resolve(config, model)` — schedule-first then default routes, first regex match wins |
86
+ | `cli.py` | argparse CLI; service lifecycle commands, foreground `run`, config/settings/sync commands, `flexgate log` journal viewer |
87
+ | `ui.py` | Shared terminal styling: ANSI helpers (`bold`/`dim`/`red`/...), `ok`/`warn`/`fail`/`err` output helpers, `FlexgateHelpFormatter` + `FlexgateParser` (colored help on every Python version; all gated by `NO_COLOR` + stdout isatty) |
88
+ | `config.py` | Pydantic-like dataclasses (`GatewayConfig`, `ProviderConfig`, `RouteConfig`, `ScheduleEntry`), YAML load/save, `TIER_PATTERNS` regex map, `is_placeholder_key` |
89
+ | `router.py` | `resolve(config, model)` — schedule-first then default routes, first regex match wins; model aliases normalized before matching |
87
90
  | `proxy.py` | `handle_request()` — httpx async proxy, per-key fallback retry loop, SSE streaming + JSON pass-through |
88
91
  | `usage.py` | `flexgate status` usage queries — per-platform adapters (MiniMax coding_plan API, Kimi Code usages API, z.ai quota API, LiteLLM `/key/info`) plus a minimal chat probe fallback |
89
92
  | `server.py` | Starlette app creation, `POST /v1/messages` endpoint, `SIGUSR1` lifespan reload |
90
93
  | `main.py` | Thin bootstrap: load config → create app → run uvicorn |
91
94
  | `service.py` | Authoritative systemd user-service install/start/stop/restart/reload/status and legacy PID migration |
92
- | `guardian.py` | Legacy port/PID helper; no longer owns persistent process supervision |
93
- | `healthcheck.py` | Pre-flight `POST /v1/messages` (max_tokens=1) to each referenced (provider, model) pair |
94
- | `settings.py` | Bridges `config.yaml` ↔ `~/.claude/settings.json` (import credentials, apply config) |
95
+ | `healthcheck.py` | Upstream connectivity probing (`POST /v1/messages`, max_tokens=1) for each referenced (provider, model) pair; called by `doctor` (`flexgate check` is a deprecated alias of doctor) |
96
+ | `settings.py` | Bridges `config.yaml` ↔ `~/.claude/settings.json`: import merges credentials into `api_keys`; apply rewrites only the managed env keys, preserving every other settings.json field |
95
97
  | `sync.py` | `flexgate sync` — pushes/pulls the whole config.yaml as an encrypted document on a confsync server (lazily imports the `confsync` client package) |
96
98
  | `migrate.py` | Config schema versioning: `config_version` marker, per-step `MIGRATIONS` chain (N → N+1), backup + atomic rewrite |
97
- | `doctor.py` | `flexgate doctor` — read-only diagnostics (Python, PyPI update, config schema/semantics, port, systemd, Claude settings) |
99
+ | `doctor.py` | `flexgate doctor` — read-only diagnostics (Python, PyPI update, config schema/semantics, port, systemd, Claude settings) plus upstream connectivity via `healthcheck` (skipped with `--offline`) |
98
100
  | `update.py` | `flexgate update` — PyPI version check, package upgrade via detected installer (pipx/uv/pip), config migration, service reload; after a successful package upgrade the config migration is re-run in a fresh process so it uses the new code's schema version (`FLEXGATE_UPDATE_DELEGATED` guards against re-delegation); also the cached (24h) new-version notice shown by bare `flexgate` / `service status` |
99
101
 
100
102
  ### Key design points
101
103
 
102
104
  - **Regex-first routing**: Routes are regex patterns matched against the `model` field in the request body. First match wins. A catch-all `".*"` pattern at the end handles fallback.
105
+ - **Model alias normalization** (`router.py`): before matching, bare aliases (`sonnet`/`opus`/`haiku`/`default`, case-insensitive, optional `[plan]` suffix) map to `claude-<tier>` prefixes (`default` → sonnet, Claude Code's default tier), and legacy numbered names (`claude-3-7-sonnet-latest`) reduce to their tier prefix; everything else passes through unchanged, so custom patterns and the catch-all behave exactly as before.
103
106
  - **Model resolution & `available_models` fallback**: A route may omit `model`; `router.resolve()` then falls back to the provider's first `available_models` entry, so `model_override` handed to the proxy is always a concrete name. `config._parse_routes` rejects routes that omit `model` on a provider with no `available_models` — so adding a provider without models requires an explicit `model` on every route using it.
104
107
  - **Proxy rewrite contract** (`proxy.py`): the upstream request gets the provider's `x-api-key` plus a fixed header set, and the JSON `model` field is rewritten only when the route set an override. Streaming responses are forwarded as raw bytes (`aiter_bytes`), never parsed.
105
- - **Key fallback** (`proxy.py`): a provider's `api_keys` list holds one or more keys for the same upstream (entries are key strings or `{key, note}` mappings; `note` is a free-form label shown by `flexgate status` and in fallback logs). Multiple accounts on one upstream — e.g. several MiniMax subscriptions — belong in ONE provider, not separate ones. On a retryable failure (HTTP 401/402/403/429/500/502/503/529, connect error, or timeout) the request is retried with the next key in order. Streaming requests can only fall back before the upstream returns 200. `_regular_proxy`/`_stream_proxy` return `(response, retryable)`; `handle_request` owns the loop and returns the last error when all keys fail. The legacy `api_key` + `fallback_keys` schema is still parsed (`config._parse_api_keys`); migration v3 → v4 rewrites it to `api_keys`. `ProviderConfig.api_key` remains as a first-key property (getter/setter) for sync/settings merge code.
106
- - **Usage inspection** (`usage.py`): `flexgate status` maps `base_url` to a platform adapter (`_ADAPTERS`): MiniMax → `{origin}/v1/api/openplatform/coding_plan/remains` (the `*_usage_count` fields are REMAINING counts, an upstream naming quirk), Kimi Code → `{base}/v1/usages` (undocumented, same endpoint as the CLI's `/usage`; reports weekly quota, 5-hour window and parallel limit), z.ai/bigmodel → `{origin}/api/monitor/usage/quota/limit` (undocumented but used by z.ai's own plugin), USTC/LiteLLM → `{origin}/key/info`. Hosts in `_PROBE_ONLY_MARKERS` (e.g. xiaomimimo.com — no key-based usage API) and unknown platforms get the minimal chat probe: `POST /v1/messages` with input `"hi"`, `max_tokens=128`. A failed adapter call also degrades to the probe.
108
+ - **Key fallback** (`proxy.py`): a provider's `api_keys` list holds one or more keys for the same upstream (entries are key strings or `{key, note}` mappings; `note` is a free-form label shown by `flexgate status` and in fallback logs). Multiple accounts on one upstream — e.g. several MiniMax subscriptions — belong in ONE provider, not separate ones. Each *route* has an active-key pointer (`active_key` in YAML, 1-based; `RouteConfig.key_index` 0-based, default first key): requests on that route start from the pointed key, and on a retryable failure (HTTP 401/402/403/429/500/502/503/529, connect error, or timeout) the next key is tried and the pointer advances with it (in memory only, wrapping around — it is not written back to the file); every key is tried at most once and a full circle of failures returns the last error. The pointer is set interactively via `flexgate config edit` → "api keys" (pick a route, with live per-key usage) or by editing the route's `active_key` directly. `resolve()` (`router.py`) returns the matched `RouteConfig` so the proxy can read/advance its pointer. Streaming requests can only fall back before the upstream returns 200. `_regular_proxy`/`_stream_proxy` return `(response, retryable)`; `handle_request` owns the loop and returns the last error when all keys fail. The legacy `api_key` + `fallback_keys` schema is still parsed (`config._parse_api_keys`); migration v3 → v4 rewrites it to `api_keys`. `ProviderConfig.api_key` remains as a first-key property (getter/setter) for the settings import code.
109
+ - **Usage inspection** (`usage.py`): `flexgate status` maps `base_url` to a platform adapter (`_ADAPTERS`): MiniMax → `{origin}/v1/api/openplatform/coding_plan/remains` (only the "general" text-model quota entry is used; its counts are usually 0/0, so usage is read from the `*_remaining_percent` fields), Kimi Code → `{base}/v1/usages` (undocumented, same endpoint as the CLI's `/usage`; reports weekly quota, 5-hour window and parallel limit), z.ai/bigmodel → `{origin}/api/monitor/usage/quota/limit` (undocumented but used by z.ai's own plugin), USTC/LiteLLM → `{origin}/key/info`. Hosts in `_PROBE_ONLY_MARKERS` (e.g. xiaomimimo.com — no key-based usage API) and unknown platforms get the minimal chat probe: `POST /v1/messages` with input `"hi"`, `max_tokens=128`. A failed adapter call also degrades to the probe.
107
110
  - **Multimodal degradation**: `MULTIMODAL_MODELS` (currently `{"MiniMax-M3", "glm-4.6v"}`) is the allowlist. Requests carrying image blocks aimed at any other model have images stripped and a `[flexgate]` text note injected into both the outgoing request and the returned response, so non-multimodal backends don't 4xx.
108
111
  - **Schedule-based overrides**: Optional time windows (e.g. 22:00-06:00) override default routes. Overnight wrap is supported.
109
112
  - **Service-first lifecycle**: `flexgate.service` is the sole persistent runtime. systemd owns restart, boot startup, logs, and process state.
@@ -111,6 +114,8 @@ Claude Code → POST /v1/messages (model="claude-sonnet-4-6")
111
114
  - **Conflict prevention**: Service startup removes stale legacy PID files, stops verified legacy Flexgate daemons, validates the configured port, and rejects temporary config paths.
112
115
  - **Tier patterns** in `config.py`: `opus`, `sonnet`, `haiku` map to regex patterns for CLI shorthand (`config set sonnet ...`).
113
116
  - **Single-source versioning**: the package version lives only in `flexgate/__init__.py` (`__version__`); hatchling reads it via `[tool.hatch.version]`. `--version`, `service status` and the bare `flexgate` command all print it.
117
+ - **Settings apply is non-destructive** (`settings.py`): only the six managed `env` keys are rewritten (BASE_URL, AUTH_TOKEN, API_TIMEOUT_MS, three `ANTHROPIC_DEFAULT_*_MODEL`); every other settings.json field (hooks, permissions, unrelated env vars) is preserved. Token policy is one code path shared with `service install`: explicit arg → token already in the file → `"gateway"`. `settings import` merges into the provider's `api_keys` list (appends new keys, never overwrites key #1 only).
118
+ - **Terminal styling** (`ui.py`): every colored output goes through `ui.bold`/`dim`/`ok`/`err`/... — all gated on `NO_COLOR` + stdout isatty, so pipes never receive escape codes. `err()` writes to stderr. Help screens use `FlexgateParser` (subparsers inherit it automatically); on Python 3.14+ argparse's own help theming is disabled so the look matches older versions.
114
119
  - **Config schema versioning**: `config.yaml` carries `config_version` (current: `migrate.CURRENT_CONFIG_VERSION`). Each schema change adds one rule to `migrate.MIGRATIONS` upgrading N → N+1; upgrades walk the chain step by step. `save_config` always stamps the current version; `load_config` rejects configs written by a newer flexgate; `flexgate update` applies pending migrations with a timestamped backup.
115
120
 
116
121
  ### Config location
@@ -119,11 +124,10 @@ Config lives at `~/.flexgate/config.yaml` (override with `FLEXGATE_CONFIG`).
119
124
  `flexgate sync` needs no flexgate-side setup — connection details come from
120
125
  the shared confsync credentials written by `confsync login --server <url>`
121
126
  (`~/.confsync/credentials.json`). The whole config.yaml is synced as one
122
- encrypted document (app `flexgate`, name `config.yaml`): pull merges
123
- provider api_keys and imports remote-only providers (local routes/schedules
124
- untouched), bootstraps the file when missing, and `--full` replaces it with a
125
- timestamped backup. The `confsync-client` package is a declared dependency
126
- (PyPI), so sync works out of the box once logged in.
127
+ encrypted document (app `flexgate`, name `config.yaml`): pull always replaces
128
+ the local file with the remote document (a timestamped backup is kept), or
129
+ bootstraps the file when missing. The `confsync-client` package is a declared
130
+ dependency (PyPI), so sync works out of the box once logged in.
127
131
  The persistent unit lives at `~/.config/systemd/user/flexgate.service`; logs are
128
132
  in the systemd user journal. `~/.flexgate/service-state.json` records the last
129
133
  successfully applied config path and endpoint. PID/guardian files are legacy artifacts only.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: flexgate
3
- Version: 0.4.1
3
+ Version: 0.6.0
4
4
  Summary: Flexible local API gateway for Claude Code — route models to different providers
5
5
  Project-URL: Homepage, https://github.com/Agony5757/flexible-gateway
6
6
  Project-URL: Repository, https://github.com/Agony5757/flexible-gateway
@@ -106,13 +106,13 @@ flexgate service uninstall # 停止、禁用并删除 unit
106
106
  - 若升级时检测到旧版后台 gateway 仍在运行,会先准备好 systemd unit,但不会强杀正在服务的进程;按提示手动 `kill <PID>` 停掉旧进程,再执行 `flexgate service start` 完成切换。
107
107
  - unit 设置了启动速率限制,永久配置错误不会再无限快速重启。
108
108
  - `service reload` 和 `config set/edit` 会在仅路由变化时发送 SIGUSR1;如果 endpoint 变化,则先检查再 restart。若只改 host、仍复用当前 port,为避免误停服务会要求先执行 `service stop`,再执行 `service start`。
109
- - 查看日志:`journalctl --user -u flexgate -e`。
109
+ - 查看日志:`flexgate log`(`-f` 跟随、`--since`/`--grep` 过滤、`-r` 只看路由决策行)。
110
110
 
111
111
  ### 版本与升级
112
112
 
113
113
  ```bash
114
114
  flexgate --version # 打印版本号(service status / 裸 flexgate 也会显示)
115
- flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings
115
+ flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings、上游连通性
116
116
  flexgate doctor --offline # 跳过 PyPI 检查
117
117
  flexgate update # 一键升级:pip/pipx/uv 升级包 + 迁移配置 schema + 热重载服务
118
118
  flexgate update --check # 只报告将要做什么,不改动
@@ -149,7 +149,7 @@ Trusted Publisher(repo: `Agony5757/flexible-gateway`,workflow: `release.yml`
149
149
 
150
150
  ### 上游连通性预检
151
151
 
152
- 运行 `flexgate check` 会向每个 **被路由引用的 `(provider, model)` 组合**
152
+ 运行 `flexgate doctor` 会向每个 **被路由引用的 `(provider, model)` 组合**
153
153
  发送一次 `POST /v1/messages`(`max_tokens=1`,消耗约 1~2 token),用于主动检查:
154
154
 
155
155
  - DNS / TCP / TLS 不可达(`base_url` 写错、网络不通)
@@ -157,7 +157,10 @@ Trusted Publisher(repo: `Agony5757/flexible-gateway`,workflow: `release.yml`
157
157
  - 仍是默认占位符(如 `your-zai-api-key`)
158
158
  - Provider 侧 5xx 故障
159
159
 
160
- 可通过 `--verify-timeout N` 调整每个 provider 的超时时间(默认 15 秒)。
160
+ 可通过 `--verify-timeout N` 调整每个 provider 的超时时间(默认 15 秒),
161
+ `--offline` 跳过全部网络检查(PyPI 新版检查 + 上游探测)。
162
+ 旧的 `flexgate check` 命令仍可用,但已弃用:它会打印提示并委托给 `doctor`
163
+ (注意 doctor 还检查本地安装,退出码语义更宽)。
161
164
 
162
165
  ### 状态总览与用量查询(`flexgate status` / `flexgate usage`)
163
166
 
@@ -187,13 +190,12 @@ fallback 链、当前生效的路由,并逐一查询**每个 key** 的用量/
187
190
  如果某平台的专用接口调用失败,flexgate 会自动退化为 minimal probe 再试一次。
188
191
  用量查询接口多为平台内部接口,可能随时变动;查询结果仅供参考。
189
192
 
190
- ### 前台调试与连通性检查
193
+ ### 前台调试
191
194
 
192
- `run` / `check` 是独立的顶层调试命令,不属于持久化服务模式:
195
+ `run` 是独立的顶层调试命令,不属于持久化服务模式:
193
196
 
194
197
  ```bash
195
198
  flexgate run # 单个前台进程,仅用于开发/调试
196
- flexgate check # 上游 provider 连通性检测
197
199
  ```
198
200
 
199
201
  非 systemd 环境只能使用 `flexgate run` 前台运行。`--port PORT` 也只对
@@ -259,10 +261,17 @@ Flexgate config — ~/.flexgate/config.yaml
259
261
  ### Settings 管理
260
262
 
261
263
  ```bash
262
- flexgate settings import # 从 ~/.claude/settings.json* 导入凭证到 config.yaml
263
- flexgate settings apply # 将 config.yaml 配置写入 ~/.claude/settings.json
264
+ flexgate settings import # 从 ~/.claude/settings.json* 导入凭证到 config.yaml(多 key 追加)
265
+ flexgate settings apply # 将网关 env 写入 ~/.claude/settings.json(非破坏性)
266
+ flexgate settings apply --dry-run # 预览将要修改的 env 键,不写文件
264
267
  ```
265
268
 
269
+ `apply` 只重写 flexgate 托管的 6 个 env 键(BASE_URL、AUTH_TOKEN、
270
+ API_TIMEOUT_MS、三个 `ANTHROPIC_DEFAULT_*_MODEL`),settings.json 中的
271
+ 其他字段(hooks、permissions、自定义 env 等)全部保留;写入前自动备份。
272
+ `import` 会把新 key 追加到 provider 的 `api_keys` 列表(已存在则跳过),
273
+ 不会覆盖已有 key。
274
+
266
275
  ### 全局参数
267
276
 
268
277
  - `--config PATH` 指定配置文件(默认 `~/.flexgate/config.yaml`)
@@ -278,7 +287,7 @@ flexgate settings apply # 将 config.yaml 配置写入 ~/.claude/settin
278
287
  | `~/.flexgate/service-state.json` | 最近一次成功启动所应用的 config 路径与 endpoint |
279
288
  | `~/.flexgate/update-check.json` | PyPI 新版本检查的缓存(24h 有效期) |
280
289
  | `~/.config/systemd/user/flexgate.service` | 唯一的持久化服务 unit |
281
- | systemd journal | 服务日志(`journalctl --user -u flexgate`) |
290
+ | systemd journal | 服务日志(`flexgate log`,即 `journalctl --user -u flexgate`) |
282
291
 
283
292
  旧版本的 `~/.flexgate/flexgate.pid`、`flexgate.guardian.pid` 和
284
293
  `flexgate.log` 不再属于当前运行架构;service 启动时会安全清理 PID 残留,
@@ -89,13 +89,13 @@ flexgate service uninstall # 停止、禁用并删除 unit
89
89
  - 若升级时检测到旧版后台 gateway 仍在运行,会先准备好 systemd unit,但不会强杀正在服务的进程;按提示手动 `kill <PID>` 停掉旧进程,再执行 `flexgate service start` 完成切换。
90
90
  - unit 设置了启动速率限制,永久配置错误不会再无限快速重启。
91
91
  - `service reload` 和 `config set/edit` 会在仅路由变化时发送 SIGUSR1;如果 endpoint 变化,则先检查再 restart。若只改 host、仍复用当前 port,为避免误停服务会要求先执行 `service stop`,再执行 `service start`。
92
- - 查看日志:`journalctl --user -u flexgate -e`。
92
+ - 查看日志:`flexgate log`(`-f` 跟随、`--since`/`--grep` 过滤、`-r` 只看路由决策行)。
93
93
 
94
94
  ### 版本与升级
95
95
 
96
96
  ```bash
97
97
  flexgate --version # 打印版本号(service status / 裸 flexgate 也会显示)
98
- flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings
98
+ flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings、上游连通性
99
99
  flexgate doctor --offline # 跳过 PyPI 检查
100
100
  flexgate update # 一键升级:pip/pipx/uv 升级包 + 迁移配置 schema + 热重载服务
101
101
  flexgate update --check # 只报告将要做什么,不改动
@@ -132,7 +132,7 @@ Trusted Publisher(repo: `Agony5757/flexible-gateway`,workflow: `release.yml`
132
132
 
133
133
  ### 上游连通性预检
134
134
 
135
- 运行 `flexgate check` 会向每个 **被路由引用的 `(provider, model)` 组合**
135
+ 运行 `flexgate doctor` 会向每个 **被路由引用的 `(provider, model)` 组合**
136
136
  发送一次 `POST /v1/messages`(`max_tokens=1`,消耗约 1~2 token),用于主动检查:
137
137
 
138
138
  - DNS / TCP / TLS 不可达(`base_url` 写错、网络不通)
@@ -140,7 +140,10 @@ Trusted Publisher(repo: `Agony5757/flexible-gateway`,workflow: `release.yml`
140
140
  - 仍是默认占位符(如 `your-zai-api-key`)
141
141
  - Provider 侧 5xx 故障
142
142
 
143
- 可通过 `--verify-timeout N` 调整每个 provider 的超时时间(默认 15 秒)。
143
+ 可通过 `--verify-timeout N` 调整每个 provider 的超时时间(默认 15 秒),
144
+ `--offline` 跳过全部网络检查(PyPI 新版检查 + 上游探测)。
145
+ 旧的 `flexgate check` 命令仍可用,但已弃用:它会打印提示并委托给 `doctor`
146
+ (注意 doctor 还检查本地安装,退出码语义更宽)。
144
147
 
145
148
  ### 状态总览与用量查询(`flexgate status` / `flexgate usage`)
146
149
 
@@ -170,13 +173,12 @@ fallback 链、当前生效的路由,并逐一查询**每个 key** 的用量/
170
173
  如果某平台的专用接口调用失败,flexgate 会自动退化为 minimal probe 再试一次。
171
174
  用量查询接口多为平台内部接口,可能随时变动;查询结果仅供参考。
172
175
 
173
- ### 前台调试与连通性检查
176
+ ### 前台调试
174
177
 
175
- `run` / `check` 是独立的顶层调试命令,不属于持久化服务模式:
178
+ `run` 是独立的顶层调试命令,不属于持久化服务模式:
176
179
 
177
180
  ```bash
178
181
  flexgate run # 单个前台进程,仅用于开发/调试
179
- flexgate check # 上游 provider 连通性检测
180
182
  ```
181
183
 
182
184
  非 systemd 环境只能使用 `flexgate run` 前台运行。`--port PORT` 也只对
@@ -242,10 +244,17 @@ Flexgate config — ~/.flexgate/config.yaml
242
244
  ### Settings 管理
243
245
 
244
246
  ```bash
245
- flexgate settings import # 从 ~/.claude/settings.json* 导入凭证到 config.yaml
246
- flexgate settings apply # 将 config.yaml 配置写入 ~/.claude/settings.json
247
+ flexgate settings import # 从 ~/.claude/settings.json* 导入凭证到 config.yaml(多 key 追加)
248
+ flexgate settings apply # 将网关 env 写入 ~/.claude/settings.json(非破坏性)
249
+ flexgate settings apply --dry-run # 预览将要修改的 env 键,不写文件
247
250
  ```
248
251
 
252
+ `apply` 只重写 flexgate 托管的 6 个 env 键(BASE_URL、AUTH_TOKEN、
253
+ API_TIMEOUT_MS、三个 `ANTHROPIC_DEFAULT_*_MODEL`),settings.json 中的
254
+ 其他字段(hooks、permissions、自定义 env 等)全部保留;写入前自动备份。
255
+ `import` 会把新 key 追加到 provider 的 `api_keys` 列表(已存在则跳过),
256
+ 不会覆盖已有 key。
257
+
249
258
  ### 全局参数
250
259
 
251
260
  - `--config PATH` 指定配置文件(默认 `~/.flexgate/config.yaml`)
@@ -261,7 +270,7 @@ flexgate settings apply # 将 config.yaml 配置写入 ~/.claude/settin
261
270
  | `~/.flexgate/service-state.json` | 最近一次成功启动所应用的 config 路径与 endpoint |
262
271
  | `~/.flexgate/update-check.json` | PyPI 新版本检查的缓存(24h 有效期) |
263
272
  | `~/.config/systemd/user/flexgate.service` | 唯一的持久化服务 unit |
264
- | systemd journal | 服务日志(`journalctl --user -u flexgate`) |
273
+ | systemd journal | 服务日志(`flexgate log`,即 `journalctl --user -u flexgate`) |
265
274
 
266
275
  旧版本的 `~/.flexgate/flexgate.pid`、`flexgate.guardian.pid` 和
267
276
  `flexgate.log` 不再属于当前运行架构;service 启动时会安全清理 PID 残留,
@@ -2,7 +2,7 @@
2
2
 
3
3
  ```text
4
4
  usage: flexgate [-h] [--config CONFIG] [--version]
5
- {service,run,check,status,usage,settings,sync,help,doctor,update,config} ...
5
+ {service,run,check,status,usage,log,settings,sync,help,doctor,update,config} ...
6
6
  ```
7
7
 
8
8
  全局参数:
@@ -45,7 +45,7 @@ flexgate service uninstall # 停止、禁用并删除 unit
45
45
  - `service reload` 和 `config set/edit` 会在仅路由变化时发送 SIGUSR1;
46
46
  如果 endpoint 变化,则先检查再 restart。若只改 host、仍复用当前 port,
47
47
  为避免误停服务会要求先执行 `service stop`,再执行 `service start`。
48
- - 查看日志:`journalctl --user -u flexgate -e`。
48
+ - 查看日志:`flexgate log`(`-f` 跟随、`--since`/`--grep` 过滤、`-r` 只看路由决策行)。
49
49
 
50
50
  ## 状态总览与用量查询
51
51
 
@@ -59,9 +59,32 @@ flexgate usage --usage-timeout 30
59
59
 
60
60
  各平台的用量查询适配器详见[用量查询](usage.md)。
61
61
 
62
+ ## 查看日志(log)
63
+
64
+ ```bash
65
+ flexgate log # 最近 50 行服务日志(systemd user journal)
66
+ flexgate log -n 200 # 最近 200 行
67
+ flexgate log -f # 实时跟随(Ctrl-C 退出)
68
+ flexgate log --since "10 min ago"
69
+ flexgate log --grep 429 # 只显示包含 429 的行(大小写不敏感)
70
+ flexgate log -r # 只看路由决策行
71
+ flexgate log -f -r # 实时观察每个请求被路由到哪个 provider/模型
72
+ ```
73
+
74
+ `flexgate log` 读取 `flexgate.service` 的 systemd 用户日志(等价于
75
+ `journalctl --user -u flexgate`,输出为单时间戳的 cat 格式)。`-r` 只显示
76
+ 每个请求完成时的路由决策行:
77
+
78
+ ```text
79
+ [default] claude-sonnet-4-6 -> zai (glm-5.3) | 200 | 6676ms
80
+ ```
81
+
82
+ 想知道"刚才那条回复到底是哪个模型服务的",看这一行即可。前台调试用的
83
+ `flexgate run` 日志直接打印在终端,不进 journal。
84
+
62
85
  ## 上游连通性预检
63
86
 
64
- `flexgate check` 会向每个**被路由引用的 `(provider, model)` 组合**发送一次
87
+ `flexgate doctor` 会向每个**被路由引用的 `(provider, model)` 组合**发送一次
65
88
  `POST /v1/messages`(`max_tokens=1`,消耗约 1~2 token),用于主动检查:
66
89
 
67
90
  - DNS / TCP / TLS 不可达(`base_url` 写错、网络不通)
@@ -69,15 +92,17 @@ flexgate usage --usage-timeout 30
69
92
  - 仍是默认占位符(如 `your-zai-api-key`)
70
93
  - Provider 侧 5xx 故障
71
94
 
72
- 可通过 `--verify-timeout N` 调整每个 provider 的超时时间(默认 15 秒)。
95
+ 可通过 `--verify-timeout N` 调整每个 provider 的探测超时(默认 15 秒);
96
+ `--offline` 跳过全部网络检查(PyPI 新版检查 + 上游探测)。旧的
97
+ `flexgate check` 命令已弃用:仍可运行,但会打印提示并委托给 `doctor`
98
+ (注意 doctor 还检查本地安装,退出码语义更宽)。
73
99
 
74
100
  ## 前台调试
75
101
 
76
- `run` / `check` 是独立的顶层调试命令,不属于持久化服务模式:
102
+ `run` 是独立的顶层调试命令,不属于持久化服务模式:
77
103
 
78
104
  ```bash
79
105
  flexgate run # 单个前台进程,仅用于开发/调试
80
- flexgate check # 上游 provider 连通性检测
81
106
  ```
82
107
 
83
108
  非 systemd 环境只能使用 `flexgate run` 前台运行。`--port PORT` 也只对
@@ -128,17 +153,24 @@ flexgate config set haiku MiniMax-M3
128
153
 
129
154
  ```text
130
155
  Flexgate config — ~/.flexgate/config.yaml
131
- ↑/↓ move · Enter edit tier · s save · q quit
156
+ ↑/↓ move · Enter edit · s save · q quit
132
157
 
133
158
  ▶ opus ustc / deepseek-v4-pro
134
159
  sonnet ustc / deepseek-v4-pro
135
160
  haiku ustc / deepseek-v4-pro
161
+ fallback ustc / deepseek-v4-pro
162
+ api keys select the active key per route
136
163
 
137
164
  ○ no unsaved changes
138
165
  ```
139
166
 
140
- - 方向键选中某个 tier(opus/sonnet/haiku),回车进入:先从候选
167
+ - 方向键选中某个 tier(opus/sonnet/haiku)或 `fallback`(兜底路由
168
+ `.*`,未命中任何 tier 的请求走它),回车进入:先从候选
141
169
  **provider** 列表选择,再从该 provider 的候选 **model** 列表选择。
170
+ - 选中 `api keys` 回车进入:先选一条**路由**,再选它的 **active key**
171
+ (该路由的请求从这个 key 开始;fallback 会自动前移指针,所有 key
172
+ 轮换一圈都失败则返回错误)。key 列表会实时查询每个 key 的用量/有效性
173
+ (与 `flexgate status` 相同),并标注当前 active 的 key。
142
174
  - model 列表包含:`available_models` 中的各个模型、「使用 provider 默认
143
175
  (首个可用模型,不写死 model)」、以及「自定义模型…」(手动输入)。
144
176
  - 按 `s` 保存(并向运行中的网关发送 SIGUSR1 热重载,**无需重启即生效**),
@@ -150,22 +182,26 @@ Flexgate config — ~/.flexgate/config.yaml
150
182
  ## Settings 管理
151
183
 
152
184
  ```bash
153
- flexgate settings import # 从 ~/.claude/settings.json* 导入凭证到 config.yaml
154
- flexgate settings apply # 将 config.yaml 配置写入 ~/.claude/settings.json
185
+ flexgate settings import # 从 ~/.claude/settings.json* 导入凭证到 config.yaml(多 key 追加)
186
+ flexgate settings apply # 将网关 env 写入 ~/.claude/settings.json(非破坏性)
187
+ flexgate settings apply --dry-run # 预览将要修改的 env 键,不写文件
155
188
  ```
156
189
 
157
190
  **import** 会扫描 `~/.claude/settings.json*`,从每个文件中提取
158
- `ANTHROPIC_BASE_URL` 和 `ANTHROPIC_AUTH_TOKEN`,自动写入 config.yaml 的
159
- providers 部分。文件名与 provider 名称的映射规则:
191
+ `ANTHROPIC_BASE_URL` 和 `ANTHROPIC_AUTH_TOKEN`,合并进 config.yaml 的
192
+ providers:provider 已存在时**追加**到它的 `api_keys` 列表(已存在同一把
193
+ key 则跳过),不存在则新建。文件名与 provider 名称的映射规则:
160
194
 
161
195
  - `settings.json` → 根据域名自动推断(如含 `z.ai` → `zai`)
162
196
  - `settings.json.zai` → provider 名 `zai`
163
197
  - `settings.json.bak.*` → 跳过(备份文件)
164
198
 
165
- **apply** 会读取 config.yaml 中的 `server` 和 `claude_settings`,备份当前
166
- `~/.claude/settings.json` 为 `settings.json.bak.{timestamp}`,然后生成新的
167
- settings.json,将 `ANTHROPIC_BASE_URL` 指向本地网关,并保留原有的
168
- `permissions` 等非 env 字段:
199
+ **apply** 是非破坏性的:备份当前 `~/.claude/settings.json` 为
200
+ `settings.json.bak.{timestamp}` 后,**只重写 flexgate 托管的 6 个 env 键**
201
+ (`ANTHROPIC_BASE_URL`、`ANTHROPIC_AUTH_TOKEN`、`API_TIMEOUT_MS`、三个
202
+ `ANTHROPIC_DEFAULT_*_MODEL`),settings.json 中的其余字段(hooks、
203
+ permissions、自定义 env 等)全部原样保留。token 策略与 `service install`
204
+ 共用一条路径:显式参数 → 文件里已有的 token → 兜底 `"gateway"`:
169
205
 
170
206
  ```json
171
207
  {
@@ -192,11 +228,10 @@ settings.json,将 `ANTHROPIC_BASE_URL` 指向本地网关,并保留原有的
192
228
  confsync 配置段):
193
229
 
194
230
  ```bash
195
- flexgate sync # 默认 pull:下载并合并远端配置
231
+ flexgate sync # 默认 pull:用远端文档整体替换本地配置(先备份)
196
232
  flexgate sync pull # 同上
197
233
  flexgate sync push # 上传本地 config.yaml
198
- flexgate sync --dry-run # 只显示哪些 key 会变化,不写配置
199
- flexgate sync --full # 用远端文档整体替换本地配置(先备份)
234
+ flexgate sync --dry-run # 只预览,不写配置
200
235
  ```
201
236
 
202
237
  更多细节见 `flexgate help`。
@@ -205,8 +240,8 @@ flexgate sync --full # 用远端文档整体替换本地配置(先备份
205
240
 
206
241
  ```bash
207
242
  flexgate --version # 打印版本号
208
- flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings
209
- flexgate doctor --offline # 跳过 PyPI 检查
243
+ flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings、上游连通性
244
+ flexgate doctor --offline # 跳过全部网络检查(PyPI 新版检查 + 上游探测)
210
245
  flexgate update # 一键升级:pip/pipx/uv 升级包 + 迁移配置 schema + 热重载服务
211
246
  flexgate update --check # 只报告将要做什么,不改动
212
247
  flexgate update --config-only # 只迁移配置,不升级包
@@ -8,7 +8,7 @@
8
8
  | `~/.flexgate/service-state.json` | 最近一次成功启动所应用的 config 路径与 endpoint |
9
9
  | `~/.flexgate/update-check.json` | PyPI 新版本检查的缓存(24h 有效期) |
10
10
  | `~/.config/systemd/user/flexgate.service` | 唯一的持久化服务 unit |
11
- | systemd journal | 服务日志(`journalctl --user -u flexgate`) |
11
+ | systemd journal | 服务日志(`flexgate log`,即 `journalctl --user -u flexgate`) |
12
12
 
13
13
  旧版本的 `~/.flexgate/flexgate.pid`、`flexgate.guardian.pid` 和
14
14
  `flexgate.log` 不再属于当前运行架构;service 启动时会安全清理 PID 残留,
@@ -60,6 +60,7 @@ routes: # 从上到下匹配,首个命中生效
60
60
  - pattern: "^claude-sonnet"
61
61
  provider: minimax
62
62
  model: "MiniMax-M3"
63
+ active_key: 2 # 可选:该路由从 minimax 的第 2 个 key 开始用(1 起始,默认 1)
63
64
  - pattern: "^claude-haiku"
64
65
  provider: minimax
65
66
  model: "MiniMax-M3"
@@ -80,6 +81,7 @@ routes: # 从上到下匹配,首个命中生效
80
81
  | `routes[].pattern` | 正则匹配请求中的 model 字段 |
81
82
  | `routes[].provider` | 路由到的 provider 名称 |
82
83
  | `routes[].model` | 可选,替换发给 provider 的模型名 |
84
+ | `routes[].active_key` | 可选,1 起始的 provider api_keys 序号,该路由的请求从哪个 key 开始(默认 1,即第一个 key) |
83
85
  | `schedule[].name` | 定时规则名称 |
84
86
  | `schedule[].start/end` | 时间窗口(HH:MM 格式,支持跨夜如 22:00-06:00) |
85
87
  | `schedule[].routes` | 该时间窗口内生效的路由(格式同 `routes`) |
@@ -91,18 +93,25 @@ routes: # 从上到下匹配,首个命中生效
91
93
  `{key, note}` 加一个存在配置里的备注(`flexgate status` 和 fallback 日志
92
94
  都会显示 note,方便分辨是哪个账号的 key):
93
95
 
94
- - 请求先走第一个 key;失败时按列表顺序自动重试后续 key,直到某个 key
95
- 成功或返回不可重试的错误。
96
+ - 每条路由有一个「当前 key」指针(路由上的 `active_key`,默认指向
97
+ provider 的第一个 key):该路由的请求从指针指向的 key 开始;key 失败
98
+ 时自动换用下一个 key(循环一圈),指针也随之自动前进——后续请求直接
99
+ 从能用的 key 开始。**所有 key 轮换一圈都失败时,请求返回最后一次的
100
+ 错误**。指针在运行时的前进只存在于网关进程内存中,不写回配置文件。
96
101
  - 触发切换的条件:HTTP **401 / 402 / 403 / 429 / 500 / 502 / 503 / 529**
97
102
  (key 失效、余额/额度耗尽、限流、平台过载)以及连接错误、超时。
98
103
  其他 4xx(如 400 请求格式错误)不会触发切换。
99
104
  - 流式请求只有在上游返回非 200 状态码之前才能切换 key;一旦开始吐
100
105
  token,响应已提交,无法再 fallback。
101
106
  - 每次切换都会在服务日志中留下记录(key 只显示前后各 4 位)。
102
- - 用 `flexgate status` 可以查看每个 provider 的 fallback 链和每个 key 的
103
- 实时用量。
107
+ - 用 `flexgate status` 可以查看每个 provider 的 fallback 链、每条路由
108
+ 当前使用的 key 和每个 key 的实时用量;在 `flexgate config edit` 交互
109
+ 界面的「api keys」入口可以按路由查看各 key 的实时用量/有效性并切换
110
+ active key。
104
111
  - 旧版 `api_key` + `fallback_keys` 写法仍然兼容,`flexgate update` 会
105
- 自动迁移为 `api_keys` 列表(config_version 3 → 4)。
112
+ 自动迁移为 `api_keys` 列表(config_version 3 → 4);路由上的
113
+ `active_key` 字段在 config_version 5 引入,旧配置的每条路由默认指向
114
+ 第一个 key。
106
115
 
107
116
  ## 环境变量
108
117
 
@@ -4,17 +4,19 @@
4
4
 
5
5
  | 文件 | 作用 |
6
6
  |------|------|
7
- | `flexgate/cli.py` | argparse CLI;service 生命周期命令、前台 `run`/`check`、config/settings/sync 命令 |
8
- | `flexgate/config.py` | dataclass 配置模型(`GatewayConfig`、`ProviderConfig`、`RouteConfig` 等),YAML 加载/保存 |
9
- | `flexgate/router.py` | `resolve(config, model)` — 先定时路由后默认路由,首个正则命中生效 |
10
- | `flexgate/proxy.py` | `handle_request()` — httpx 异步代理,per-key fallback 重试,SSE 流式 + JSON 透传 |
7
+ | `flexgate/cli.py` | argparse CLI;service 生命周期命令、前台 `run`、config/settings/sync 命令、`flexgate log` 日志查看 |
8
+ | `flexgate/ui.py` | 共享终端样式:ANSI 辅助函数、`ok`/`warn`/`fail`/`err` 输出辅助、`FlexgateHelpFormatter`(各版本一致的彩色 help;统一受 `NO_COLOR` + isatty 门控) |
9
+ | `flexgate/config.py` | dataclass 配置模型(`GatewayConfig`、`ProviderConfig`、`RouteConfig` 等),YAML 加载/保存,`is_placeholder_key` |
10
+ | `flexgate/router.py` | `resolve(config, model)` — 先定时路由后默认路由,首个正则命中生效;匹配前归一化模型别名(`sonnet`/`claude-3-7-sonnet-latest` → `^claude-<tier>`) |
11
+ | `flexgate/proxy.py` | `handle_request()` — httpx 异步代理,per-key fallback 重试,SSE 流式 + JSON 透传;记录每个请求由哪把 key 服务 |
11
12
  | `flexgate/usage.py` | `flexgate status` / `flexgate usage` 的用量查询 — 各平台适配器 + minimal chat probe 兜底 |
12
13
  | `flexgate/server.py` | Starlette 应用,`POST /v1/messages` 端点,SIGUSR1 热重载 |
13
- | `flexgate/service.py` | systemd 用户服务的安装/启停/重载/状态(持久化运行的唯一入口) |
14
- | `flexgate/settings.py` | config.yaml ↔ `~/.claude/settings.json` 双向桥接 |
14
+ | `flexgate/service.py` | systemd 用户服务的安装/启停/重载/状态(持久化运行的唯一入口);journal 日志查看 |
15
+ | `flexgate/healthcheck.py` | 上游连通性探测(`POST /v1/messages`,`max_tokens=1`),由 `doctor` 调用(`flexgate check` 为弃用别名) |
16
+ | `flexgate/settings.py` | config.yaml ↔ `~/.claude/settings.json` 双向桥接(apply 非破坏性:只改托管 env 键) |
15
17
  | `flexgate/sync.py` | `flexgate sync` — 通过 confsync 服务器加密同步整份配置 |
16
18
  | `flexgate/migrate.py` | 配置 schema 版本化:逐级迁移链 + 备份 + 原子重写 |
17
- | `flexgate/doctor.py` | `flexgate doctor` — 只读诊断 |
19
+ | `flexgate/doctor.py` | `flexgate doctor` — 只读诊断 + 上游连通性(`--offline` 跳过网络检查) |
18
20
  | `flexgate/update.py` | `flexgate update` — PyPI 版本检查、按安装方式升级、配置迁移、服务重载 |
19
21
 
20
22
  ## 关键设计
@@ -49,5 +49,5 @@ provider。日常管理常用:
49
49
  ```bash
50
50
  flexgate status # providers + fallback 链 + 每个 key 的用量 + 当前路由
51
51
  flexgate config edit # 交互式调整每个 tier 的 provider/model
52
- journalctl --user -u flexgate -e # 查看服务日志
52
+ flexgate log # 查看服务日志(-r 只看路由决策行)
53
53
  ```
@@ -1,3 +1,3 @@
1
1
  """Flexgate — Flexible API Gateway for Claude Code."""
2
2
 
3
- __version__ = "0.4.1"
3
+ __version__ = "0.6.0"