pi-zengate-models 1.0.1 → 1.0.4

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.2] - 2026-11-04
4
+
5
+ - Read `baseUrl` and `apiKey` from the `opencode2api` provider in
6
+ `<agent-dir>/models.json` when the environment and `zengate.json` are empty.
7
+ A machine the gateway sync already prepared needs no second copy, and the
8
+ session warning stops for those machines.
9
+ - Name all three sources in that warning.
10
+
11
+ ## [Unreleased]
12
+
13
+ - Install without a version tag, so `pi update --extensions` follows releases.
14
+ - Add `scripts/setup.ps1` and `scripts/setup.sh`. They ask for the gateway URL
15
+ and key, write `<agent-dir>/zengate.json` without a BOM, and move a stale
16
+ `models.json` that holds only the static provider.
17
+ - Document the text-editor route for a machine without an agent.
18
+
3
19
  ## [1.0.1] - 2026-11-04
4
20
 
5
21
  - Remove the built-in gateway URL. Every machine sets `OPENCODE2API_BASE_URL`
package/README.md CHANGED
@@ -28,10 +28,14 @@ pi install npm:pi-zengate-models
28
28
  From git, or from a local checkout:
29
29
 
30
30
  ```bash
31
- pi install git:github.com/ham-zax/pi-zengate@v1.0.1
31
+ pi install git:github.com/ham-zax/pi-zengate
32
32
  pi install /path/to/pi-zengate
33
33
  ```
34
34
 
35
+ Install without a tag. A tag in the install command, such as `@v1.0.2`, freezes
36
+ that machine on one version, and `pi update --extensions` then re-fetches the same
37
+ tag forever. Without a tag, updates follow the newest release.
38
+
35
39
  ## Configure
36
40
 
37
41
  Every machine needs its own gateway URL and key. Set them in the environment:
@@ -53,8 +57,35 @@ or in `<agent-dir>/zengate.json`, which avoids environment variables:
53
57
  ```
54
58
 
55
59
  `<agent-dir>` is `~/.pi/agent` by default, or `PI_CODING_AGENT_DIR` when set.
56
- The environment wins over the file. Without a URL the extension registers no
57
- provider and shows one warning per session.
60
+ The extension also reads `providers.opencode2api.baseUrl` and `.apiKey` from
61
+ `<agent-dir>/models.json`, so a machine the gateway sync prepared needs no second
62
+ copy. Precedence is environment, then `zengate.json`, then `models.json`. Without
63
+ any URL the extension registers no provider and warns once per session.
64
+
65
+ ## Setup helpers
66
+
67
+ The fastest manual way is a text editor. On Windows:
68
+
69
+ ```powershell
70
+ notepad "$env:USERPROFILE\.pi\agent\zengate.json"
71
+ ```
72
+
73
+ Paste the two fields, save, restart Pi. On Linux, macOS or WSL create
74
+ `~/.pi/agent/zengate.json` the same way.
75
+
76
+ Two scripts ask for the URL and the key and then write the file, so neither
77
+ script contains a secret:
78
+
79
+ ```powershell
80
+ iex (irm "<raw URL of scripts/setup.ps1>") # Windows
81
+ ```
82
+
83
+ ```bash
84
+ curl -fsSL "<raw URL of scripts/setup.sh>" | bash # Linux, macOS, WSL
85
+ ```
86
+
87
+ Both scripts write the file with mode `0600` and print the model count. A
88
+ `models.json` that holds only `opencode2api` moves to `models.json.disabled`.
58
89
 
59
90
  ## Verify
60
91
 
@@ -147,6 +147,10 @@ export function configPath(): string {
147
147
  return join(agentDir(), "zengate.json");
148
148
  }
149
149
 
150
+ export function modelsConfigPath(): string {
151
+ return join(agentDir(), "models.json");
152
+ }
153
+
150
154
  export function cachePath(): string {
151
155
  return join(agentDir(), "cache", "zengate-models.json");
152
156
  }
@@ -165,25 +169,49 @@ function normalizeBaseUrl(value: string): string {
165
169
  }
166
170
 
167
171
  /**
168
- * Settings precedence: environment, then <agent-dir>/zengate.json.
169
- * The config file lets a machine skip environment variables. This package ships
170
- * no endpoint: every machine supplies its own.
172
+ * A machine prepared by the gateway sync already holds the endpoint and the key
173
+ * in models.json. Read them so the client needs no second copy of either.
174
+ */
175
+ function gatewayFromModelsConfig(): { baseUrl?: string; apiKey?: string } {
176
+ const file = readJson(modelsConfigPath()) ?? {};
177
+ const providers = file.providers;
178
+ const provider =
179
+ providers && typeof providers === "object"
180
+ ? (providers as Record<string, unknown>)[PROVIDER_ID]
181
+ : undefined;
182
+ if (!provider || typeof provider !== "object") return {};
183
+ const record = provider as Record<string, unknown>;
184
+ const baseUrl =
185
+ typeof record.baseUrl === "string" && record.baseUrl.trim() ? record.baseUrl : undefined;
186
+ const apiKey =
187
+ typeof record.apiKey === "string" && record.apiKey.trim() ? record.apiKey.trim() : undefined;
188
+ return { baseUrl, apiKey };
189
+ }
190
+
191
+ /**
192
+ * Settings precedence: environment, then <agent-dir>/zengate.json, then the
193
+ * `opencode2api` provider in <agent-dir>/models.json. The last source means a
194
+ * machine the gateway sync already prepared needs no extra file. This package
195
+ * ships no endpoint: every machine supplies its own.
171
196
  */
172
197
  export function readSettings(): { baseUrl?: string; apiKey?: string; keySource: string } {
173
198
  const file = readJson(configPath()) ?? {};
174
199
  const fileBase = typeof file.baseUrl === "string" && file.baseUrl.trim() ? file.baseUrl : undefined;
175
200
  const fileKey = typeof file.apiKey === "string" && file.apiKey.trim() ? file.apiKey.trim() : undefined;
201
+ const synced = gatewayFromModelsConfig();
176
202
  const envBase = process.env[BASE_URL_ENV];
177
203
  const envKey = process.env[KEY_ENV]?.trim();
178
- const base = envBase || fileBase;
204
+ const base = envBase || fileBase || synced.baseUrl;
179
205
  return {
180
206
  baseUrl: base ? normalizeBaseUrl(base) : undefined,
181
- apiKey: envKey || fileKey,
182
- keySource: envKey ? KEY_ENV : fileKey ? "zengate.json" : "none",
207
+ apiKey: envKey || fileKey || synced.apiKey,
208
+ keySource: envKey ? KEY_ENV : fileKey ? "zengate.json" : synced.apiKey ? "models.json" : "none",
183
209
  };
184
210
  }
185
211
 
186
- const configureHint = (): string => `Set ${BASE_URL_ENV} or baseUrl in ${configPath()} to your gateway /v1 URL.`;
212
+ const configureHint = (): string =>
213
+ `No gateway endpoint found. Set ${BASE_URL_ENV}, baseUrl in ${configPath()}, ` +
214
+ `or providers.${PROVIDER_ID}.baseUrl in ${modelsConfigPath()}.`;
187
215
 
188
216
  export default async function (pi: ExtensionAPI) {
189
217
  const settings = readSettings();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-zengate-models",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "Pi provider extension that discovers free models and their metadata from an OpenAI-compatible gateway catalog, with a local cache and no scheduler.",
5
5
  "keywords": [
6
6
  "pi-package",