@jacobbd/relay-ai 0.8.0 → 0.9.0

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.
@@ -1,5 +1,5 @@
1
1
  // src/config.ts
2
- import { dirname, join as join2 } from "path";
2
+ import { dirname, join as join3 } from "path";
3
3
  import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
4
4
 
5
5
  // src/paths.ts
@@ -43,83 +43,14 @@ function getLegacyConfPath(env = process.env, platform = process.platform) {
43
43
  return join(env.XDG_CONFIG_HOME ?? join(home, ".config"), appName, "config.json");
44
44
  }
45
45
 
46
- // src/config.ts
47
- function readJsonFile(path) {
48
- try {
49
- const parsed = JSON.parse(readFileSync(path, "utf8"));
50
- return parsed && typeof parsed === "object" ? parsed : null;
51
- } catch {
52
- return null;
53
- }
54
- }
55
- function ensureAppHomeMigrated() {
56
- const configPath = getConfigPath();
57
- if (existsSync(configPath)) return;
58
- const legacyConfig = join2(getLegacyAppHome(), "config.json");
59
- if (!existsSync(legacyConfig)) return;
60
- mkdirSync(getAppHome(), { recursive: true, mode: 448 });
61
- copyFileSync(legacyConfig, configPath);
62
- const legacyVertex = join2(getLegacyAppHome(), "vertex-models.json");
63
- const vertexPath = join2(getAppHome(), "vertex-models.json");
64
- if (existsSync(legacyVertex) && !existsSync(vertexPath)) {
65
- copyFileSync(legacyVertex, vertexPath);
66
- }
67
- }
68
- function ensureConfigMigrated() {
69
- ensureAppHomeMigrated();
70
- const configPath = getConfigPath();
71
- if (existsSync(configPath)) return;
72
- const legacyPath = getLegacyConfPath();
73
- if (!existsSync(legacyPath)) return;
74
- const legacy = readJsonFile(legacyPath);
75
- if (!legacy) return;
76
- mkdirSync(dirname(configPath), { recursive: true, mode: 448 });
77
- writeFileSync(configPath, `${JSON.stringify(legacy, null, 2)}
78
- `, { encoding: "utf8", mode: 384 });
79
- try {
80
- renameSync(legacyPath, `${legacyPath}.migrated`);
81
- } catch {
82
- }
83
- }
84
- function readConfig() {
85
- ensureConfigMigrated();
86
- return readJsonFile(getConfigPath()) ?? {};
87
- }
88
- function loadPreferences() {
89
- const config = readConfig();
90
- const lastProvider = config.lastProvider === "opencode" ? "zen" : config.lastProvider;
91
- return {
92
- lastBackend: config.lastBackend,
93
- lastModel: config.lastModel,
94
- lastProvider,
95
- lastCodexProvider: config.lastCodexProvider,
96
- lastCodexModel: config.lastCodexModel,
97
- lastGeminiProvider: config.lastGeminiProvider,
98
- lastGeminiModel: config.lastGeminiModel,
99
- lastAntigravityProvider: config.lastAntigravityProvider,
100
- lastAntigravityModel: config.lastAntigravityModel,
101
- lastClaudeTransparentMode: config.lastClaudeTransparentMode,
102
- recentModelsByProvider: config.recentModelsByProvider,
103
- favoriteModels: config.favoriteModels,
104
- antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,
105
- antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,
106
- appPathOverrides: config.appPathOverrides,
107
- recentLaunchFolders: config.recentLaunchFolders,
108
- server: config.server
109
- };
110
- }
111
-
112
- // src/provider-factory.ts
113
- import { wrapLanguageModel, extractReasoningMiddleware } from "ai";
114
-
115
46
  // src/constants.ts
116
47
  import { homedir as homedir2 } from "os";
117
- import { join as join3 } from "path";
48
+ import { join as join2 } from "path";
118
49
 
119
50
  // package.json
120
51
  var package_default = {
121
52
  name: "@jacobbd/relay-ai",
122
- version: "0.8.0",
53
+ version: "0.9.0",
123
54
  publishConfig: {
124
55
  access: "public"
125
56
  },
@@ -202,10 +133,11 @@ var package_default = {
202
133
  "@types/node": "^22.0.0",
203
134
  "@types/node-forge": "^1.3.14",
204
135
  "@types/ws": "^8.18.1",
205
- "@vitest/coverage-v8": "^2.1.9",
136
+ "@vitest/coverage-v8": "^4.1.10",
206
137
  tsup: "^8.0.0",
207
138
  typescript: "^5.5.0",
208
- vitest: "^2.0.0"
139
+ "vite-node": "^6.0.0",
140
+ vitest: "^4.1.10"
209
141
  },
210
142
  optionalDependencies: {
211
143
  "@napi-rs/keyring": "^1.3.0"
@@ -227,10 +159,81 @@ var package_default = {
227
159
  var CODEX_RESPONSES_LITE_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
228
160
  var CODEX_RESPONSES_LITE_VERSION = "0.144.1";
229
161
  var CODEX_RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
230
- var OPENCODE_CACHE_PATH = join3(homedir2(), ".cache", "opencode", "models.json");
162
+ var OPENCODE_CACHE_PATH = join2(homedir2(), ".cache", "opencode", "models.json");
163
+ var CODEX_SUBAGENT_MODEL_CAP = 1;
231
164
  var VERTEX_ANTHROPIC_NPM = "@ai-sdk/google-vertex/anthropic";
232
165
  var VERSION = package_default.version;
233
166
 
167
+ // src/config.ts
168
+ function readJsonFile(path) {
169
+ try {
170
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
171
+ return parsed && typeof parsed === "object" ? parsed : null;
172
+ } catch {
173
+ return null;
174
+ }
175
+ }
176
+ function ensureAppHomeMigrated() {
177
+ const configPath = getConfigPath();
178
+ if (existsSync(configPath)) return;
179
+ const legacyConfig = join3(getLegacyAppHome(), "config.json");
180
+ if (!existsSync(legacyConfig)) return;
181
+ mkdirSync(getAppHome(), { recursive: true, mode: 448 });
182
+ copyFileSync(legacyConfig, configPath);
183
+ const legacyVertex = join3(getLegacyAppHome(), "vertex-models.json");
184
+ const vertexPath = join3(getAppHome(), "vertex-models.json");
185
+ if (existsSync(legacyVertex) && !existsSync(vertexPath)) {
186
+ copyFileSync(legacyVertex, vertexPath);
187
+ }
188
+ }
189
+ function ensureConfigMigrated() {
190
+ ensureAppHomeMigrated();
191
+ const configPath = getConfigPath();
192
+ if (existsSync(configPath)) return;
193
+ const legacyPath = getLegacyConfPath();
194
+ if (!existsSync(legacyPath)) return;
195
+ const legacy = readJsonFile(legacyPath);
196
+ if (!legacy) return;
197
+ mkdirSync(dirname(configPath), { recursive: true, mode: 448 });
198
+ writeFileSync(configPath, `${JSON.stringify(legacy, null, 2)}
199
+ `, { encoding: "utf8", mode: 384 });
200
+ try {
201
+ renameSync(legacyPath, `${legacyPath}.migrated`);
202
+ } catch {
203
+ }
204
+ }
205
+ function readConfig() {
206
+ ensureConfigMigrated();
207
+ return readJsonFile(getConfigPath()) ?? {};
208
+ }
209
+ function loadPreferences() {
210
+ const config = readConfig();
211
+ const lastProvider = config.lastProvider === "opencode" ? "zen" : config.lastProvider;
212
+ return {
213
+ lastBackend: config.lastBackend,
214
+ lastModel: config.lastModel,
215
+ lastProvider,
216
+ lastCodexProvider: config.lastCodexProvider,
217
+ lastCodexModel: config.lastCodexModel,
218
+ lastGeminiProvider: config.lastGeminiProvider,
219
+ lastGeminiModel: config.lastGeminiModel,
220
+ lastAntigravityProvider: config.lastAntigravityProvider,
221
+ lastAntigravityModel: config.lastAntigravityModel,
222
+ lastClaudeTransparentMode: config.lastClaudeTransparentMode,
223
+ recentModelsByProvider: config.recentModelsByProvider,
224
+ favoriteModels: config.favoriteModels,
225
+ codexSubagentModels: Array.isArray(config.codexSubagentModels) ? config.codexSubagentModels.slice(0, CODEX_SUBAGENT_MODEL_CAP) : void 0,
226
+ antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,
227
+ antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,
228
+ appPathOverrides: config.appPathOverrides,
229
+ recentLaunchFolders: config.recentLaunchFolders,
230
+ server: config.server
231
+ };
232
+ }
233
+
234
+ // src/provider-factory.ts
235
+ import { wrapLanguageModel, extractReasoningMiddleware } from "ai";
236
+
234
237
  // src/oauth/refresh-http.ts
235
238
  async function postOAuthRefresh(url, body, options) {
236
239
  const isJson = options.contentType === "json";
@@ -1710,6 +1713,9 @@ var KEYRING_CHUNK_SIZE = 1200;
1710
1713
  var LEGACY_KEYRING_SERVICE = "opencode-starter";
1711
1714
  var LEGACY_KEYRING_ACCOUNT = "opencode-starter";
1712
1715
  var GLOBAL_OPENCODE_KEYRING_ACCOUNT = "global:opencode";
1716
+ function providerKeyringAccount(providerId) {
1717
+ return `provider:${providerId}`;
1718
+ }
1713
1719
  function oauthProviderIdFromAccount(account) {
1714
1720
  const prefix = "oauth:provider:";
1715
1721
  return account.startsWith(prefix) ? account.slice(prefix.length) : null;
@@ -1801,10 +1807,14 @@ async function readGlobalOpencodeCredential(diag) {
1801
1807
  }
1802
1808
  }
1803
1809
  async function resolveProviderCredential(providerId, authRef, diag) {
1804
- const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
1805
- if (namespaced) return namespaced;
1806
1810
  const parsed = parseAuthRef(authRef);
1807
1811
  if (!parsed) return null;
1812
+ if (parsed.kind === "keyring" && parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {
1813
+ const relayOverride = await readProviderSecret(providerKeyringAccount("opencode"), diag);
1814
+ if (relayOverride) return relayOverride;
1815
+ }
1816
+ const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
1817
+ if (namespaced) return namespaced;
1808
1818
  if (parsed.kind === "env") {
1809
1819
  return readEnvCredential(parsed.varName);
1810
1820
  }
@@ -1814,12 +1824,16 @@ async function resolveProviderCredential(providerId, authRef, diag) {
1814
1824
  return readProviderSecret(parsed.account, diag);
1815
1825
  }
1816
1826
  async function forceRefreshProviderCredential(providerId, authRef, diag) {
1817
- const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
1818
- if (namespaced) return namespaced;
1819
1827
  const parsed = parseAuthRef(authRef);
1820
1828
  if (!parsed || parsed.kind !== "keyring") {
1821
1829
  return resolveProviderCredential(providerId, authRef, diag);
1822
1830
  }
1831
+ if (parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {
1832
+ const relayOverride = await readProviderSecret(providerKeyringAccount("opencode"), diag);
1833
+ if (relayOverride) return relayOverride;
1834
+ }
1835
+ const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
1836
+ if (namespaced) return namespaced;
1823
1837
  const oauthProviderId = oauthProviderIdFromAccount(parsed.account);
1824
1838
  const raw = await readKeyringAccount(parsed.account, diag);
1825
1839
  if (!raw || !oauthProviderId) return decodeProviderSecret(raw);