pi-cliproxyapi-autoconnect 1.2.3 → 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 +219 -167
  2. package/index.ts +12 -3
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,172 +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.
28
38
 
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.
39
+ Confirm that pi has recorded the package:
30
40
 
31
- ### Option B: install from a local directory
41
+ ```bash
42
+ pi list
43
+ ```
44
+
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.
82
+
83
+ ### Migrating from `pi-cliproxy`
70
84
 
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.
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.
72
86
 
73
- ```powershell
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
83
97
 
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:
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.
94
105
 
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
- ```
106
+ ### Domain input
100
107
 
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>`.
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.
104
109
 
105
- ### Address formatting
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` |
106
118
 
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:
119
+ Trailing slashes and common suffixes such as `/v1`, `/v1beta`, `/v1/models`, and `/v1beta/models` are removed. A reverse-proxy path prefix is preserved.
108
120
 
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) |
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.
122
+
123
+ ---
114
124
 
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.
125
+ ## How discovery works
116
126
 
117
- ### Fallback when discovery fails
127
+ The plugin probes the compatible endpoints in this order and uses the first one that returns a non-empty model list:
118
128
 
119
- The plugin first tries every compatible endpoint automatically. After that:
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) |
120
134
 
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).
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`.
134
136
 
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`.
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.
138
+
139
+ When discovery succeeds, the selected base URL, protocol, and model metadata are saved. The models are immediately available in `/model`.
140
+
141
+ ### If discovery fails
142
+
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 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.
148
165
 
149
- 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.
150
167
 
151
- 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
152
169
 
153
- ### 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.
154
171
 
155
- - **`pi update --models` does not refresh this plugin's model list.**
156
- 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.
157
- - To refresh plugin models, use `/cliproxy refresh`, open `/model`, or restart pi (interactive startup refreshes dynamic providers).
158
- - **`pi update --extensions`** updates the npm package itself (the plugin code); restart pi after updating.
159
- - 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.
160
173
 
161
174
  ---
162
175
 
163
176
  ## Files and security
164
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
+
165
180
  | Content | Location |
166
181
  | --- | --- |
167
- | API key | `~/.pi/agent/auth.json` (written by pi's login flow) |
168
- | Domain, endpoint, model cache | `~/.pi/agent/cliproxy.json` |
169
- | 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`.
170
187
 
171
188
  Example `cliproxy.json`:
172
189
 
@@ -196,49 +213,52 @@ Example `cliproxy.json`:
196
213
 
197
214
  Notes:
198
215
 
199
- - Since 1.1.0, complete model metadata (`reasoning` / `input` / `cost` / `contextWindow` / `maxTokens`) is written directly to `cliproxy.json`, not just model IDs.
200
- - The previous version is saved as `cliproxy.json.bak` before each write, for manual recovery.
201
- - The plugin never writes the key to `cliproxy.json` and never prints it to logs.
202
- - `/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.
203
- - 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.
204
- - 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.
205
220
 
206
221
  ---
207
222
 
208
223
  ## Model capabilities
209
224
 
210
- `/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.
211
226
 
212
- 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:
213
228
 
214
- 1. A model with the same ID in `~/.pi/agent/models.json` (explicit user config, highest priority);
215
- 2. Metadata already stored in `cliproxy.json`;
216
- 3. A model with the same ID cached by pi in `~/.pi/agent/models-store.json` (preserves information when upgrading from an older version);
217
- 4. pi's built-in model catalog (after stripping prefixes such as `cn:`, `global:` and `models/`);
218
- 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
219
234
 
220
- 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.
221
236
 
222
- When no metadata is available, the plugin uses conservative guesses:
237
+ When no metadata is available, the guesses are:
223
238
 
224
- - `claude*` / Anthropic protocol: 200K context, 64K max output;
225
- - `gemini*` / Gemini protocol: 1M context, 64K max output;
226
- - `gpt-5*` / `gpt-6*`: 272K context, 128K max output;
227
- - everything else: 128K context, 32K max output;
228
- - 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
229
245
 
230
- If a model's real capabilities differ:
231
-
232
- - Add its metadata to `~/.pi/agent/models.json` (the plugin inherits it); or
233
- - 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`.
234
247
 
235
248
  ---
236
249
 
237
250
  ## Troubleshooting
238
251
 
239
- ### 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.
240
258
 
241
- 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):
242
262
 
243
263
  ```yaml
244
264
  access:
@@ -246,25 +266,21 @@ access:
246
266
  - sk-your-real-key
247
267
  ```
248
268
 
249
- `/v1/models` requires authentication by default, unless the server has no keys configured at all.
250
-
251
- Since 1.2.0, login tries every compatible endpoint first (OpenAI first):
269
+ `/v1/models` requires authentication unless the server has no keys configured.
252
270
 
253
- - If an endpoint returns models, it is used immediately;
254
- - If no endpoint returns models and at least one returned 401/403, the plugin prompts for the key again and retries every endpoint;
255
- - 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.
256
272
 
257
273
  ### 403 `unsafe_example_api_key`
258
274
 
259
- 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.
260
276
 
261
277
  ### `/v1/models` returns an empty list
262
278
 
263
- 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`.
264
280
 
265
- ### Only `/healthz` works; `/v1/models` returns 404
281
+ ### `/healthz` works but `/v1/models` returns 404
266
282
 
267
- 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:
268
284
 
269
285
  ```nginx
270
286
  location /cliproxy/ {
@@ -272,27 +288,82 @@ location /cliproxy/ {
272
288
  }
273
289
  ```
274
290
 
275
- 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.
276
292
 
277
- ### Streaming disconnects mid-response / long answers time out
293
+ ### Streaming disconnects mid-response
278
294
 
279
295
  CLIProxyAPI recommends increasing nginx's `proxy_read_timeout`. Cloudflare's free-plan 100-second timeout can also truncate long streaming responses.
280
296
 
281
297
  ### No models visible in `/model`
282
298
 
283
- - `/model` only lists models from providers with configured authentication; complete `/login` first.
284
- - Run `/cliproxy` to check the model count and last error.
285
- - Run `/cliproxy refresh` to retry.
286
- - 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:
287
307
 
288
- ### Models look wrong after changing the domain
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
+ ```
289
317
 
290
- Run `/reload`, or restart pi after editing the plugin. The model list refreshes whenever `/model` is opened.
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`:
344
+
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`
348
+
349
+ CLIProxyAPI reference: <https://github.com/router-for-me/CLIProxyAPI>
291
350
 
292
351
  ---
293
352
 
294
353
  ## Changelog
295
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
+
362
+ ### 1.2.4
363
+
364
+ - Added argument completions for `/cliproxy`: typing `/cliproxy ` now suggests `refresh` and `clear` in the TUI.
365
+ - The extension still registers a single top-level command; subcommands remain arguments rather than separate slash commands.
366
+
296
367
  ### 1.2.3
297
368
 
298
369
  - `/cliproxy` now checks whether CLIProxy is actually signed in. After `/logout` it reports “not signed in” instead of displaying the previous endpoint and model count as if they were active.
@@ -301,53 +372,34 @@ Run `/reload`, or restart pi after editing the plugin. The model list refreshes
301
372
 
302
373
  ### 1.2.2
303
374
 
304
- - 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.
305
376
  - Translated the npm package description to English.
306
377
  - The pi TUI remains fully English.
307
378
 
308
379
  ### 1.2.1
309
380
 
310
- - All pi TUI strings are now English: login prompts, endpoint picker, errors and `/cliproxy` output.
311
- - 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.
312
383
 
313
384
  ### 1.2.0
314
385
 
315
- - 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.
316
387
  - Login now tries every compatible endpoint automatically: **OpenAI → Gemini → Anthropic**, OpenAI first; the first non-empty model list wins.
317
- - A bare domain also tries both https and http for every protocol, for up to 6 candidates.
318
- - 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.
319
- - 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.
320
- - `/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.
321
392
 
322
393
  ### 1.1.0
323
394
 
324
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.
325
396
  - `cliproxy.json` now stores complete model metadata (reasoning / input / cost / contextWindow / maxTokens) and keeps a `.bak` backup.
326
- - 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.
327
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.
328
399
  - Refresh failures persist `lastError` to the config, so `/cliproxy` can show the last error after a restart.
329
400
 
330
401
  ---
331
402
 
332
- ## Development and debugging
333
-
334
- ```powershell
335
- # Load a local file temporarily (does not write settings)
336
- pi --extension F:\Desktop\pi-cliproxyapi-autoconnect\index.ts
337
-
338
- # List models only
339
- pi --list-models
340
- ```
341
-
342
- The plugin only depends on pi's host-provided peer packages and has no third-party runtime dependencies:
343
-
344
- - `@earendil-works/pi-ai`
345
- - `@earendil-works/pi-coding-agent`
346
-
347
- The core implementation is in `index.ts`:
403
+ ## License
348
404
 
349
- - `runLogin()`: domain + key + model discovery + fallback;
350
- - `refreshProviderModels()`: dynamic refresh on startup, `/model` and `/cliproxy refresh`;
351
- - `buildProvider()`: registers the native pi-ai provider (`apiKey.login` makes it appear in `/login`).
352
-
353
- 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.3",
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.3" },
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.3",
706
+ "User-Agent": "pi-cliproxyapi-autoconnect/1.2.5",
707
707
  },
708
708
  signal: requestSignal,
709
709
  });
@@ -1255,6 +1255,15 @@ export default function (pi: ExtensionAPI): void {
1255
1255
 
1256
1256
  pi.registerCommand("cliproxy", {
1257
1257
  description: "Show CLIProxy config, refresh models, or clear the saved config",
1258
+ getArgumentCompletions: (argumentPrefix) => {
1259
+ const prefix = argumentPrefix.trim().toLowerCase();
1260
+ const items = [
1261
+ { value: "refresh", label: "refresh", description: "Refresh the CLIProxy model list" },
1262
+ { value: "clear", label: "clear", description: "Delete the saved CLIProxy config and backup" },
1263
+ ];
1264
+ const matches = items.filter((item) => item.value.startsWith(prefix));
1265
+ return matches.length > 0 ? matches : null;
1266
+ },
1258
1267
  handler: async (args, ctx) => {
1259
1268
  const subcommand = args.trim().toLowerCase();
1260
1269
  const config = readConfig();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-cliproxyapi-autoconnect",
3
- "version": "1.2.3",
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": {