@route_33/opencode 0.1.2 → 0.1.3
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/README.md +1 -1
- package/dist/index.js +86 -54
- package/dist/tui/index.js +31 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Add to the `plugin` array of your opencode config and restart opencode:
|
|
|
14
14
|
|
|
15
15
|
## Auth
|
|
16
16
|
|
|
17
|
-
Run `opencode auth login` and choose `route_33`, or set the `ROUTE33_API_KEY` environment variable. Without a key, the TUI wizard offers to save one: per-project inside a git workspace, global otherwise. `ROUTE33_BASE_URL` overrides the default gateway URL; `ROUTE33_TUI_PROMPT=0` disables the wizard.
|
|
17
|
+
Run `opencode auth login` and choose `route_33`, or set the `ROUTE33_API_KEY` environment variable. Without a key, the TUI wizard offers to save one: per-project inside a git workspace, global otherwise. A globally stored key applies only outside git workspaces — inside a workspace, keys resolve from the environment, the workspace config, or `.opencode/route33.key` (per-project keys are the metering boundary). `ROUTE33_BASE_URL` overrides the default gateway URL; `ROUTE33_TUI_PROMPT=0` disables the wizard.
|
|
18
18
|
|
|
19
19
|
## License
|
|
20
20
|
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ function readAuthEntry(env = process.env) {
|
|
|
32
32
|
|
|
33
33
|
// src/auth/workspace-key-file.ts
|
|
34
34
|
import * as fs2 from "fs";
|
|
35
|
-
import * as
|
|
35
|
+
import * as path4 from "path";
|
|
36
36
|
|
|
37
37
|
// src/shared/default-base-url.ts
|
|
38
38
|
var DEFAULT_BASE_URL = "https://api.route33.ai/v1";
|
|
@@ -64,6 +64,23 @@ var ENV_ENRICH_CAPS = "ROUTE33_ENRICH_CAPS";
|
|
|
64
64
|
// src/shared/env-strict.ts
|
|
65
65
|
var ENV_STRICT = "ROUTE33_STRICT";
|
|
66
66
|
|
|
67
|
+
// src/shared/git-workspace.ts
|
|
68
|
+
import { existsSync } from "fs";
|
|
69
|
+
import * as path2 from "path";
|
|
70
|
+
function isInsideGitWorktree(startDir) {
|
|
71
|
+
try {
|
|
72
|
+
let dir = path2.resolve(startDir);
|
|
73
|
+
for (; ; ) {
|
|
74
|
+
if (existsSync(path2.join(dir, ".git"))) return true;
|
|
75
|
+
const parent = path2.dirname(dir);
|
|
76
|
+
if (parent === dir) return false;
|
|
77
|
+
dir = parent;
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
67
84
|
// src/shared/logger.ts
|
|
68
85
|
var logger = {
|
|
69
86
|
info: (...args) => {
|
|
@@ -82,18 +99,18 @@ var MODELS_DEV_TTL_MS = 864e5;
|
|
|
82
99
|
|
|
83
100
|
// src/shared/resolve-cache-dir.ts
|
|
84
101
|
import * as os2 from "os";
|
|
85
|
-
import * as
|
|
102
|
+
import * as path3 from "path";
|
|
86
103
|
function resolveCacheDir(env = process.env) {
|
|
87
104
|
const override = env[ENV_CACHE_DIR];
|
|
88
105
|
if (override) return override;
|
|
89
106
|
const xdgCacheHome = env.XDG_CACHE_HOME;
|
|
90
|
-
const base = xdgCacheHome ??
|
|
91
|
-
return
|
|
107
|
+
const base = xdgCacheHome ?? path3.join(os2.homedir(), ".cache");
|
|
108
|
+
return path3.join(base, "opencode-route33");
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
// src/auth/workspace-key-file.ts
|
|
95
|
-
var WORKSPACE_KEY_RELATIVE_PATH =
|
|
96
|
-
var WORKSPACE_GITIGNORE_RELATIVE_PATH =
|
|
112
|
+
var WORKSPACE_KEY_RELATIVE_PATH = path4.join(".opencode", "route33.key");
|
|
113
|
+
var WORKSPACE_GITIGNORE_RELATIVE_PATH = path4.join(".opencode", ".gitignore");
|
|
97
114
|
var GITIGNORE_ENTRIES = ["route33.key", "tui.json"];
|
|
98
115
|
function usable2(value) {
|
|
99
116
|
if (typeof value !== "string") return void 0;
|
|
@@ -107,7 +124,7 @@ function readWorkspaceKey(worktree) {
|
|
|
107
124
|
if (worktree === void 0) return void 0;
|
|
108
125
|
try {
|
|
109
126
|
const raw = fs2.readFileSync(
|
|
110
|
-
|
|
127
|
+
path4.join(worktree, WORKSPACE_KEY_RELATIVE_PATH),
|
|
111
128
|
"utf8"
|
|
112
129
|
);
|
|
113
130
|
const parsed = JSON.parse(raw);
|
|
@@ -119,10 +136,10 @@ function readWorkspaceKey(worktree) {
|
|
|
119
136
|
}
|
|
120
137
|
function ensureWorkspaceKeyGitignore(worktree) {
|
|
121
138
|
if (worktree === void 0 || worktree.trim() === "") return;
|
|
122
|
-
if (
|
|
123
|
-
const gitignorePath =
|
|
139
|
+
if (path4.resolve(worktree) === "/") return;
|
|
140
|
+
const gitignorePath = path4.join(worktree, WORKSPACE_GITIGNORE_RELATIVE_PATH);
|
|
124
141
|
try {
|
|
125
|
-
fs2.mkdirSync(
|
|
142
|
+
fs2.mkdirSync(path4.dirname(gitignorePath), { recursive: true });
|
|
126
143
|
let content = "";
|
|
127
144
|
try {
|
|
128
145
|
content = fs2.readFileSync(gitignorePath, "utf8");
|
|
@@ -157,8 +174,8 @@ function urlFromConfig(cfg) {
|
|
|
157
174
|
return literal;
|
|
158
175
|
return void 0;
|
|
159
176
|
}
|
|
160
|
-
function resolveBaseUrl(cfg, env = process.env) {
|
|
161
|
-
return usable3(env[ENV_BASE_URL]) ?? urlFromConfig(cfg) ?? readAuthEntry(env).baseURL ?? DEFAULT_BASE_URL;
|
|
177
|
+
function resolveBaseUrl(cfg, env = process.env, worktree) {
|
|
178
|
+
return usable3(env[ENV_BASE_URL]) ?? urlFromConfig(cfg) ?? (worktree !== void 0 && isInsideGitWorktree(worktree) ? void 0 : readAuthEntry(env).baseURL) ?? DEFAULT_BASE_URL;
|
|
162
179
|
}
|
|
163
180
|
|
|
164
181
|
// src/auth/api-key-method.ts
|
|
@@ -208,7 +225,7 @@ function keyFromConfig(cfg) {
|
|
|
208
225
|
return void 0;
|
|
209
226
|
}
|
|
210
227
|
function resolveKey(cfg, env = process.env, worktree) {
|
|
211
|
-
return usable4(env[ENV_API_KEY]) ?? keyFromConfig(cfg) ?? readWorkspaceKey(worktree) ?? readAuthEntry(env).key;
|
|
228
|
+
return usable4(env[ENV_API_KEY]) ?? keyFromConfig(cfg) ?? readWorkspaceKey(worktree) ?? (worktree !== void 0 && isInsideGitWorktree(worktree) ? void 0 : readAuthEntry(env).key);
|
|
212
229
|
}
|
|
213
230
|
|
|
214
231
|
// src/auth/route33-auth.ts
|
|
@@ -229,20 +246,20 @@ function buildRoute33Auth(env = process.env, worktree) {
|
|
|
229
246
|
}
|
|
230
247
|
|
|
231
248
|
// src/bootstrap/ensure-tui-registration.ts
|
|
232
|
-
import * as
|
|
249
|
+
import * as path8 from "path";
|
|
233
250
|
|
|
234
251
|
// src/bootstrap/global-context.ts
|
|
235
252
|
import * as os3 from "os";
|
|
236
|
-
import * as
|
|
253
|
+
import * as path5 from "path";
|
|
237
254
|
import { fileURLToPath } from "url";
|
|
238
255
|
function isGlobalContext(worktree, moduleUrl) {
|
|
239
256
|
try {
|
|
240
257
|
if (moduleUrl === void 0) return false;
|
|
241
258
|
if (worktree === void 0) return true;
|
|
242
|
-
const root =
|
|
259
|
+
const root = path5.resolve(worktree);
|
|
243
260
|
if (root === "/") return true;
|
|
244
261
|
const modulePath = fileURLToPath(moduleUrl);
|
|
245
|
-
return !modulePath.startsWith(root +
|
|
262
|
+
return !modulePath.startsWith(root + path5.sep);
|
|
246
263
|
} catch {
|
|
247
264
|
return false;
|
|
248
265
|
}
|
|
@@ -252,13 +269,13 @@ function usable5(value) {
|
|
|
252
269
|
return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
|
|
253
270
|
}
|
|
254
271
|
function globalTuiJsonPath(env) {
|
|
255
|
-
const configHome = usable5(env.XDG_CONFIG_HOME) ??
|
|
256
|
-
return
|
|
272
|
+
const configHome = usable5(env.XDG_CONFIG_HOME) ?? path5.join(os3.homedir(), ".config");
|
|
273
|
+
return path5.join(configHome, "opencode", "tui.json");
|
|
257
274
|
}
|
|
258
275
|
|
|
259
276
|
// src/bootstrap/tui-json-upsert.ts
|
|
260
277
|
import * as fs4 from "fs";
|
|
261
|
-
import * as
|
|
278
|
+
import * as path7 from "path";
|
|
262
279
|
import {
|
|
263
280
|
applyEdits,
|
|
264
281
|
modify,
|
|
@@ -268,15 +285,17 @@ import {
|
|
|
268
285
|
// src/bootstrap/tui-spec-resolution.ts
|
|
269
286
|
import * as fs3 from "fs";
|
|
270
287
|
import * as os4 from "os";
|
|
271
|
-
import * as
|
|
288
|
+
import * as path6 from "path";
|
|
272
289
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
273
|
-
var NPM_TUI_SPEC = "@route_33/opencode
|
|
290
|
+
var NPM_TUI_SPEC = "@route_33/opencode";
|
|
291
|
+
var DEAD_SUBPATH_TUI_SPEC = "@route_33/opencode/tui";
|
|
274
292
|
var OLD_NPM_TUI_SPEC = "opencode-route33/tui";
|
|
275
293
|
var TUI_BUNDLE_NAME = "route33-tui.js";
|
|
276
294
|
var TUI_SCHEMA = "https://opencode.ai/tui.json";
|
|
277
295
|
var SERVER_BUNDLE_NAME = "route33.js";
|
|
278
296
|
var DIST_TUI_ENTRY_SUFFIX = "/opencode-route33/dist/tui/index.js";
|
|
279
297
|
var SCOPED_DIST_TUI_ENTRY_SUFFIX = "/@route_33/opencode/dist/tui/index.js";
|
|
298
|
+
var NPM_PACKAGE_DIR = path6.join("node_modules", "@route_33", "opencode");
|
|
280
299
|
function fileExists(candidate) {
|
|
281
300
|
try {
|
|
282
301
|
return fs3.statSync(candidate).isFile();
|
|
@@ -284,17 +303,30 @@ function fileExists(candidate) {
|
|
|
284
303
|
return false;
|
|
285
304
|
}
|
|
286
305
|
}
|
|
306
|
+
function npmSpecFromModulePath(selfPath) {
|
|
307
|
+
const segments = selfPath.split(path6.sep);
|
|
308
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
309
|
+
const pkgDir = segments[i + 1];
|
|
310
|
+
if (segments[i] === "@route_33" && pkgDir !== void 0 && pkgDir.startsWith("opencode@")) {
|
|
311
|
+
const pin = pkgDir.slice("opencode@".length);
|
|
312
|
+
if (pin !== "") return `${NPM_TUI_SPEC}@${pin}`;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return selfPath.includes(`${NPM_PACKAGE_DIR}${path6.sep}`) ? NPM_TUI_SPEC : void 0;
|
|
316
|
+
}
|
|
287
317
|
function specFromModuleUrl(moduleUrl) {
|
|
288
318
|
try {
|
|
289
319
|
if (moduleUrl === void 0) return void 0;
|
|
290
320
|
const selfPath = fileURLToPath2(moduleUrl);
|
|
291
|
-
const dir =
|
|
292
|
-
if (
|
|
293
|
-
const sibling =
|
|
321
|
+
const dir = path6.dirname(selfPath);
|
|
322
|
+
if (path6.basename(selfPath) === SERVER_BUNDLE_NAME) {
|
|
323
|
+
const sibling = path6.join(dir, TUI_BUNDLE_NAME);
|
|
294
324
|
return fileExists(sibling) ? sibling : void 0;
|
|
295
325
|
}
|
|
296
|
-
if (
|
|
297
|
-
const
|
|
326
|
+
if (path6.basename(selfPath) === "index.js" && path6.basename(dir) === "dist") {
|
|
327
|
+
const npmSpec = npmSpecFromModulePath(selfPath);
|
|
328
|
+
if (npmSpec !== void 0) return npmSpec;
|
|
329
|
+
const tuiEntry = path6.join(dir, "tui", "index.js");
|
|
298
330
|
return fileExists(tuiEntry) ? tuiEntry : void 0;
|
|
299
331
|
}
|
|
300
332
|
return void 0;
|
|
@@ -305,17 +337,17 @@ function specFromModuleUrl(moduleUrl) {
|
|
|
305
337
|
function resolveTuiSpec(worktree, env, moduleUrl) {
|
|
306
338
|
const fromModule = specFromModuleUrl(moduleUrl);
|
|
307
339
|
if (fromModule !== void 0) return fromModule;
|
|
308
|
-
if (worktree !== void 0 && worktree.trim() !== "" &&
|
|
309
|
-
const local =
|
|
340
|
+
if (worktree !== void 0 && worktree.trim() !== "" && path6.resolve(worktree) !== "/") {
|
|
341
|
+
const local = path6.join(worktree, ".opencode", "plugins", TUI_BUNDLE_NAME);
|
|
310
342
|
if (fileExists(local)) return local;
|
|
311
343
|
}
|
|
312
|
-
const configHome = env.XDG_CONFIG_HOME?.trim() ||
|
|
313
|
-
const global =
|
|
344
|
+
const configHome = env.XDG_CONFIG_HOME?.trim() || path6.join(os4.homedir(), ".config");
|
|
345
|
+
const global = path6.join(configHome, "opencode", "plugins", TUI_BUNDLE_NAME);
|
|
314
346
|
if (fileExists(global)) return global;
|
|
315
347
|
return NPM_TUI_SPEC;
|
|
316
348
|
}
|
|
317
349
|
function isOurEntry(entry) {
|
|
318
|
-
return typeof entry === "string" && (entry === NPM_TUI_SPEC || entry === OLD_NPM_TUI_SPEC || entry.endsWith(`/${TUI_BUNDLE_NAME}`) || entry.endsWith(DIST_TUI_ENTRY_SUFFIX) || entry.endsWith(SCOPED_DIST_TUI_ENTRY_SUFFIX));
|
|
350
|
+
return typeof entry === "string" && (entry === NPM_TUI_SPEC || entry.startsWith(`${NPM_TUI_SPEC}@`) || entry === DEAD_SUBPATH_TUI_SPEC || entry === OLD_NPM_TUI_SPEC || entry.endsWith(`/${TUI_BUNDLE_NAME}`) || entry.endsWith(DIST_TUI_ENTRY_SUFFIX) || entry.endsWith(SCOPED_DIST_TUI_ENTRY_SUFFIX));
|
|
319
351
|
}
|
|
320
352
|
|
|
321
353
|
// src/bootstrap/tui-json-upsert.ts
|
|
@@ -332,7 +364,7 @@ function fileExists2(candidate) {
|
|
|
332
364
|
function upsertTuiSpec(file, spec) {
|
|
333
365
|
try {
|
|
334
366
|
if (!fileExists2(file)) {
|
|
335
|
-
fs4.mkdirSync(
|
|
367
|
+
fs4.mkdirSync(path7.dirname(file), { recursive: true });
|
|
336
368
|
fs4.writeFileSync(
|
|
337
369
|
file,
|
|
338
370
|
JSON.stringify({ $schema: TUI_SCHEMA, plugin: [spec] }, null, 2) + "\n",
|
|
@@ -407,10 +439,10 @@ function ensureTuiRegistration(deps) {
|
|
|
407
439
|
try {
|
|
408
440
|
const { worktree, env } = deps;
|
|
409
441
|
if (env.ROUTE33_TUI_PROMPT === "0") return;
|
|
410
|
-
const usableWorktree = worktree !== void 0 && worktree.trim() !== "" &&
|
|
442
|
+
const usableWorktree = worktree !== void 0 && worktree.trim() !== "" && path8.resolve(worktree) !== "/" ? worktree : void 0;
|
|
411
443
|
const spec = resolveTuiSpec(usableWorktree, env, deps.moduleUrl);
|
|
412
444
|
if (usableWorktree !== void 0) {
|
|
413
|
-
upsertTuiSpec(
|
|
445
|
+
upsertTuiSpec(path8.join(usableWorktree, ".opencode", "tui.json"), spec);
|
|
414
446
|
}
|
|
415
447
|
if (isGlobalContext(worktree, deps.moduleUrl)) {
|
|
416
448
|
upsertTuiSpec(globalTuiJsonPath(env), spec);
|
|
@@ -566,9 +598,9 @@ function hashKey(key) {
|
|
|
566
598
|
import * as fs5 from "fs";
|
|
567
599
|
|
|
568
600
|
// src/catalog/catalog-cache/cache-file-path.ts
|
|
569
|
-
import * as
|
|
601
|
+
import * as path9 from "path";
|
|
570
602
|
function cacheFilePath(keyHash, env) {
|
|
571
|
-
return
|
|
603
|
+
return path9.join(resolveCacheDir(env), `catalog-${keyHash}.json`);
|
|
572
604
|
}
|
|
573
605
|
|
|
574
606
|
// src/catalog/catalog-cache/read-disk.ts
|
|
@@ -1172,7 +1204,7 @@ function enrichModel(slug2, sources) {
|
|
|
1172
1204
|
|
|
1173
1205
|
// src/enrich/models-dev/load-models-dev.ts
|
|
1174
1206
|
import * as fs7 from "fs";
|
|
1175
|
-
import * as
|
|
1207
|
+
import * as path10 from "path";
|
|
1176
1208
|
|
|
1177
1209
|
// src/enrich/models-dev/is-record.ts
|
|
1178
1210
|
function isRecord7(value) {
|
|
@@ -1273,10 +1305,10 @@ function swapLast(value, from, to) {
|
|
|
1273
1305
|
return index === -1 ? value : `${value.slice(0, index)}${to}${value.slice(index + 1)}`;
|
|
1274
1306
|
}
|
|
1275
1307
|
function probeCandidates(slug2) {
|
|
1276
|
-
const
|
|
1277
|
-
if (
|
|
1278
|
-
const vendor = slug2.slice(0,
|
|
1279
|
-
const model = slug2.slice(
|
|
1308
|
+
const sep3 = slug2.indexOf("/");
|
|
1309
|
+
if (sep3 <= 0 || sep3 >= slug2.length - 1) return [];
|
|
1310
|
+
const vendor = slug2.slice(0, sep3);
|
|
1311
|
+
const model = slug2.slice(sep3 + 1);
|
|
1280
1312
|
const vendors = [vendor];
|
|
1281
1313
|
const alias = VENDOR_ALIASES[vendor];
|
|
1282
1314
|
if (alias !== void 0 && alias !== vendor) vendors.push(alias);
|
|
@@ -1352,7 +1384,7 @@ function readCache(cachePath) {
|
|
|
1352
1384
|
}
|
|
1353
1385
|
function writeCache(cachePath, envelope) {
|
|
1354
1386
|
try {
|
|
1355
|
-
fs7.mkdirSync(
|
|
1387
|
+
fs7.mkdirSync(path10.dirname(cachePath), { recursive: true });
|
|
1356
1388
|
fs7.writeFileSync(cachePath, JSON.stringify(envelope), "utf8");
|
|
1357
1389
|
} catch (error) {
|
|
1358
1390
|
logger.warn("failed to write models.dev cache:", error);
|
|
@@ -1366,7 +1398,7 @@ async function loadModelsDev(options = {}) {
|
|
|
1366
1398
|
const cacheDir = options.cacheDir ?? resolveCacheDir();
|
|
1367
1399
|
const ttlMs = options.ttlMs ?? MODELS_DEV_TTL_MS;
|
|
1368
1400
|
const now = options.now ?? Date.now;
|
|
1369
|
-
const cachePath =
|
|
1401
|
+
const cachePath = path10.join(cacheDir, CACHE_FILE);
|
|
1370
1402
|
const cached = readCache(cachePath);
|
|
1371
1403
|
if (cached && now() - cached.fetchedAt < ttlMs)
|
|
1372
1404
|
return makeSource("cache", cached.data);
|
|
@@ -1516,10 +1548,10 @@ function mergeConfig(cfg, blocks) {
|
|
|
1516
1548
|
|
|
1517
1549
|
// src/config/collected-ref.ts
|
|
1518
1550
|
function parseRef(ref, source) {
|
|
1519
|
-
const
|
|
1520
|
-
if (
|
|
1521
|
-
const providerId = ref.slice(0,
|
|
1522
|
-
const suffix = ref.slice(
|
|
1551
|
+
const sep3 = ref.indexOf("/");
|
|
1552
|
+
if (sep3 <= 0 || sep3 >= ref.length - 1) return void 0;
|
|
1553
|
+
const providerId = ref.slice(0, sep3);
|
|
1554
|
+
const suffix = ref.slice(sep3 + 1);
|
|
1523
1555
|
if (providerId === "route_33")
|
|
1524
1556
|
return { providerId, modelKey: suffix, ref, source };
|
|
1525
1557
|
if (providerId !== "route_33_anthropic") return void 0;
|
|
@@ -1551,7 +1583,7 @@ function collectCfgRefs(cfg) {
|
|
|
1551
1583
|
// src/config/collect-flavour-refs.ts
|
|
1552
1584
|
import * as fs8 from "fs";
|
|
1553
1585
|
import * as os5 from "os";
|
|
1554
|
-
import * as
|
|
1586
|
+
import * as path11 from "path";
|
|
1555
1587
|
import { parse as parseJsonc2 } from "jsonc-parser";
|
|
1556
1588
|
function isRecord8(value) {
|
|
1557
1589
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1559,10 +1591,10 @@ function isRecord8(value) {
|
|
|
1559
1591
|
function findFlavourPath(env, cwd) {
|
|
1560
1592
|
const candidates = [];
|
|
1561
1593
|
const configDir = env.OPENCODE_CONFIG_DIR?.trim();
|
|
1562
|
-
if (configDir) candidates.push(
|
|
1563
|
-
candidates.push(
|
|
1564
|
-
const configHome = env.XDG_CONFIG_HOME?.trim() ||
|
|
1565
|
-
candidates.push(
|
|
1594
|
+
if (configDir) candidates.push(path11.join(configDir, "oh-my-openagent.jsonc"));
|
|
1595
|
+
candidates.push(path11.join(cwd, ".opencode", "oh-my-openagent.jsonc"));
|
|
1596
|
+
const configHome = env.XDG_CONFIG_HOME?.trim() || path11.join(os5.homedir(), ".config");
|
|
1597
|
+
candidates.push(path11.join(configHome, "opencode", "oh-my-openagent.jsonc"));
|
|
1566
1598
|
for (const candidate of candidates) {
|
|
1567
1599
|
try {
|
|
1568
1600
|
if (fs8.existsSync(candidate)) return candidate;
|
|
@@ -1725,7 +1757,7 @@ function createConfigHook(options = {}) {
|
|
|
1725
1757
|
let key;
|
|
1726
1758
|
try {
|
|
1727
1759
|
key = resolveKey(cfg, env, cwd);
|
|
1728
|
-
const baseURL = resolveBaseUrl(cfg, env);
|
|
1760
|
+
const baseURL = resolveBaseUrl(cfg, env, cwd);
|
|
1729
1761
|
const catalog = await getCatalog({
|
|
1730
1762
|
key,
|
|
1731
1763
|
baseURL,
|
package/dist/tui/index.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
// src/shared/env-api-key.ts
|
|
2
2
|
var ENV_API_KEY = "ROUTE33_API_KEY";
|
|
3
3
|
|
|
4
|
+
// src/shared/git-workspace.ts
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
function isInsideGitWorktree(startDir) {
|
|
8
|
+
try {
|
|
9
|
+
let dir = path.resolve(startDir);
|
|
10
|
+
for (; ; ) {
|
|
11
|
+
if (existsSync(path.join(dir, ".git"))) return true;
|
|
12
|
+
const parent = path.dirname(dir);
|
|
13
|
+
if (parent === dir) return false;
|
|
14
|
+
dir = parent;
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
4
21
|
// src/shared/logger.ts
|
|
5
22
|
var logger = {
|
|
6
23
|
info: (...args) => {
|
|
@@ -16,12 +33,12 @@ var logger = {
|
|
|
16
33
|
|
|
17
34
|
// src/shared/resolve-cache-dir.ts
|
|
18
35
|
import * as os from "os";
|
|
19
|
-
import * as
|
|
36
|
+
import * as path2 from "path";
|
|
20
37
|
|
|
21
38
|
// src/auth/auth-json.ts
|
|
22
39
|
import * as fs from "fs";
|
|
23
40
|
import * as os2 from "os";
|
|
24
|
-
import * as
|
|
41
|
+
import * as path3 from "path";
|
|
25
42
|
var PROVIDER_ID = "route_33";
|
|
26
43
|
function usable(value) {
|
|
27
44
|
if (typeof value !== "string") return void 0;
|
|
@@ -33,8 +50,8 @@ function isRecord(value) {
|
|
|
33
50
|
}
|
|
34
51
|
function readAuthEntry(env = process.env) {
|
|
35
52
|
try {
|
|
36
|
-
const dataHome = usable(env.XDG_DATA_HOME) ??
|
|
37
|
-
const authPath =
|
|
53
|
+
const dataHome = usable(env.XDG_DATA_HOME) ?? path3.join(os2.homedir(), ".local", "share");
|
|
54
|
+
const authPath = path3.join(dataHome, "opencode", "auth.json");
|
|
38
55
|
const parsed = JSON.parse(fs.readFileSync(authPath, "utf8"));
|
|
39
56
|
if (!isRecord(parsed)) return {};
|
|
40
57
|
const entry = parsed[PROVIDER_ID];
|
|
@@ -52,9 +69,9 @@ function readAuthEntry(env = process.env) {
|
|
|
52
69
|
|
|
53
70
|
// src/auth/workspace-key-file.ts
|
|
54
71
|
import * as fs2 from "fs";
|
|
55
|
-
import * as
|
|
56
|
-
var WORKSPACE_KEY_RELATIVE_PATH =
|
|
57
|
-
var WORKSPACE_GITIGNORE_RELATIVE_PATH =
|
|
72
|
+
import * as path4 from "path";
|
|
73
|
+
var WORKSPACE_KEY_RELATIVE_PATH = path4.join(".opencode", "route33.key");
|
|
74
|
+
var WORKSPACE_GITIGNORE_RELATIVE_PATH = path4.join(".opencode", ".gitignore");
|
|
58
75
|
var GITIGNORE_ENTRIES = ["route33.key", "tui.json"];
|
|
59
76
|
function usable2(value) {
|
|
60
77
|
if (typeof value !== "string") return void 0;
|
|
@@ -68,7 +85,7 @@ function readWorkspaceKey(worktree) {
|
|
|
68
85
|
if (worktree === void 0) return void 0;
|
|
69
86
|
try {
|
|
70
87
|
const raw = fs2.readFileSync(
|
|
71
|
-
|
|
88
|
+
path4.join(worktree, WORKSPACE_KEY_RELATIVE_PATH),
|
|
72
89
|
"utf8"
|
|
73
90
|
);
|
|
74
91
|
const parsed = JSON.parse(raw);
|
|
@@ -80,10 +97,10 @@ function readWorkspaceKey(worktree) {
|
|
|
80
97
|
}
|
|
81
98
|
function ensureWorkspaceKeyGitignore(worktree) {
|
|
82
99
|
if (worktree === void 0 || worktree.trim() === "") return;
|
|
83
|
-
if (
|
|
84
|
-
const gitignorePath =
|
|
100
|
+
if (path4.resolve(worktree) === "/") return;
|
|
101
|
+
const gitignorePath = path4.join(worktree, WORKSPACE_GITIGNORE_RELATIVE_PATH);
|
|
85
102
|
try {
|
|
86
|
-
fs2.mkdirSync(
|
|
103
|
+
fs2.mkdirSync(path4.dirname(gitignorePath), { recursive: true });
|
|
87
104
|
let content = "";
|
|
88
105
|
try {
|
|
89
106
|
content = fs2.readFileSync(gitignorePath, "utf8");
|
|
@@ -107,8 +124,8 @@ function ensureWorkspaceKeyGitignore(worktree) {
|
|
|
107
124
|
}
|
|
108
125
|
function writeWorkspaceKey(worktree, key) {
|
|
109
126
|
ensureWorkspaceKeyGitignore(worktree);
|
|
110
|
-
const filePath =
|
|
111
|
-
fs2.mkdirSync(
|
|
127
|
+
const filePath = path4.join(worktree, WORKSPACE_KEY_RELATIVE_PATH);
|
|
128
|
+
fs2.mkdirSync(path4.dirname(filePath), { recursive: true });
|
|
112
129
|
fs2.writeFileSync(
|
|
113
130
|
filePath,
|
|
114
131
|
`${JSON.stringify({ type: "api", key }, null, 2)}
|
|
@@ -130,7 +147,7 @@ function keyFromConfig(cfg) {
|
|
|
130
147
|
return void 0;
|
|
131
148
|
}
|
|
132
149
|
function resolveKey(cfg, env = process.env, worktree) {
|
|
133
|
-
return usable3(env[ENV_API_KEY]) ?? keyFromConfig(cfg) ?? readWorkspaceKey(worktree) ?? readAuthEntry(env).key;
|
|
150
|
+
return usable3(env[ENV_API_KEY]) ?? keyFromConfig(cfg) ?? readWorkspaceKey(worktree) ?? (worktree !== void 0 && isInsideGitWorktree(worktree) ? void 0 : readAuthEntry(env).key);
|
|
134
151
|
}
|
|
135
152
|
|
|
136
153
|
// src/tui/key-prompt-ui.ts
|
|
@@ -274,23 +291,6 @@ function createDismissalStore(kv, key = PROJECT_KEY_PROMPT_DISMISSED_AT_KEY) {
|
|
|
274
291
|
};
|
|
275
292
|
}
|
|
276
293
|
|
|
277
|
-
// src/tui/git-workspace.ts
|
|
278
|
-
import { existsSync } from "fs";
|
|
279
|
-
import * as path4 from "path";
|
|
280
|
-
function isInsideGitWorktree(startDir) {
|
|
281
|
-
try {
|
|
282
|
-
let dir = path4.resolve(startDir);
|
|
283
|
-
for (; ; ) {
|
|
284
|
-
if (existsSync(path4.join(dir, ".git"))) return true;
|
|
285
|
-
const parent = path4.dirname(dir);
|
|
286
|
-
if (parent === dir) return false;
|
|
287
|
-
dir = parent;
|
|
288
|
-
}
|
|
289
|
-
} catch {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
294
|
// src/tui/key-prompt-copy.ts
|
|
295
295
|
var PROJECT_COPY = {
|
|
296
296
|
selectTitle: KEY_SELECT_TITLE,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@route_33/opencode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"description": "opencode provider plugin for the route33.ai AI gateway — key-scoped model discovery, cost/limit enrichment, auth, and the key-setup wizard.",
|