pi-cliproxyapi-autoconnect 1.2.4 → 1.2.5

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 (3) hide show
  1. package/README.md +214 -169
  2. package/index.ts +3 -3
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,174 +1,189 @@
1
1
  # pi-cliproxyapi-autoconnect
2
2
 
3
- A **CLIProxyAPI provider for [pi](https://github.com/earendil-works/pi)**.
3
+ An independent **CLIProxyAPI provider for [pi](https://github.com/earendil-works/pi)**.
4
4
 
5
- After installation, `/login` shows a **CLIProxy** entry under **“Sign in with an API key”**. Select it and:
5
+ The extension adds **CLIProxy** to pi's `/login` flow. Enter the CLIProxyAPI bound domain and client API key once; the plugin derives the compatible endpoints, tests them automatically, downloads the model catalog, and registers every model in `/model`.
6
6
 
7
- 1. Enter the CLIProxy **bound domain** (for example `proxy.example.com`);
8
- 2. Enter the **API key**;
9
- 3. The plugin derives every compatible endpoint and tries them automatically in this order: **OpenAI → Gemini → Anthropic** (OpenAI first);
10
- 4. Every discovered model is registered with pi and becomes available in `/model`;
11
- 5. Only when every endpoint fails are you asked to pick an endpoint manually (or enter a custom one) and type model IDs.
7
+ - Provider ID: `cliproxy`
8
+ - Models are listed as `cliproxy/<model-id>`
9
+ - Endpoint discovery order: **OpenAI → Gemini → Anthropic** (OpenAI first)
10
+ - No runtime dependencies beyond the packages pi already provides
12
11
 
13
- The API key is stored by pi in `~/.pi/agent/auth.json`. The plugin's own config file only stores the domain, endpoint and model cache; it **never stores the key**.
12
+ > This is a community extension. It is not an official CLIProxyAPI or pi package.
14
13
 
15
- > Verified on pi `1.2.0` and `1.3.0`: provider registration, `/model` listing, model discovery and fallback, and real streaming chat requests over the OpenAI-compatible API.
14
+ **Links:** [npm package](https://www.npmjs.com/package/pi-cliproxyapi-autoconnect) · [pi package gallery](https://pi.dev/packages) · [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)
15
+
16
+ ---
17
+
18
+ ## Requirements
19
+
20
+ - **pi 1.2.0 or newer** (tested with pi 1.2.x and 1.3.x)
21
+ - **Node.js 22.19 or newer** (required by pi)
22
+ - A running **CLIProxyAPI** instance whose OpenAI-, Gemini-, or Anthropic-compatible API you can reach
23
+ - A CLIProxyAPI **client API key** (configured in `access.api-keys`)
24
+
25
+ The key you enter here is CLIProxyAPI's own client key — **not** an OpenAI, Anthropic, or Google upstream key.
16
26
 
17
27
  ---
18
28
 
19
29
  ## Install
20
30
 
21
- ### Option A: install from npm (recommended)
31
+ Install the extension through pi:
22
32
 
23
- ```powershell
33
+ ```bash
24
34
  pi install npm:pi-cliproxyapi-autoconnect
25
35
  ```
26
36
 
27
- Then restart pi (or run `/reload` inside pi).
37
+ Restart pi. On a running session, `/reload` also reloads extensions.
38
+
39
+ Confirm that pi has recorded the package:
28
40
 
29
- The npm package contains only `index.ts`, `README.md` and `LICENSE`; pi's npm installer downloads it. The next two options are only for local development.
41
+ ```bash
42
+ pi list
43
+ ```
30
44
 
31
- ### Option B: install from a local directory
45
+ > Do not install this package with `npm install`. It is a pi extension, not a standalone CLI; pi must install it so the extension is loaded and managed.
32
46
 
33
- Plugin directory: `F:\Desktop\pi-cliproxyapi-autoconnect`.
47
+ After installation, the provider appears in `/login`. The `cliproxy/*` models appear after the first successful login and model discovery. To verify the registered models at that point:
34
48
 
35
- ```powershell
36
- pi install F:\Desktop\pi-cliproxyapi-autoconnect
49
+ ```bash
50
+ pi --list-models
37
51
  ```
38
52
 
39
- Then restart pi (or run `/reload` inside pi).
53
+ ### Update
40
54
 
41
- ### Option C: copy into the extensions directory
55
+ Update only this extension:
42
56
 
43
- ```powershell
44
- powershell -ExecutionPolicy Bypass -File F:\Desktop\pi-cliproxyapi-autoconnect\install.ps1
57
+ ```bash
58
+ pi update npm:pi-cliproxyapi-autoconnect
45
59
  ```
46
60
 
47
- The script copies the plugin to:
61
+ Update every installed pi package:
48
62
 
49
- ```text
50
- %USERPROFILE%\.pi\agent\extensions\pi-cliproxyapi-autoconnect\
63
+ ```bash
64
+ pi update --extensions
51
65
  ```
52
66
 
53
- If `PI_CODING_AGENT_DIR` is set, it copies to `extensions\pi-cliproxyapi-autoconnect\` under that directory instead.
67
+ Restart pi after updating.
54
68
 
55
- You can also copy the whole `pi-cliproxyapi-autoconnect` folder into `%USERPROFILE%\.pi\agent\extensions\`; make sure the entry point is:
69
+ `pi update` without a target updates pi itself. `pi update --models` refreshes pi's built-in or `models.json` catalog and **does not** refresh this extension's provider catalog; use `/cliproxy refresh`, open `/model`, or restart pi for that.
56
70
 
57
- ```text
58
- %USERPROFILE%\.pi\agent\extensions\pi-cliproxyapi-autoconnect\index.ts
59
- ```
71
+ ### Uninstall
60
72
 
61
- pi automatically loads subfolders under `extensions` whose entry point is `index.ts`.
73
+ Before removing the extension, run `/logout` and select **CLIProxy** if you want to delete the saved API key from pi's `auth.json`. You can also remove the saved connection metadata with `/cliproxy clear`.
62
74
 
63
- After installation, verify that the plugin loads and models are available:
75
+ Then remove the package:
64
76
 
65
- ```powershell
66
- pi --list-models
77
+ ```bash
78
+ pi remove npm:pi-cliproxyapi-autoconnect
67
79
  ```
68
80
 
69
- ### Migrating from the old `pi-cliproxy` package
81
+ Restart pi. Removing the package does not automatically delete credentials from `auth.json`; remove them with `/logout` before uninstalling, or edit `auth.json` manually.
70
82
 
71
- The package was renamed to `pi-cliproxyapi-autoconnect`. The provider ID is still `cliproxy`, and the existing `cliproxy.json` and `auth.json` credentials remain valid.
83
+ ### Migrating from `pi-cliproxy`
72
84
 
73
- ```powershell
85
+ The package was renamed from `pi-cliproxy` to `pi-cliproxyapi-autoconnect`. The provider ID, model prefix, `cliproxy.json` format, and existing credentials are unchanged.
86
+
87
+ ```bash
74
88
  pi remove npm:pi-cliproxy
75
89
  pi install npm:pi-cliproxyapi-autoconnect
76
90
  ```
77
91
 
78
- Then restart pi. Models are still listed as `cliproxy/<model-id>`; no config or cache rebuild is required.
92
+ Restart pi afterward. Models remain `cliproxy/<model-id>`, and no config or cache rebuild is required.
79
93
 
80
94
  ---
81
95
 
82
- ## Usage
96
+ ## Quick start
97
+
98
+ 1. Start pi and run `/login`.
99
+ 2. Choose **Sign in with an API key** (not an account/subscription login).
100
+ 3. Select **CLIProxy**.
101
+ 4. Enter the bound domain, for example `proxy.example.com` or `https://proxy.example.com`.
102
+ 5. Enter the CLIProxyAPI client key.
103
+ 6. Wait for automatic endpoint discovery to finish.
104
+ 7. Run `/model` and select a `cliproxy/<model-id>` entry.
83
105
 
84
- 1. Restart pi and run `/login`.
85
- 2. Choose **“Sign in with an API key”** (not “Sign in with an account”).
86
- 3. Select **CLIProxy** from the list.
87
- 4. Enter the bound domain, for example:
88
- - `proxy.example.com`
89
- - `https://proxy.example.com`
90
- - `http://192.168.1.10:8317`
91
- - a complete URL such as `https://proxy.example.com/v1` also works
92
- 5. Enter the CLIProxy API key (the value in CLIProxy's `access.api-keys`).
93
- 6. The plugin tries every compatible endpoint in this order:
106
+ ### Domain input
94
107
 
95
- ```text
96
- https://<domain>/v1/models OpenAI (highest priority)
97
- https://<domain>/v1beta/models Gemini
98
- https://<domain>/v1/models Anthropic (x-api-key, best effort)
99
- ```
108
+ The value is normalized to a root URL before compatible endpoints are derived. You can paste a bare host, a full URL, or a complete compatible endpoint.
100
109
 
101
- The first endpoint that returns a non-empty model list is selected and saved. The models are immediately visible in `/model`.
102
- If you entered a bare domain without a scheme, every endpoint is also tried with the alternate scheme (https/http), for at most 6 probes.
103
- 7. Run `/model` and select `cliproxy/<model-id>`.
110
+ | You enter | Normalized root |
111
+ | --- | --- |
112
+ | `proxy.example.com` | `https://proxy.example.com` |
113
+ | `https://proxy.example.com/` | `https://proxy.example.com` |
114
+ | `http://192.168.1.10:8317` | `http://192.168.1.10:8317` |
115
+ | `https://proxy.example.com/v1` | `https://proxy.example.com` |
116
+ | `https://proxy.example.com/v1/models` | `https://proxy.example.com` |
117
+ | `https://proxy.example.com/cliproxy/v1` | `https://proxy.example.com/cliproxy` |
104
118
 
105
- ### Address formatting
119
+ Trailing slashes and common suffixes such as `/v1`, `/v1beta`, `/v1/models`, and `/v1beta/models` are removed. A reverse-proxy path prefix is preserved.
106
120
 
107
- The input is first normalized to a root URL: trailing `/`, `/v1`, `/v1beta`, `/v1/models` and similar suffixes are removed, while any path prefix is preserved. The plugin then derives:
121
+ Without an explicit scheme, local and private hosts (`localhost`, `127.0.0.1`, `10.*`, `192.168.*`, `172.16–31.*`, `.local`, `.lan`) default to `http://`; public hosts default to `https://`. A bare host is also retried with the alternate scheme.
108
122
 
109
- | Purpose | Derived endpoint |
110
- | --- | --- |
111
- | OpenAI compatible (highest priority) | `https://<domain>/v1`; model discovery uses `/v1/models` |
112
- | Gemini compatible | `https://<domain>/v1beta`; model discovery uses `/v1beta/models` |
113
- | Anthropic compatible | `https://<domain>` (the SDK appends `/v1/messages`; model discovery tries `/v1/models` as a best effort) |
123
+ ---
124
+
125
+ ## How discovery works
126
+
127
+ The plugin probes the compatible endpoints in this order and uses the first one that returns a non-empty model list:
128
+
129
+ | Priority | Protocol | Derived base URL | Model discovery |
130
+ | --- | --- | --- | --- |
131
+ | 1 | OpenAI compatible | `<root>/v1` | `GET /v1/models` |
132
+ | 2 | Gemini compatible | `<root>/v1beta` | `GET /v1beta/models` |
133
+ | 3 | Anthropic compatible | `<root>` | `GET /v1/models?limit=1000` (best effort) |
114
134
 
115
- Local and private addresses (`localhost`, `127.0.0.1`, `10.*`, `192.168.*`, `172.16-31.*`, `.local`, `.lan`) default to `http://`; everything else defaults to `https://`. Without an explicit scheme, each compatible endpoint is also tried with the alternate scheme.
135
+ The scheme (`http` or `https`) and any path prefix come from the normalized root. For example, with `https://proxy.example.com`, the OpenAI base URL is `https://proxy.example.com/v1`.
116
136
 
117
- ### Fallback when discovery fails
137
+ If you entered a bare host without a scheme, all three protocols are also tried with the alternate scheme, for at most six probes. OpenAI candidates run first, then Gemini, then Anthropic.
118
138
 
119
- The plugin first tries every compatible endpoint automatically. After that:
139
+ When discovery succeeds, the selected base URL, protocol, and model metadata are saved. The models are immediately available in `/model`.
120
140
 
121
- 1. If **any** endpoint returned 401/403, the key is the more likely problem:
122
- - The plugin prompts for the key once more;
123
- - It retries every endpoint;
124
- - If authentication still fails, login aborts and **nothing is saved**.
125
- 2. If there are only other failures (404, timeout, format error, etc.) and no endpoint returned a model list:
126
- - The plugin reports the failure for each endpoint and probes `/healthz` to check whether the service is CLIProxyAPI;
127
- - It shows an endpoint picker:
128
- - Retry OpenAI compatible: `https://<domain>/v1`
129
- - Anthropic compatible: `https://<domain>`
130
- - Gemini compatible: `https://<domain>/v1beta`
131
- - Custom compatible endpoint (enter a full base URL and choose a protocol)
132
- 3. If the selected endpoint still returns no model list, you can enter model IDs manually (comma or space separated, or leave empty).
133
- 4. If every endpoint returns HTTP 200 with an empty model list, the picker is skipped and you go straight to manual input (usually because the upstream account has no available credentials).
141
+ ### If discovery fails
134
142
 
135
- An Anthropic-compatible endpoint does not always expose a model list. If `/v1/models` returns 404/405, automatic discovery skips it; after selecting that endpoint, enter model IDs manually. Gemini-compatible endpoints are probed at `/v1beta/models`.
143
+ 1. **No endpoint returned models, and at least one returned 401/403:** the key is the likely problem. The plugin asks for the key again, retries every endpoint, and aborts without saving anything if authentication still fails.
144
+ 2. **No endpoint returned models, and the failures were other errors (404, timeout, format error, etc.):** the plugin reports each failure, probes `/healthz` to check whether the service is CLIProxyAPI, and shows an endpoint picker:
145
+ - Retry OpenAI compatible: `<root>/v1`
146
+ - Anthropic compatible: `<root>`
147
+ - Gemini compatible: `<root>/v1beta`
148
+ - Custom compatible endpoint: enter a full base URL and choose a protocol
149
+ 3. **An endpoint responded successfully with an empty model list:** the picker is skipped and you are asked for model IDs manually. This usually means the upstream account has no available credentials.
150
+ 4. **The selected endpoint still returns no model list:** enter model IDs manually, separated by commas or spaces. You can leave this empty and add models later.
151
+
152
+ An Anthropic-compatible endpoint does not always expose a model list. If its list request returns 404/405/501, automatic discovery continues; after selecting that endpoint, enter model IDs manually.
136
153
 
137
154
  ---
138
155
 
139
156
  ## `/cliproxy` command
140
157
 
141
158
  ```text
142
- /cliproxy Show the current config, model count and last error
159
+ /cliproxy Show the current endpoint, protocol, model count, and last error
143
160
  /cliproxy refresh Refresh the model list immediately
144
161
  /cliproxy clear Delete the saved config and its backup
145
162
  ```
146
163
 
147
- The extension registers one top-level command, `/cliproxy`; `refresh` and `clear` are arguments. In the TUI, type `/cliproxy ` (with a trailing space) to see argument completions.
148
-
149
- The model catalog is cached for **5 minutes** by default: opening `/model` does not hit the upstream every time. `/cliproxy refresh` forces a refresh.
164
+ The extension registers one top-level command, `/cliproxy`; `refresh` and `clear` are arguments, not separate slash commands. In the TUI, type `/cliproxy ` (with a trailing space) to see argument completions.
150
165
 
151
- Running `/logout` only removes the credential from pi's `auth.json`; the saved `cliproxy.json` is intentionally kept so a later `/login` can reuse it. While signed out, `/cliproxy` reports that CLIProxy is not signed in instead of showing the old endpoint as active. Use `/cliproxy clear` if you want to remove the saved domain, endpoint and model cache as well.
166
+ The model catalog is cached for **5 minutes**. Opening `/model` normally reuses the recent snapshot; `/cliproxy refresh` forces an upstream refresh.
152
167
 
153
- To reconfigure (new domain or key), run `/login` → `CLIProxy` again. If you switched to a completely different domain and the old models are still visible, run `/reload` so the plugin rebuilds the provider from the new config.
168
+ ### Signing out and reconfiguring
154
169
 
155
- ### Relationship to pi update commands
170
+ `/logout` removes the API key from pi's `auth.json` but keeps `cliproxy.json`, so a later `/login` can reuse the saved domain and endpoint. While signed out, `/cliproxy` reports that CLIProxy is not signed in instead of showing the old endpoint as active.
156
171
 
157
- - **`pi update --models` does not refresh this plugin's model list.**
158
- It creates a temporary ModelRuntime without extensions and refreshes pi's built-in or `models.json` catalog; plugin providers are not included. It does not break the plugin, but `cliproxy/*` models are not updated.
159
- - To refresh plugin models, use `/cliproxy refresh`, open `/model`, or restart pi (interactive startup refreshes dynamic providers).
160
- - **`pi update --extensions`** updates the npm package itself (the plugin code); restart pi after updating.
161
- - To update only this plugin, run `pi update npm:pi-cliproxyapi-autoconnect`.
172
+ Use `/cliproxy clear` to delete the saved domain, endpoint, and model cache. To change the domain or key, run `/login` → **CLIProxy** again. If you switched to a different domain and the previous models are still visible, run `/reload` or restart pi so the provider is rebuilt from the new config.
162
173
 
163
174
  ---
164
175
 
165
176
  ## Files and security
166
177
 
178
+ Paths below use pi's default agent directory, `~/.pi/agent` (on Windows, `%USERPROFILE%\.pi\agent`). If `PI_CODING_AGENT_DIR` is set, pi uses that directory instead.
179
+
167
180
  | Content | Location |
168
181
  | --- | --- |
169
- | API key | `~/.pi/agent/auth.json` (written by pi's login flow) |
170
- | Domain, endpoint, model cache | `~/.pi/agent/cliproxy.json` |
171
- | pi model catalog cache (maintained by pi) | `~/.pi/agent/models-store.json` |
182
+ | API key | `<agent-dir>/auth.json` (written and managed by pi) |
183
+ | Domain, endpoint, protocol, model cache | `<agent-dir>/cliproxy.json` |
184
+ | pi model catalog cache | `<agent-dir>/models-store.json` (maintained by pi) |
185
+
186
+ The API key is stored by pi's login flow in `auth.json`. This extension does **not** write the key to `cliproxy.json`.
172
187
 
173
188
  Example `cliproxy.json`:
174
189
 
@@ -198,49 +213,52 @@ Example `cliproxy.json`:
198
213
 
199
214
  Notes:
200
215
 
201
- - Since 1.1.0, complete model metadata (`reasoning` / `input` / `cost` / `contextWindow` / `maxTokens`) is written directly to `cliproxy.json`, not just model IDs.
202
- - The previous version is saved as `cliproxy.json.bak` before each write, for manual recovery.
203
- - The plugin never writes the key to `cliproxy.json` and never prints it to logs.
204
- - `/logout` removes the credential from `auth.json` but keeps `cliproxy.json`, so the saved endpoint and model cache can be reused after signing in again. While signed out, `/cliproxy` reports that CLIProxy is not signed in; run `/cliproxy clear` to delete the saved config.
205
- - The key prompt is **not masked** in pi's current TUI (pi renders `secret` and normal text prompts the same way). Be aware of your surroundings.
206
- - Removing the plugin does not remove credentials from `auth.json`. To clean up, run `/logout` in pi and select CLIProxy, or edit `auth.json` manually.
216
+ - The previous config is saved as `cliproxy.json.bak` before each write, for manual recovery.
217
+ - `/logout` removes the credential from `auth.json` but keeps `cliproxy.json`; use `/cliproxy clear` to delete the saved config as well.
218
+ - Removing the extension does not by itself remove credentials from `auth.json`. Run `/logout` before uninstalling, or edit `auth.json` manually.
219
+ - Treat `auth.json` as sensitive. Do not commit it, share it, or include it in bug reports.
207
220
 
208
221
  ---
209
222
 
210
223
  ## Model capabilities
211
224
 
212
- `/v1/models` only returns model IDs (and possibly `owned_by`). It does not include context length, image support or reasoning support.
225
+ Model list endpoints usually return only model IDs and, sometimes, an owner. They do not reliably include context length, image support, or reasoning support.
213
226
 
214
- The plugin resolves capability fields (`name`, `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`) in this order:
227
+ The extension resolves capability fields (`name`, `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`) in this order:
215
228
 
216
- 1. A model with the same ID in `~/.pi/agent/models.json` (explicit user config, highest priority);
217
- 2. Metadata already stored in `cliproxy.json`;
218
- 3. A model with the same ID cached by pi in `~/.pi/agent/models-store.json` (preserves information when upgrading from an older version);
219
- 4. pi's built-in model catalog (after stripping prefixes such as `cn:`, `global:` and `models/`);
220
- 5. Conservative guesses based on the model name.
229
+ 1. The same model ID in `<agent-dir>/models.json` (explicit user config, highest priority)
230
+ 2. Metadata already stored in `cliproxy.json`
231
+ 3. The same model ID cached by pi in `<agent-dir>/models-store.json`
232
+ 4. pi's built-in model catalog (after removing prefixes such as `cn:`, `global:`, and `models/`)
233
+ 5. Conservative guesses based on the model name and protocol
221
234
 
222
- In other words, if you previously hand-wrote a provider pointing at the same CLIProxyAPI instance, the new `cliproxy` provider inherits the more accurate metadata; upgrading from 1.0.x does not lose it either.
235
+ This means an existing hand-written provider for the same CLIProxyAPI instance can supply more accurate metadata, and upgrading from an older version does not lose it.
223
236
 
224
- When no metadata is available, the plugin uses conservative guesses:
237
+ When no metadata is available, the guesses are:
225
238
 
226
- - `claude*` / Anthropic protocol: 200K context, 64K max output;
227
- - `gemini*` / Gemini protocol: 1M context, 64K max output;
228
- - `gpt-5*` / `gpt-6*`: 272K context, 128K max output;
229
- - everything else: 128K context, 32K max output;
230
- - text input only, `reasoning` disabled, cost set to 0.
239
+ - `claude*` or Anthropic protocol: 200K context, 64K max output
240
+ - `gemini*` or Gemini protocol: 1M context, 65,536 max output
241
+ - `gpt-5*`, `gpt-6*`, `gpt-7*`: 272K context, 128K max output
242
+ - `o1`–`o9`: 200K context, 100K max output
243
+ - everything else: 128K context, 32K max output
244
+ - text input only, reasoning disabled, cost set to 0
231
245
 
232
- If a model's real capabilities differ:
233
-
234
- - Add its metadata to `~/.pi/agent/models.json` (the plugin inherits it); or
235
- - Edit `guessLimits()` / `toModel()` in `index.ts` and run `/reload`.
246
+ If a model's real capabilities differ, add its metadata to `<agent-dir>/models.json`; the extension will inherit it. Alternatively, edit `guessLimits()` or `toModel()` in `index.ts` and run `/reload`.
236
247
 
237
248
  ---
238
249
 
239
250
  ## Troubleshooting
240
251
 
241
- ### 401 / Invalid API key
252
+ ### The extension does not appear after installation
253
+
254
+ - Run `pi list` and confirm that `npm:pi-cliproxyapi-autoconnect` is present.
255
+ - Restart pi, or run `/reload`.
256
+ - Check that pi is version 1.2.0 or newer.
257
+ - Check the startup diagnostics for extension load errors.
242
258
 
243
- CLIProxyAPI's client key lives in `access.api-keys` in the v8 config (the top-level `api-keys` in older versions). Check:
259
+ ### 401 / invalid API key
260
+
261
+ The client key lives in `access.api-keys` in the CLIProxyAPI v8 config (the top-level `api-keys` in older versions):
244
262
 
245
263
  ```yaml
246
264
  access:
@@ -248,25 +266,21 @@ access:
248
266
  - sk-your-real-key
249
267
  ```
250
268
 
251
- `/v1/models` requires authentication by default, unless the server has no keys configured at all.
252
-
253
- Since 1.2.0, login tries every compatible endpoint first (OpenAI first):
269
+ `/v1/models` requires authentication unless the server has no keys configured.
254
270
 
255
- - If an endpoint returns models, it is used immediately;
256
- - If no endpoint returns models and at least one returned 401/403, the plugin prompts for the key again and retries every endpoint;
257
- - If authentication still fails, login aborts and does not save the config.
271
+ Login tries every compatible endpoint first. If no endpoint returns models and at least one returns 401/403, the plugin prompts for the key again and retries. If authentication still fails, login aborts and does not save the config.
258
272
 
259
273
  ### 403 `unsafe_example_api_key`
260
274
 
261
- CLIProxyAPI detected that the example key (`your-api-key-1`, etc.) is still in use. Replace `access.api-keys` with a real key and restart CLIProxyAPI.
275
+ CLIProxyAPI detected that an example key (`your-api-key-1`, etc.) is still in use. Replace `access.api-keys` with a real key and restart CLIProxyAPI.
262
276
 
263
277
  ### `/v1/models` returns an empty list
264
278
 
265
- This is a valid result: there are currently no available upstream credentials, or all of them are cooling down. Sign in to or configure the upstream accounts in CLIProxyAPI, then run `/cliproxy refresh`.
279
+ This is a valid response: there may be no available upstream credentials, or all of them may be cooling down. Configure or sign in to the upstream accounts in CLIProxyAPI, then run `/cliproxy refresh`.
266
280
 
267
- ### Only `/healthz` works; `/v1/models` returns 404
281
+ ### `/healthz` works but `/v1/models` returns 404
268
282
 
269
- CLIProxyAPI itself does not support a path prefix. If nginx/Caddy is in front and adds a prefix, make the reverse proxy remove it, for example:
283
+ CLIProxyAPI itself expects to be served at the root path. If nginx or Caddy adds a path prefix, configure the reverse proxy to strip it before forwarding. For example:
270
284
 
271
285
  ```nginx
272
286
  location /cliproxy/ {
@@ -274,27 +288,77 @@ location /cliproxy/ {
274
288
  }
275
289
  ```
276
290
 
277
- Alternatively, choose “Custom compatible endpoint” in the plugin and enter the full base URL exposed by the reverse proxy.
291
+ Alternatively, choose **Custom compatible endpoint** in the plugin and enter the exact base URL exposed by the reverse proxy.
278
292
 
279
- ### Streaming disconnects mid-response / long answers time out
293
+ ### Streaming disconnects mid-response
280
294
 
281
295
  CLIProxyAPI recommends increasing nginx's `proxy_read_timeout`. Cloudflare's free-plan 100-second timeout can also truncate long streaming responses.
282
296
 
283
297
  ### No models visible in `/model`
284
298
 
285
- - `/model` only lists models from providers with configured authentication; complete `/login` first.
286
- - Run `/cliproxy` to check the model count and last error.
287
- - Run `/cliproxy refresh` to retry.
288
- - Confirm that `pi --list-models` shows `cliproxy/*`.
299
+ - `/model` lists models only from providers with configured authentication. Complete `/login` first.
300
+ - Run `/cliproxy` to check the endpoint, protocol, model count, and last error.
301
+ - Run `/cliproxy refresh` to retry discovery.
302
+ - Run `pi --list-models` and confirm that `cliproxy/*` entries exist.
303
+
304
+ ### The same models appear twice
305
+
306
+ If `/model` shows both `cliproxy/*` and `cliproxyapi/*` entries, both this extension and the separate `@router-for-me/pi-cliproxyapi-provider` package are installed. They are independent providers. Remove the one you do not need:
307
+
308
+ ```bash
309
+ pi remove npm:@router-for-me/pi-cliproxyapi-provider
310
+ ```
311
+
312
+ or
313
+
314
+ ```bash
315
+ pi remove npm:pi-cliproxyapi-autoconnect
316
+ ```
317
+
318
+ Restart pi afterward.
319
+
320
+ ### Models look stale after changing the domain
321
+
322
+ Run `/reload`, or restart pi. The model list is also refreshed whenever `/model` is opened and the cached snapshot is older than five minutes.
323
+
324
+ ---
325
+
326
+ ## Development
327
+
328
+ The published npm tarball contains the full extension source (`index.ts`), `README.md`, `LICENSE`, and `package.json`. There is no build step and no compiled output.
329
+
330
+ To try the published source without adding it to pi's settings:
331
+
332
+ ```bash
333
+ npm pack pi-cliproxyapi-autoconnect
334
+ tar -xzf pi-cliproxyapi-autoconnect-*.tgz
335
+ pi --extension ./package/index.ts
336
+ ```
337
+
338
+ The extension depends only on packages supplied by pi at runtime:
339
+
340
+ - `@earendil-works/pi-ai`
341
+ - `@earendil-works/pi-coding-agent`
342
+
343
+ Core implementation points in `index.ts`:
289
344
 
290
- ### Models look wrong after changing the domain
345
+ - `runLogin()` — domain, key, endpoint discovery, and fallback
346
+ - `refreshProviderModels()` — startup, `/model`, and `/cliproxy refresh` refreshes
347
+ - `buildProvider()` — registers the native pi-ai provider; `apiKey.login` makes it appear in `/login`
291
348
 
292
- Run `/reload`, or restart pi after editing the plugin. The model list refreshes whenever `/model` is opened.
349
+ CLIProxyAPI reference: <https://github.com/router-for-me/CLIProxyAPI>
293
350
 
294
351
  ---
295
352
 
296
353
  ## Changelog
297
354
 
355
+ ### 1.2.5
356
+
357
+ - Documentation and metadata release.
358
+ - Made `pi install npm:pi-cliproxyapi-autoconnect` the documented installation path and removed local-directory and script instructions.
359
+ - Standardized command examples for a public audience.
360
+ - Clarified update/uninstall behavior, endpoint normalization, discovery fallback, model capability overrides, and troubleshooting.
361
+
298
362
  ### 1.2.4
299
363
 
300
364
  - Added argument completions for `/cliproxy`: typing `/cliproxy ` now suggests `refresh` and `clear` in the TUI.
@@ -308,53 +372,34 @@ Run `/reload`, or restart pi after editing the plugin. The model list refreshes
308
372
 
309
373
  ### 1.2.2
310
374
 
311
- - Rewrote this README in English for the npm package page and the pi package gallery.
375
+ - Rewrote the README in English for the npm package page and the pi package gallery.
312
376
  - Translated the npm package description to English.
313
377
  - The pi TUI remains fully English.
314
378
 
315
379
  ### 1.2.1
316
380
 
317
- - All pi TUI strings are now English: login prompts, endpoint picker, errors and `/cliproxy` output.
318
- - The provider display name remains `CLIProxy`; the `/login` entry, `/cliproxy` command and `cliproxy/` model prefix are unchanged.
381
+ - All pi TUI strings are now English: login prompts, endpoint picker, errors, and `/cliproxy` output.
382
+ - The provider display name remains `CLIProxy`; the `/login` entry, `/cliproxy` command, and `cliproxy/` model prefix are unchanged.
319
383
 
320
384
  ### 1.2.0
321
385
 
322
- - Renamed the package from `pi-cliproxy` to `pi-cliproxyapi-autoconnect`; the provider ID, `cliproxy.json`, `/cliproxy` command and `cliproxy/` model prefix are unchanged.
386
+ - Renamed the package from `pi-cliproxy` to `pi-cliproxyapi-autoconnect`; the provider ID, `cliproxy.json`, `/cliproxy` command, and `cliproxy/` model prefix are unchanged.
323
387
  - Login now tries every compatible endpoint automatically: **OpenAI → Gemini → Anthropic**, OpenAI first; the first non-empty model list wins.
324
- - A bare domain also tries both https and http for every protocol, for up to 6 candidates.
325
- - Best-effort discovery of Anthropic's `/v1/models`; if the endpoint is missing (404/405), fall back to manual model IDs instead of skipping Anthropic entirely.
326
- - When every endpoint fails and at least one returned 401/403, the plugin asks for the key again. When every endpoint returns an empty list, it skips the endpoint picker and goes straight to manual input.
327
- - `/cliproxy refresh` silently keeps the cache when the Anthropic endpoint has no model list; it does not persist a refresh error in that case.
388
+ - A bare domain also tries both https and http for every protocol, for up to six candidates.
389
+ - Added best-effort discovery of Anthropic's `/v1/models`; if the endpoint is missing (404/405/501), fall back to manual model IDs instead of skipping Anthropic entirely.
390
+ - When every endpoint fails and at least one returned 401/403, the plugin asks for the key again. When an endpoint returns an empty list, it skips the endpoint picker and goes straight to manual input.
391
+ - `/cliproxy refresh` keeps the cache when the Anthropic endpoint has no model list; it does not persist a refresh error in that case.
328
392
 
329
393
  ### 1.1.0
330
394
 
331
395
  - On 401/403 during login, prompt for the key again instead of incorrectly entering the endpoint picker; if the second attempt fails, abort without saving the config.
332
396
  - `cliproxy.json` now stores complete model metadata (reasoning / input / cost / contextWindow / maxTokens) and keeps a `.bak` backup.
333
- - Model refresh now has a 5-minute TTL; `/cliproxy refresh` still forces a refresh.
397
+ - Model refresh now has a five-minute TTL; `/cliproxy refresh` still forces a refresh.
334
398
  - Capability metadata now also comes from `models-store.json` and pi's built-in catalog, so upgrading from an older config does not lose information.
335
399
  - Refresh failures persist `lastError` to the config, so `/cliproxy` can show the last error after a restart.
336
400
 
337
401
  ---
338
402
 
339
- ## Development and debugging
340
-
341
- ```powershell
342
- # Load a local file temporarily (does not write settings)
343
- pi --extension F:\Desktop\pi-cliproxyapi-autoconnect\index.ts
344
-
345
- # List models only
346
- pi --list-models
347
- ```
348
-
349
- The plugin only depends on pi's host-provided peer packages and has no third-party runtime dependencies:
350
-
351
- - `@earendil-works/pi-ai`
352
- - `@earendil-works/pi-coding-agent`
353
-
354
- The core implementation is in `index.ts`:
403
+ ## License
355
404
 
356
- - `runLogin()`: domain + key + model discovery + fallback;
357
- - `refreshProviderModels()`: dynamic refresh on startup, `/model` and `/cliproxy refresh`;
358
- - `buildProvider()`: registers the native pi-ai provider (`apiKey.login` makes it appear in `/login`).
359
-
360
- CLIProxyAPI reference: <https://github.com/router-for-me/CLIProxyAPI>
405
+ [MIT](./LICENSE)
package/index.ts CHANGED
@@ -638,7 +638,7 @@ async function fetchOpenAIModels(baseUrl: string, apiKey: string, signal: AbortS
638
638
  headers: {
639
639
  Accept: "application/json",
640
640
  Authorization: `Bearer ${apiKey}`,
641
- "User-Agent": "pi-cliproxyapi-autoconnect/1.2.4",
641
+ "User-Agent": "pi-cliproxyapi-autoconnect/1.2.5",
642
642
  },
643
643
  signal: requestSignal,
644
644
  });
@@ -662,7 +662,7 @@ async function fetchGeminiModels(baseUrl: string, apiKey: string, signal: AbortS
662
662
  const { signal: requestSignal, cleanup } = abortSignalWithTimeout(signal, REQUEST_TIMEOUT_MS);
663
663
  try {
664
664
  const response = await fetch(url, {
665
- headers: { Accept: "application/json", "User-Agent": "pi-cliproxyapi-autoconnect/1.2.4" },
665
+ headers: { Accept: "application/json", "User-Agent": "pi-cliproxyapi-autoconnect/1.2.5" },
666
666
  signal: requestSignal,
667
667
  });
668
668
  if (!response.ok) {
@@ -703,7 +703,7 @@ async function fetchAnthropicModels(baseUrl: string, apiKey: string, signal: Abo
703
703
  // Anthropic's x-api-key header; sending both is harmless upstream.
704
704
  Authorization: `Bearer ${apiKey}`,
705
705
  "anthropic-version": "2023-06-01",
706
- "User-Agent": "pi-cliproxyapi-autoconnect/1.2.4",
706
+ "User-Agent": "pi-cliproxyapi-autoconnect/1.2.5",
707
707
  },
708
708
  signal: requestSignal,
709
709
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-cliproxyapi-autoconnect",
3
- "version": "1.2.4",
4
- "description": "CLIProxyAPI auto-connect provider for pi: sign in with a bound domain and API key, automatically discover OpenAI/Gemini/Anthropic-compatible endpoints, and register models in /model.",
3
+ "version": "1.2.5",
4
+ "description": "Independent CLIProxyAPI provider for pi: sign in with your CLIProxyAPI domain and API key, auto-discover OpenAI-, Gemini-, or Anthropic-compatible endpoints, and register models in /model.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "engines": {